Skip to content
Nov 26 / Nizam Sayeed

Splitting up Django models

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.

  • Pedro Costa

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

    • http://www.nomadjourney.com Nizam

      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. :)

  • Dumb F

    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.

    • http://www.nomadjourney.com Nizam

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

  • Dumb F

    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?

    • http://www.nomadjourney.com Nizam

      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.

  • http://www.amazingworks.com.br Ezequiel Bertti

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

  • http://danielquinn.org/ Daniel Quinn

    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.

  • Thomas Holloway

    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.

    • Wizard of Oz

      Thanks for this comment. I was also having failures with the __init__.py file as originally described.

      Nizam, great post, very concise. My only comment is that I think it would save people quite a bit of time if you could incorporate this comment into your original post.

      Thanks again.

  • Sebastien

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

  • Pingback: Document your Django project using Sphinx documentation tool and reStructuredText | dgraziotin