Oooooooh, New Shiny! A major new vesion of Django was released on December 2nd 2017, and you can check out the full release documentation for Django 2.0 here. Just in time to start playing with over the holidays. As with any new release, it’s about new features and modernization; however, when upgrading to any new version there can be changes or deprecations that might introduce new errors into your codebase. This version is the first that will use a new versioning cadence and isn’t backward compatible. With that in mind, we’re going to highlight a few key changes to hopefully avoid error creep.
One of the most notable changes in the new version of Django is the lack of support for Python 2.7, as it exclusively supports Python 3.4, 3.5, 3.6. This relegates support of Python 2.7 to the older Django 1.11 version. Although Python 3 was released over seven years ago, 2.7 still remains heavily used. Keep this compatibility in mind when you are looking at Django 2.0.
When querying a slice of data, you may have gotten unexpected results if you also applied
.last() to the query. This is due to the ordering operation occurring before the slice is taken, which is not obvious from the readability of the code. In Django 2.0 this operation will be blocked and produce the following error:
TypeError: Cannot reverse a query once a slice has been taken.
Previously in Django 1.11 you may have experienced this confusing behavior:
people = Person.objects.order_by('name') # people = (Person<'Alex'>, Person<'Bob'>, Person<'Clint'>, Person<'Dave'>) people_slice = people[:2] # people_slice = (Person<'Alex'>, Person<'Bob'>) reversed_slice = people_slice.reverse() #Expecting (Person<'Bob'>, Person<'Alex'>)? # reversed_slice = (Person<'Dave'>, Person<'Clint'>)
Now, in Django 2.0:
reversed_slice = Person.objects.order_by('name')[:2].reverse() TypeError: Cannot reverse a query once a slice has been taken.
Django has many built in form fields, each with a various number of optional parameters. Previous versions of Django allowed for positional value entry for the optional parameters. This has changed to explicit value declaration in the 2.0 version, which will help to reduce run time errors from positional parameters in an incorrect order. It also makes the declaration of the optional parameters more readable. Your future self will thank you.
Previous optional parameters implied that maximum length of form entry for email is 30 and minimum length is 1:
forms.EmailField(30, 1) #Valid optional fields
It makes it more difficult to create a field with impossible validation requirements:
forms.EmailField(1, 30) # !Impossible to have a valid input
Django 2.0 makes the declaration of the optional parameters explicit thus preventing a run time error:
In the same vein as the change to optional form fields mentioned above, Django 2.0 also has now prohibited positional parameters for indices. You will need to explicitly define the fields and index names going forward.
Previously it was easy to mix up parameters when creating an Index:
Index('name_index', ['first_name', 'last_name']) ValueError: Index.fields must be a list.
Correct positional index in Django 1.11 and earlier:
Index(['first_name', 'last_name'], 'name_index') # Valid index
Django 2.0 makes this construction more explicit:
Index(fields=['first_name', 'last_name'], name='name_index')
Updating your codebase to use Django 2.0 will hopefully be smoother now that you are aware of some changes to slice ordering and explicit declarations required in forms and indices.
As you upgrade to this version, we are there to help you catch and prioritize any errors. Our Django library is fully compatible with this latest version.