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.

10 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!!!

  5. 2010 January 18

    This is one of those things that should really be part of the official documentation. I really wish that I’d found this 3hours ago rather than tinkering and surfing for all that time :-(

    Great post though btw.

  6. 2010 April 7
    Thomas Holloway permalink

    I couldn’t get it to work until I revised my __init__.py to simply:


    from foo import Foo
    from bar import Bar

    This works and makes sense since you don’t need to specify the full namespace from the top level.

  7. 2010 April 29
    Sebastien permalink

    Hi !
    I did what you said (thanks by the way, because it was -until recently- very useful!), but when I try to dynamically import some models, I got something strange…
    Take a look a my code (which is in myapp.logger.__init__.py) :

    from django.conf import settings

    for log_hook in settings.LOG_HOOKS :
    try :
    __import__(log_hook)
    except ImportError as e :
    pass
    #from myapp.logger.hooks.vmm import *

    Now, the problem is that when I try to import dynamically, I got some import errors, while if I directly write exactly the same import statement as the one generated, everything goes well…

    Any idea to make this dynamic import work would be greatly welcome !!!

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