Splitting up Django models

2009 November 26

Sometimes it makes sense to split up your Django models for a specific application across multiple files instead of having all of them in one models.py file. This allows for easier and simpler code organization and maintenance.

Splitting up your models in Django is fairly simple, although it requires a few extra steps. In our example, we’ll create two Django models, Foo and Bar, each defined in their own files within an app called myapp.

Let’s also assume that Bar has a ForeignKey to Foo.

Create a models Python module within the app. The application directory structure may look something like:

  • /myapp
    • /models
      • __init__.py
      • bar.py
      • foo.py

Here are the contents of foo.py:

from django.db import models

class Foo( models.Model ):
    foo_text = models.CharField()

    class Meta:
        app_label = 'myapp'

And bar.py:

from django.db import models
from myapp.models.foo import Foo

class Bar( models.Model ):
    foo = models.ForeignKey( Foo )
    bar_text = models.CharField()

    class Meta:
        app_label = 'myapp'

Notice the definition of the app_label property in the inner Meta classes for each model. This is very important to let Django’s syncdb command know that these split up model classes belong to the same application.

We’re not done yet. You’ll also need to explicitly import each model class in the model module’s __init__.py file:

from myapp.models.foo import Foo
from myapp.models.bar import Bar

And that’s it. Run syncdb and you should be all set.

NOTE: One thing to note about ForeignKey relationships is that the import order in __init__.py is very important. Since Bar has a ForeignKey to Foo, Foo must be imported before Bar.

NOTE: If you are splitting up the contents of an existing models.py file, make sure to delete the original models.py file when you are done otherwise syncdb may get confused.

UPDATE November 28, 2009 @ 3:30PM) Pedro Costa pointed out an existing issue with Django (ticket #6961) and loading fixtures for split up models. One solution is to just put the fixtures under the new /models sub-dir since Django is already looking for them there. However, this may break once they do fix the bug in the Django code base. Or you could try Justin Lillly’s approach which was mentioned on his blog.

UPDATE November 29, 2009 @ 10:04AM) I was asked to illustrate how to use a ForeignKey between these models. I have modified my post to show an example of how to do that.

7 Responses leave one →
  1. 2009 November 26
    Pedro Costa permalink

    This would be great but has problems with fixtures:

    http://code.djangoproject.com/ticket/6961

    I saw here: http://justinlilly.com/blog/2009/oct/27/fix-your-models-subdir/
    how to solve this problem and it works!!

    • 2009 November 26

      Pedro,

      Thanks for your comment. All this time, I was putting my fixtures under the /models sub-directory. I thought it was a Django feature and it turns out to be a bug. :)

  2. 2009 November 29
    Dumb F permalink

    N00b here. Could you make one of your models have a foreign key to the other one? That would make a more complete guide for us n00bs.

    Thanks.

    • 2009 November 29

      Sure thing. I just added that in as part of the example. Thanks.

  3. 2009 December 1
    Dumb F permalink

    Thanks a lot for taking note of my earlier comment.

    In the article where it says “You’ll also need to explicitly import each model class in the model module’s __init__.py file”, am I right in saying that the models would need to be imported in the proper order for syncdb etc to work right?

    • 2009 December 1

      Yup, you are absolutely right. I have added a note at the end:

      NOTE: One thing to note about ForeignKey relationships is that the import order in __init__.py is very important. Since Bar has a ForeignKey to Foo, Foo must be imported before Bar.

  4. 2009 December 12

    This is the best “HOW TO” to make split models file in django!!! thanks!!!

Leave a Reply

Note: You can use basic XHTML in your comments. Your email address will never be published.

Subscribe to this comment feed via RSS