Saying Goodbye to Old Django

We recently wrote about our switch from TravisCI and Coveralls to CircleCI and CodeCov in How We Maintain High Levels of Code Quality.

In addition to adding Django 2.0 compatibility testing, we are dropping support for Django 1.8, 1.9, and 1.10 since their official support has ended. Python 3.3 has reached end of life and is removed from compatibility testing as well. Django 2.0 no longer supports Python 2, so that combination is also removed. This table shows the combinations of Django and Python supported by Pinax:

Django \ Python 2.7 3.4 3.5 3.6
1.11 * * * *
2.0 * * *

About Automated Testing

We run detox locally to see which test configurations fail and why. In addition, we use isort for automated import sorting and flake8-quotes for enforcing our double quote standard.

Django 2.0 Deprecations

These are the most common deprecations we encountered when upgrading to Django 2.0 as well as their resolutions.

1. django.urls

from django.core.urlresolvers import include, url

Becomes:

from django.urls import include, url

2. MIDDLEWARE

In settings.py, we change MIDDLEWARE_CLASSES to MIDDLEWARE per the 1.11 docs.

3. django.shortcuts.render()

Theh django.shortcuts.render_to_response() method is deprecated in favor of django.shortcuts.render().

4. User.is_authenticated and User.is_anonymous

We change references to User.is_authenticated() and User.is_anonymous() to property references (User.is_authenticated and User.is_anonymous).

5. SessionAuthenticationMiddleware

We remove references to SessionAuthenticationMiddleware class.

This middleware is no longer needed since session authentication is unconditionally enabled in Django 1.10+.

6. assignment_tag becomes simple_tag

We change out @register.assignment_tag for @register.simple_tag.

Django 2.0 Updates

These are the most common updates we made when upgrading to Django 2.0:

7. on_delete=models.CASCADE

We add on_delete=models.CASCADE (or some other value) to all ForeignKey and OneToOne model fields. This is required for Django 2.0.

8. compat.py

In reusuable apps that could be used for both 1.11 and 2.0 we create a compat.py module, if needed.

Currently the only import issue we know is mock which did not exist in Python standard library unittest until Python 3.3. See pinax-announcements's compat.py for example imports, then use from .compat import mock.

9. URL namespacing

We need to add app_name = "pinax_announcements" or similar to urls.py.

For example:

from django.urls import url

from . import views

urlpatterns = [
    url(r"^like/(?P<content_type_id>\d+):(?P<object_id>\d+)/$",
        views.LikeToggleView.as_view(),
        name="like_toggle")
]

becomes:

from django.urls import url

from . import views

app_name = "pinax_likes"

urlpatterns = [
    url(r"^like/(?P<content_type_id>\d+):(?P<object_id>\d+)/$",
        views.LikeToggleView.as_view(),
        name="like_toggle")
]

10. Use of path() in Projects

For new applications not requiring Django 1.11 compatibility we use path so we can write url definitions like this:

from django.urls import path

from . import views

app_name = "pinax_likes"

urlpatterns = [
    path("^like/<int:content_type_id>:<int:object_id>/$", views.LikeToggleView.as_view(), name="like_toggle")
]

Conclusion

There might be other issues to consider as you upgrade your site. These are just the ones we've hit upgrading apps and sites so far. For the full list of new features and changes in Django 2.0, see the official release notes.

If you need help, upgrading your site or building something new, don't hesitate to let us know.

Happy upgrading!


Let's Keep in Touch

We'll update you when we post new articles like this one.