Fixing 1_6.W001 when upgrading from Django 1.5 to 1.7

After upgrading a Django project from Django 1.5 to the current beta of Django 1.7, running the tests triggered a warning:

System check identified some issues:

WARNINGS:

?: (1_6.W001) Some project unittests may not execute as expected.
	HINT: Django 1.6 introduced a new default test runner. It looks like this project was generated using Django 1.5 or earlier. You should ensure your tests are all running & behaving as expected. See https://docs.djangoproject.com/en/dev/releases/1.6/#discovery-of-tests-in-any-test-module for more information.

This warning is printed by the System Check Framework, which is new in Django 1.7 and checks your project for common problems. You can run it manually with the “check” management command.

python manage.py check

After verifying that all my tests are run, I was left wondering how I can silence the warning after reading (okay, let’s be honest: skimming) the release notes of 1.6. The answer is simple, but I had to look in the source of the system check framework to find it. Apparently you have to explicitly define a test runner starting from Django 1.6. To do so, add the following line to your settings:

TEST_RUNNER = 'django.test.runner.DiscoverRunner'

Easy Django management commands with autogenerated aliases

Recently, I got sick of typing django-admin.py <command> to run Django management commands and decided that something must be done about it. This is what I came up with:

This little script creates short aliases for all available Django management commands. Typing this every time you want to work on your project obviously defeats the point, so I added it to bin/activate which is created by virtualenv (you do use virtualenv, don’t you?). I actually do this in a bootstrap script, using this snippet:

If you use virtualenvwrapper, you can append the script to the bin/postactivate script instead.

I know there is bash completion for Django management commands. The advantage of my solution is that it is available for every developer on the project after running the bootstrap script. And it is one character less to type.

To run django-admin.py syncdb, just type djsy<TAB> instead of dj<TAB>sy<TAB>.

Slides from EuroDjangoCon

These are the slides and code of talks given at the EuroDjangoCon, which is held in Prague from May 4th to May 6th. This information can also be found in the EuroDjangoCon Wiki.

Day 1:

Day 2:

Day 3:

Other:

This post will be updated over time. Please leave a comment if you think something is missing.

Building a site with Django? Start with Pinax!

Some time ago, I watched James Tauber’s talk at DjangoCon about Pinax, a collection of re-usable Django applications. If you are thinking of a collection as a bunch of apps carelessly thrown together, you could not be more mistaken. Pinax is the foundation for a complete social networking site which covers most features you can imagine, the whole nine yards.

Forget django-admin.py startproject! Just do cp pinax myproject, remove some stuff you don’t need, adjust the templates and you are done!

Ok, I might be exagerating a bit, but watch the talk to build your own opinion.

Dynamic paths for lazy people

Once your Django project has to run on multiple machines, the absolute paths in settings.py will drive you nuts.

A suggested solution to enhance portability (in German) is to define a PROJECT_ROOT.

import os
PROJECT_ROOT = os.path.dirname(__file__)

And then define absolute paths like this:

MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'site_media')
TEMPLATE_DIRS = (
    os.path.join(PROJECT_ROOT, 'templates'),
)

The downside is, typing os.path.join(PROJECT_ROOT,'foo') twice over and over again, will probably incur the wrath of the DRY gods. But don’t despair, we can do better:

import os
PROJECT_ROOT = os.path.dirname(__file__)
p = lambda *x: os.path.join(PROJECT_ROOT,*x)

Use it like this:

MEDIA_ROOT = p('static')
TEMPLATE_DIRS = (
    p('templates'),
)
MY_NESTED_PATH = p('x','y')

Pitfalls in Django unittests

I’m currently rewriting dwidder [1] and I just spent way to much time on a unit test for the registration view. These are the things that made me stumble:

  1. Write fixtures. Unit tests run on an empty database. Somewhere deep in your code might be a reference to one of the default applications, like django.contrib.sites, which will fail, because there is no default site object in your database.
  2. Don’t subclass unittest.TestCase. Use Django’s TestCase class instead. Otherwise you will miss all the fancy stuff, like automatic fixture loading.
  3. Import mail, not outbox. Django provides a dummy email outbox. But to make it work as expected, you have to import the mail module. If you import the outbox directly, it will always be empty.

[1] a now defunct site where you could tweet by sending an SMS to a German mobile phone number