Date Tags Django

Django 1.4 came out recently, and I took a few hours to upgrade my first site yesterday. I thought it would be useful for my own reference to write down what I did. I hope it will be useful to others. I'd love to read what you had to do, so if you went through this process and blogged about it, please leave a comment. Please keep in mind these aren't hard and fast steps or a recipe to follow, as my sites are probably nothing like yours and may use different features of Django.

Preparation

The first thing I did was to read very carefully the Django 1.4 release notes. The Django team does a great job of documenting what has changed, so it is well worth your time to read the release notes. It is also a good idea to at least skim the Django Deprecation Timeline. After reading these, you should make a list of the things you want to change, add, or remove.

Tips

After deciding what areas you want or need to change in your code, these tips may be useful to help you implement the changes.

  1. Run with warnings turned on. Use this command to run the development server: $ python -Wall manage.py runserver. Django makes use of Python's warning system to flag features that are deprecated. By running Python with the -Wall switch, you'll see these warnings in the development server output.
  2. Use the debugger to track down warnings. Not sure where a pesky warning is coming from? Just open the Django source code in your editor and put a import pdb; pdb.set_trace() line right above or below the warning. You can then use the debugger's w command to get a stack trace and find out exactly what code is leading to the warning. In my case I kept getting a few warnings with no idea where they were coming from. I used this technique to verify the warnings were coming from third party code and not my own. For more information on using the debugger (and you really should know how to use this invaluable tool), see the Pdb documentation.

My upgrade experience

Here is a list of things that I did during my port. Again, you may not need to do these, and the next site I upgrade may have a different list. All of these changes (except for the first) are described in the Django 1.4 release notes.

  1. Upgrade my Django debug toolbar. As of this writing, the Django debug toolbar I got from PyPI was not compatible with Django 1.4. I simply uninstalled it and grabbed the development version from GitHub with pip install git+https://github.com/django-debug-toolbar/django-debug-toolbar.git.
  2. Remove the ADMIN_MEDIA_PREFIX setting. The admin application in Django 1.4 now relies on the staticfiles application (introduced in Django 1.3) to handle the serving of static assets.
  3. Remove use of the {% admin_media_prefix %} template tag. Related to the above, this tag is now deprecated. I had a custom admin view that used this template tag, and I simply replaced it with {{ STATIC_URL }}/admin.
  4. Remove verify_exists on URLFields. The verify_exists option to the URLField has been removed for performance and security reasons. I had always set this to False; now I just had to remove it altogether.
  5. Add the require_debug_false filter to logging settings. As explained in the release notes, this change prevents admin error emails from being sent while in DEBUG mode.
  6. django.conf.urls.defaults is deprecated. I changed my imports in all urls.py files to use django.conf.urls instead of django.conf.urls.defaults to access include(), patterns(), and url(). The Django team had recently moved these functions and updated the docs and tutorial to stop using the frowned upon from django.conf.urls.defaults import *.
  7. Enable the new clickjacking protection. A nice new feature is some new middleware that adds the X-Frame-Options header to all response headers. This provides clickjacking protection in modern browsers.
  8. Add an admin password reset feature. By adding a few new lines to your urlconf you get a nifty new password reset feature for your admin.
  9. Update to the new manage.py. This was the biggest change with the most impact. The Django team has finally removed a long standing wart with its manage.py utility. Previously, manage.py used to play games with your PYTHONPATH which led to confusion when migrating to production. It could also lead to having your settings imported twice. See the next section in this blog entry for more on what I did here.

Reorganizing for the new manage.py

The change with the largest impact for me was reorganizing my directory structure for the new manage.py command. Before this change, I had organized my directory structure like this:

mysite/
   media/
   static/
   mysite/
      myapp1/
         __init__.py
         models.py
         views.py
         urls.py
      myapp2/
         __init__.py
         models.py
         views.py
         urls.py
      settings/
         __init__.py
         base.py
         local.py
         production.py
         test.py
      apache/
         myproject.wsgi
      logs/
      templates/
      manage.py
      urls.py
   LICENSE
   fabfile.py
   requirements.txt

After replacing the contents of my old manage.py with the new content, I then reorganized my directory structure to this:

mysite/
   media/
   static/
   myapp1/
      __init__.py
      models.py
      views.py
      urls.py
   myapp2/
      __init__.py
      models.py
      views.py
      urls.py
   myproject/
      settings/
         __init__.py
         base.py
         local.py
         production.py
         test.py
      apache/
         myproject.wsgi
      logs/
      templates/
      urls.py
   LICENSE
   fabfile.py
   manage.py
   requirements.txt

It is a subtle change, but I like it. It now makes it clear that my project is just an application itself, consisting of the top-level urls.py, settings, templates and logs. The manage.py file is now at the top level directory also, which seems right.

I had always made my imports as from app.models import MyModel instead of from myproject.app.models, so I didn't have to update any imports.

Since I use the "settings as a package" scheme, I did have to update the imports in my settings files. For example, in my local.py I had to change from settings.base import * to myproject.settings.base import *.

What I didn't do

Django 1.4's largest new feature is probably its support for timezones. I decided for this project not to take advantage of that. It would require a lot of changes, and it isn't really worth it for this small site. I may use it on the next site I convert to Django 1.4, and I will definitely be using it on new projects.

Conclusion

The upgrade process went smoother and quicker than I thought thanks to the excellent release notes and the Django team's use of Python warnings to flag deprecated features.


Comments

comments powered by Disqus