The Django’s ORM already has its own data loading mechanism for testing but you can use the Fixture module as an alternative. When using Fixture, you don’t have to deal with JSON or XML, you simply create DataSet objects in Python code and load them with an instance of DjangoFixture. Using Python code helps you share objects and common field definitions whereas in Django you might have many JSON files with the same field definitions in separate places. Using Python code also allows you to represent test data alongside your test code, take advantage of inheritance, and improve readability.
However, unlike Django, Fixture does not currently provide a way to auto generate DataSet classes from a real database. It is safe to mix Fixture style data loading and Django style data loading if desired.
This feature was contributed by Ben Ford.
Fixture can only be used with Django version 1.0.2 and greater.
Here’s a simple blog application written in Django. The data model consists of Post objects that belong to Category objects.
from django.db import models from django.utils.translation import ugettext_lazy as _ from django.contrib.auth.models import User class Category(models.Model): title = models.CharField(_('title'), max_length=100) slug = models.SlugField(_('slug'), unique=True) def __unicode__(self): return u'%s' % self.title class Post(models.Model): title = models.CharField(_('title'), max_length=200) author = models.ForeignKey(User, blank=True, null=True) body = models.TextField(_('body')) created = models.DateTimeField(_('created'), auto_now_add=True) modified = models.DateTimeField(_('modified'), auto_now=True) categories = models.ManyToManyField(Category, blank=True) def __unicode__(self): return u'%s' % self.title
A complete version of this blog app with fixtures and tests can be found in fixture/examples/django_example/blog/
To load data into the test database, you first create some DataSet subclasses in Python code:
class UserData(DataSet): class Meta: django_model = 'auth.User' class ben: first_name = 'Ben' last_name = 'Ford' # ...
In this example, the nested class ben will be used to create a row in django’s auth.User model. Fixture knows to load into that model because of the django_model attribute of the inner Meta class. A couple other ways to link each DataSet to a specfic Django model are shown later on.
More realistically you would need to load one or more foreign key dependencies as part of each DataSet. Here are the DataSets for testing the blog application, taken from fixture/examples/django_example/blog/datasets/blog_data.py
from fixture import DataSet, DjangoFixture from blog.datasets.user_data import UserData class BlogMeta: django_app_label = 'blog' class CategoryData(DataSet): class Meta(BlogMeta): pass class python: title = 'python' slug = 'py' class testing: title = 'testing' slug = 'test' class PostData(DataSet): class Meta(BlogMeta): pass class first_post: title = "1st test post" body = "this one's about python" author = UserData.ben categories = [CategoryData.python] class second_post(first_post): title = "2nd test post" body = "this one's also about python" class third_post(first_post): title = "3rd test post" body = "this one's about both" categories = [CategoryData.python, CategoryData.testing]
Here first_post is a blog entry posted in the Python category and authored by Ben (notice the UserData class has been imported from the user_data module).
In this style, each DataSet class name starts with that of the Django model it should be loaded into and a shared class BlogMeta has the attribute django_app_label='blog' to tell the loader which app to find models in.
In the current release of fixture you can only specify a relationship from the direction that the field is defined, not from the reverse (see DjangoMedium for more details).
>>> from fixture import DjangoFixture >>> from fixture.style import NamedDataStyle >>> db_fixture = DjangoFixture(style=NamedDataStyle())
You would insert each defined row into its target database table via setup() :
>>> data = db_fixture.data(CategoryData, PostData) >>> data.setup() >>> Post.objects.filter(author__first_name='Ben').count() 3 >>> data.teardown() >>> Post.objects.all() 
Foreign DataSet classes like UserData need not be mentioned in data() since they are loaded automatically when referenced.
Here is an example of how to create a unittest style class to test with data. This is taken directly from fixture.examples.django_example.blog.tests:
from fixture import DataSet, DjangoFixture from fixture.style import NamedDataStyle from fixture.django_testcase import FixtureTestCase from datetime import datetime from django.contrib.auth.models import User from fixture.examples.django_example.blog.models import Post, Category from fixture.examples.django_example.blog.datasets.blog_data import ( UserData, PostData, CategoryData) db_fixture = DjangoFixture(style=NamedDataStyle()) class TestBlogWithData(FixtureTestCase): fixture = db_fixture datasets = [PostData] def test_blog_posts(self): self.assertEquals(Post.objects.all().count(), 3, "There are 3 blog posts") post = Post.objects.get(title=PostData.third_post.title) self.assertEquals(post.categories.count(), 2, "The 3rd test post is in 2 categories") def test_posts_by_category(self): py = Category.objects.get(title=CategoryData.python.title) self.assertEquals(py.post_set.count(), 3, "There are 3 posts in python category") def test_posts_by_author(self): ben = User.objects.get(username=UserData.ben.username) self.assertEquals(ben.post_set.all().count(), 3, "Ben has published 3 posts")
This test case uses Django’s fast data loading strategy introduced in 1.1 whereby data is removed by rolling back the transaction. If you need to test specific transactional behavior in your code then don’t use this test case.
See fixture.django_testcase.FixtureTestCase for details on how to configure the test case.