Anyone who knows me will know that Django is my favourite web framework. On the second of September 2014, Django 1.7 was finally released to the public after a much anticipated wait. Some of the new features coming out in 1.7 include App Loading refactoring, custom Queryset methods and a bunch of minor updates to make Django development smoother than it has ever been before.
However, the most exciting feature present in the new version is database schema migration management. This feature update was driven primarily by Andrew Godwin, after a successful Kickstarter campaign to work on the integration. Andrew is the author of the original schema migration package South and the entire community is forever grateful for the contributions he has given to the platform.
When I first used Twilio, I stumbled upon Randall Degges’ helper library for Django, django-twilio. I offered my technical support to Randall after emailing him about the fantastic library he created. After some great Python banter he let me have access to the repository to help continue the work he started.
With the advent of Django 1.7, Django Reusable Apps (the term used to refer to plugins) will need to be updated to support both Django 1.7 migrations and pre-Django 1.7 database migrations.
I recently had to update the django-twilio reusable app to do just this and I decided to document the procedure in order to provide other maintainers with a quick how-to on easily updating their own projects.
This guide only covers database migrations management support for Django 1.7, no other new 1.7 features.What We’ll Cover
This guide assumes you are familiar with Python, virtualenv, PyPI and Django open source project development. Even so, to keep up with The Zen of Python, I’m going to be explicit about the steps required to reliably update your Django reusable app.
In this guide I’ll cover:
- Setting up two separate virtual environments for Django 1.7 and Django 1.6 respectively.
- Updating the migrations files to support Django 1.7 and Django 1.6
- Running the migrations for your Django reusable app in both versions
- Updating the documentation to cover both versions of Django
The quickest, most reliable way to test compatibility with both Django 1.7 and Django 1.6 is to install both versions on separate virtual environments. If you are unfamiliar with virtualenv, it is a tool that allows you to “sandbox” Python development environments so you do not encounter dependency issues from multiple projects with multiple versions.
The new virtual environments will be directories within the root of your project. You will need to cd into the root of your project directory.
I am going to be using the word “django-package” to refer to the Django reusable app we are updating, be sure to substitute it with the name of your own reusable app. I’ve also taken screenshots of the procedure with django-twilio, to give you visual support.
With virtualenv installed we can create new virtual environments with the following commands:
$ virtualenv venv1.7 $ virtualenv venv1.6
This will add a bunch of folders into a new venv1.7/ and venv1.6/ directory which will be filled with Python packages later.
Your django reusable app root directory should now have two extra child directories like so:
django-package/ venv1.6/ venv1.7/ ...
Installing Django 1.7 And Django 1.6
To install Django 1.7 into our venv1.7/ directory we first need to activate the virtual environment using this terminal command:
$ . venv1.7/bin/activate
This will prepend your terminal command line with the name of the virtual environment you’re currently in:
We can then install Django1.7 (and any other requirements your project needs) with the following terminal commands:
$ pip install -r requirements.txt $ pip install django==1.7
You can exit the venv1.7/ virtual environment with the terminal command:
At this point, you will need to activate the venv1.6/ directory using the same commands as above (but substituting “venv1.7” with “venv1.6”) and then install the latest version of Django 1.6 and other requirements with the following terminal command:
$ . /venv1.6/bin/activate $ pip install -r requirements.txt $ pip install django==1.6.7
We’ll also need to install South in this virtual environment too, if it isn’t already installed:
$ pip install South==1.0
Now we have:
- A virtual environment called venv1.7/ with Django 1.7 installed
- A virtual environment called venv1.6/ with Django 1.6.7 and South 1.0 installed
With both versions of Django ready we can now start updating our reusable app to support them!Support All The Djangos!
The nitty gritty of updating a Django reusable app to support both versions of Django migrations boils down to two things:
- Renaming the old migrations directory to south_migrations
- Using Django 1.7 to build new migrations for your project
The first step is dead simple: just rename the old migrations folder in your project (usually in the same directory as models.py) to south_migrations. This directory will now be used by South to run migrations for projects that are not on Django 1.7. You will also want to remove all the old .pyc files in this directory using the following terminal command:
$ rm -rf django_package/south_migrations/*.pyc
The second step is a bit more complex: you will need an existing Django project in order to run the makemigrations command used by Django 1.7 to make the new migrations files.
In the Django-twilio project, we use a Django project called test_project that has all the settings needed by Django to build new migrations. This project is a default project with nothing additional added and is used purely for creating or updating migrations files. I’ve found this is a pretty reliable way of updating migrations, but if you know a better way, please tell me!
From within django-package directory, we need to activate the venv1.7 virtual environment:
$ . ../django1.7/bin/activate
We can then build a new Django1.7 project, called test_project, with the following terminal command:
$ python venv1.7/bin/django-admin.py startproject test_project
In the test project, we need to add our Django reusable app to the list of installed apps, in test_project/test_project/settings.py:
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # Our Django reusable app goes here 'django_package', )
You may need to copy/paste the django_package directory (your reusable app) into the test_project too, this can be done simply:
$ cp -r django_package test_project/django_package
Finally, we can run the makemigrations command:
$ python test_project/manage.py makemigrations django_package
Based on the project structure we’ve laid out, the following will happen:
- Python will execute the makemigrations command through the manage.py file in the test_project project.
- Based on the settings.py in the test_project folder, Django 1.7 will check the django_package reusable app for any changes. Because this is the first time – there will be no migrations, so a new migration file must be created!
- Django 1.7 will generate the new migrations files:
Here we see the django_twilio example that I did earlier
If Django gives the warning “No changes detected in app” try to remove all the old *.pyc files.
Et voilà: Django 1.7 migration support in your reusable app! Wasn’t that easy?Testing Everything Out
We’re not done yet however. A good Django reusable app will be fully tested with the latest version. With the Django1.7 virtualenv still active and your django_package in the project settings.py file, we can try to build the new migrations into the database with the terminal command:
$ python manage.py migrate
The output will be something similar to this:
In this example Django 1.7 has detected my django_twilio library and applied the migrations for the models. Perfect.
You should now be able to deactivate the current virtual environment with the terminal command:
and activate the django1.6 virtual environment with:
$ source venv1.6/bin/activate
We will need to add South to the list of installed apps quickly:
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # Our Django reusable app goes here 'django_package', # South goes here: 'south', )
The Django 1.6 style of handling migrations, using South, should still work with the two terminal command. You’re likely to be asked to add an Admin user to Django, you can type “no” in this case, we won’t need to:
$ python test_project/manage.py syncdb $ python test_project/manage.py migrate django_package
The first command will sync the standard Django models and South. The second command then uses South to migrate your Django reusable app migrations separately. If the old migrations directory has been renamed to south_migrations correctly, you should see a similar successful output like in the image above.
If you have issues, try updating South to South 1.0 and removing old *.pyc files.
Finally, copy the reusable app directory back out of the test_project and over the old root project folder:
$ cp -r test_project/django_package django_package/
You’re now free to commit the changes to git and release a new version.But We’re Still Not Finished
Documentation is a key part of any good software, and Django reusable apps are no exception. With the advent of Django 1.7, it is crucial that you provide documentation on setting up your reusable app with the new Django 1.7 and older versions. Don’t forget to be verbose about which commands are required for which versions. The documentation for Django-twilio provides details on Django 1.6 and lower:
as well as steps for Django 1.7:
For inspiration, I recommend reading the documentation page for django-twilio.Uploading to PyPI
This guide assumes you’re well versed in uploading new versions of your Django reusable app to PyPI, the online repository of Python and Django reusable apps. You will now need to upload your updated Django reusable for other developers to take advantage of the new Django 1.7 updates. If you’re a bit rusty or unsure how to properly package and upload a new version to PyPI, there is a fantastic guide on Twilio by my fellow Pythonista Matt Makai. There is no strict rule on what type of version bump you’ll require, but I suggest a 0.N update as this change is significant. If you’re not sure check out the semantic versioning rules.Final Steps
Today we just worked through what is needed to update your Django reusable app to support the new migrations framework included in Django 1.7. The additional features of Django 1.7 are game changing and are sure to make web application development with Django a smoother and easier experience.