Breaking Apart Models in Django

Depending on the size of your models.py, you may find it becoming unwieldy, especially if you are on a team with multiple developers are editing the same file, increasing the odds for merge conflicts.

There are two parts to breaking up a large module in Django. The first is a purely Python convention where you break apart the file into multiple files and create a subdirectory for the name of the original module so your models.py file becomes:

models/__init__.py
models/module1.py
models/modlue2.py

Inside your __init__.py you’ll want to import from your module1.py and module2.py modules and add those imported objects to __all__:

# __init__.py
from app.models.module1 import MyClass
from app.models.module2 import AnotherClass, function_one
__all__ = ['MyClass', 'AnotherClass', 'function_one']

Now that you have taken care of the Python part of this exercise, you’ll need to do a couple tricks to get your models importing properly in the context of your django project.

It involves adding a couple o attributes to the Meta inner class. Thanks to Collin Grady (aka Magus on #django on irc.freenode.net) for pointing these tips out to me:

class MyClass:
    ...
    class Meta:
        app_name = 'myappname'
        db_table = 'myappname_myclass'

Now you should have a better code base that causes less contention and makes it faster to locate the models you are looking for.

Update

As has been pointed out to me in the comments as well as one #djano today, I got “Empty” and “Magus” mixed up with their real names. Much apologies for any and all confusion this might have caused.

Update 2

As pointed out in some of the recent comments below, this post was corrupted when I enabled the markdown plugin for wordpress. It is treating all posts I have ever written as markdown which is not right but I have not the energy nor the inclination to go back in time and update all my old posts. That being said, I really love markdown for my posting so I’ll keep the plugin activated.

12 comments ↓

#1 derelm on 01.29.08 at 9:04 pm

Magus != Michael Trier

#2 Kent Johnson on 01.29.08 at 9:10 pm

db_table is not needed with Django 0.96.

#3 Patrick Altman on 01.29.08 at 9:16 pm

@derelm: good catch, I am not why I got him mixed up with Empty. appears that Magus == Collin Grady (http://djangopeople.net/magus/)

@kent: thanks, good to know!

#4 Collin on 01.30.08 at 2:24 pm

Actually, the dbtable option should not be required - only applabel (not app_name)

#5 Patrick Altman on 01.30.08 at 2:51 pm

@collin: thanks for the edit

#6 Chris Heisel on 01.31.08 at 1:21 pm

I also don’t think you want/need the .py on the end of your import statements.

Thus: from app.models.module1.py import MyClass from app.models.module2.py import AnotherClass, function_one

Shoudl be from app.models.module1 import MyClass from app.models.module2 import AnotherClass, function_one

#7 Patrick Altman on 01.31.08 at 1:26 pm

@Chris: you’re right, that was a silly typo/mistake on my part. thanks.

#8 Neal McBurnett on 02.16.08 at 1:58 pm

You still have “appname” and “dbtable” there, despite the comment that it should be just “app_label”. I’m no expert, but that seems correct to me given the official documentation:

http://www.djangoproject.com/documentation/model-api/

#9 Giuliani Vito, Ivan on 04.25.08 at 1:54 pm

shouldn’t be init.py instead of init.py in the first example?

#10 Giuliani Vito, Ivan on 04.25.08 at 4:07 pm

got it: the double underscore disappear because of formatting syntax :)

#11 Patrick Altman on 04.25.08 at 4:24 pm

@Ivan: should be all fixed now. thanks!

#12 rbd on 07.22.08 at 12:54 pm

Note that this method works for me, but it seems to break fixture importing (manage.py loaddata, or initial_data importing after a syncdb). This is because the loaddata code in django gets the fixtures path via:

appfixtures = [os.path.join(os.path.dirname(app.file), 'fixtures') for app in getapps()]

Which means that django ends up looking in myproj/myapp/models/fixtures for the fixtures, instead of myproj/myapp/fixtures.

As can be expected, the fix for this is to explicitly specify the fixtures path as settings.FIXTURE_DIRS

Robby

Leave a Comment