Upgrading Django

For the second time in a few years I've found myself doing a number of Django upgrades. It's a good thing: I'm happy the framework I chose to base most of my work on when I went solo has stayed relevant. But this time I wanted to document some of the pain points to make things easier on anyone else going through the same.

First off, this round of updates has been a lot easier than the first: back then I was the point of contact for WebFaction clients who had a Django app but no longer had a developer and those orphaned projects trended ancient. I started working with Django in 2009 with Django 1.1 and that was modern compared to most of the WebFaction projects. The biggest challenge in that group was a project running on 0.96 and using psycopg . I'd been installing psycopg2 for so long at that point it never occurred to me there was a version before it. And the Internet felt the same way: obtaining a version of Django that old was a challenge (see this thread for how to get versions no longer listed in Pypi). Obtaining a copy of psycopg proved impossible (I cheated and wound up downloading the folder from the client's site-packages directory and using that to replicate the issue they were seeing-- definitely not a recommended approach).

General Guidelines

Use a virtualenv or similar concept. If you're already doing so, great. If you are not, now is definitely the time to start. If you're doing anything more than a minor upgrade/ working on a project with no 3rd party libraries, you are going to run into some "dependency hell" where you've updated to Django 1.NEW and updated all your code to be compatible and then find out some libraries you use aren't compatible. The best case scenario is where you just need to update the libraries to their latest versions too, but you may have to play around with the versions to make it all work. Otherwise you need to figure out how to replace the library or fork it.

or similar concept. If you're already doing so, great. If you are not, now is definitely the time to start. If you're doing anything more than a minor upgrade/ working on a project with no 3rd party libraries, you are going to run into some "dependency hell" where you've updated to Django 1.NEW and updated all your code to be compatible and then find out some libraries you use aren't compatible. The best case scenario is where you just need to update the libraries to their latest versions too, but you may have to play around with the versions to make it all work. Otherwise you need to figure out how to replace the library or fork it. Implicit in my virtualenv suggestion is that you also use pip to install packages and pip freeze to create a requirements file with the exact versions of the libraries your project uses.

suggestion is that you also use to install packages and to create a requirements file with the exact versions of the libraries your project uses. If you are updating from a truly old version of Django, try not to get too hung up on updating to the latest and greatest. You might have to shoot for something a little bit older because the incompatibilities are just too great or there isn't enough time right now to make it all work. In updating my old site from 1.2 to 1.10 I actually stopped at 1.6 for a while instead. This is another place virtualenv is your friend: at one point I had three local environments for my site, tkc (live), tkc16 and tkc110 . Once I finished the upgrade process, I deleted the first two and renamed tkc110 to tkc and it was like nothing ever happened. Be aware of the long-term release versions and the deprecation schedule when targeting a new version.

is your friend: at one point I had three local environments for my site, (live), and . Once I finished the upgrade process, I deleted the first two and renamed to and it was like nothing ever happened. Be aware of the long-term release versions and the deprecation schedule when targeting a new version. If you are jumping from a really old version, do some reading on the release notes to see what new features are available to you. I'm focusing on problems you may run into and backwards-incompatible changes, but one of the major reasons to upgrade are all the improvements you get. Be aware of things like select_related , prefetch_related and only for making queries faster.

, and for making queries faster. Change from render_to_response to render . It will make things easier and the former is soon to be removed.

to . It will make things easier and the former is soon to be removed. If you get stuck because the changes to project layout or syntax have changed so much, try creating a new virtualenv and project with 1.10 (or similar) and then dragging your apps into the project. You will still need to update a bunch of stuff but it may make things a lot easier and help with your future-proofing.

Version-Specific Notes

Major changes to middleware

If you are using MySQL (don't start now), Django recommends you turn on strict mode. See project note about why and this answer for how

django.conf.urls.patterns is gone and all view references in urls.py need to be imported views, not string names.

The admin got a facelift!

Password validation options

django.contrib.sites is no longer included by default, which can cause a RuntimeError: Model class django.contrib.sites.models.Site doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS . Just add it back to INSTALLED_APPS .

is no longer included by default, which can cause a . Just add it back to . django.utils.log.NullHandler was removed, replace the references with logging.NullHandler

Major settings change: the new TEMPLATES setting replaces all TEMPLATE_* settings. This is a bit of PITA as you have to move a bunch of things into their new home in that setting.

setting replaces all settings. This is a bit of PITA as you have to move a bunch of things into their new home in that setting. select_related actually checks that the fields exist on the model you are querying. Previously this just silently ignored the error and you were left thinking you'd improved performance when you weren't doing anything.

actually checks that the fields exist on the model you are querying. Previously this just silently ignored the error and you were left thinking you'd improved performance when you weren't doing anything. django.contrib.formtools is replaced by an external app

is replaced by an external app The syntax of urls.py files changed: you now have to have url(regex, view) instead of just (regex, view) , otherwise you will get AttributeError 'tuple' object has no attribute 'regex' . Make note of the changes in 1.10 to urls.py files if you're going to be updating all of them anyway.

files changed: you now have to have instead of just , otherwise you will get . Make note of the changes in 1.10 to files if you're going to be updating all of them anyway. request.REQUEST was removed, but you weren't using that anyway, were you?

was removed, but you weren't using that anyway, were you? Drops support for Postgres < 9.0 (and then 9.0 and 9.1 are dropped in .9 and .10) and MySQL < 5.5

Not much new, simplified setup, swapped a couple of defaults in settings. At least that's how I remember it and its why I chose this as a halfway step in my own update.

Actually there's one change that will bite you if you have any custom managers: get_query_set is now get_queryset .

is now . django.contrib.localflavor is gone, replaced by a 3rd-party app. Update your requirments file and your references.

is gone, replaced by a 3rd-party app. Update your requirments file and your references. django.contrib.markup is gone. You will need a replacement.

is gone. You will need a replacement. There no longer is a .raw_post_data attribute on Request objects. Use .body instead.

attribute on Request objects. Use instead. There was a change to session handling. If, after upgrading, you get an error from the SessionMiddleware telling you a value isn't JSON-serializable, you need to swap back to the old way of handling sessions by adding this to your settings.py : SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'

Lots of good new stuff introduced in this version, the biggest being timezone support.

The concept of ADMIN_MEDIA is replaced by static files app from 1.3

is replaced by static files app from 1.3 django.conf.urls.defaults is replaced by django.conf.urls . Update your urls.py files accordingly.

is replaced by . Update your files accordingly. The default project structure changed along with the contents of manage.py . You may run into some errors like "The system cannot find the file X" until you restructure (or update how you reference urls, etc in the settings).

. You may run into some errors like "The system cannot find the file X" until you restructure (or update how you reference urls, etc in the settings). Error: "No modules named six" - this is an annoying one I ran into with a couple 3rd party libraries. I was testing which versions I could easily update to by updating to 1.2.0, 1.3.0, 1.4.0, etc. The problem is six was introduced in Django 1.4.2 so don't update to anything less than that if you're going to use 1.4.