Split models.py to smaller parts.

4,579 views
Skip to first unread message

x_O

unread,
Apr 20, 2009, 5:57:58 AM4/20/09
to Django users
Hi

I'm looking for some general solution how to split models.py. Right
now my models.py reached 1000 lines and that argues some how with good
programing behaviour that I used use.

I'm thinking about:
myproject/
settings.py
myapp/
models/
file.py
directory.py

instead of classic solution:
myproject/
settings.py
myapp/
models.py
views.py

to In the simple case where in models we are able to avoid cyclic
import there is no problem. But what when classes definition use each
other implementation.
Django implements very nice and tricky solution using 'string' to
import definition in related fields.
http://docs.djangoproject.com/en/dev/ref/models/fields/#module-django.db.models.fields.related
but in current case its useless.

Any idea how to win with that problem?

x_O

Rick Wagner

unread,
Apr 20, 2009, 12:19:01 PM4/20/09
to Django users


On Apr 20, 2:57 am, x_O <Sebastian.Paw...@gmail.com> wrote:
> Hi
>
> I'm looking for some general solution how to split models.py. Right
> now my models.py reached 1000 lines and that argues some how with good
> programing behaviour that I used use.
>
> I'm thinking about:
> myproject/
>    settings.py
>    myapp/
>       models/
>          file.py
>          directory.py
>
> instead of classic solution:
> myproject/
>    settings.py
>    myapp/
>       models.py
>       views.py
>
> to In the simple case where in models we are able to avoid cyclic
> import there is no problem. But what when classes definition use each
> other implementation.
> Django implements very nice and tricky solution using 'string' to
> import definition in related fields.http://docs.djangoproject.com/en/dev/ref/models/fields/#module-django...
> but in current case its useless.
>
> Any idea how to win with that problem?
>
> x_O

Hi,

You're actually dealing with two separate issues:

1) How to move the model files into a separate package (i.e., a
directory named "models/").
2) How to reference models in different modules, that may or may not
have been defined.

To move the models into their own packages, move them into a directory
named "models/", and create a file name __init__.py to make the
directory a package:

myapp/
models/
__init__.py
one.py
two.py

In one.py, define your first model, but you'll need to add the
attribute "app_label" to the Meta inner class. Here's one.py:

from django.db import models

class ModelOne(models.Model):
class Meta:
app_label = 'myapp'

Now, in two.py, you can either reference ModelOne using its name, or
by importing it first. Here's the string version of two.py:

from django.db import models

class ModelTwo(models.Model):
one = models.ForeignKey('ModelOne')

class Meta:
app_label = 'myapp'

Here's the import version of two.py:

from django.db import models
from one import ModelOne

class ModelTwo(models.Model):
one = models.ForeignKey(ModelOne)

class Meta:
app_label = 'myapp'

Finally, you're going to need to import these models into the
__init__.py modules, so that when it's imported later, it finds your
models. Here's the contents of __init__.py:

from one import ModelOne
from two import ModelTwo

A way to check that all of this is working is to either use "manage.py
validate", or "manage.py sql myapp", to view the SQL that will be used
to created the models' tables. Here's what I see:

rpwagner$ ./manage.py validate
0 errors found
rpwagner$ ./manage.py sql myapp
BEGIN;
CREATE TABLE "myapp_modelone" (
"id" integer NOT NULL PRIMARY KEY
)
;
CREATE TABLE "myapp_modeltwo" (
"id" integer NOT NULL PRIMARY KEY,
"one_id" integer NOT NULL REFERENCES "myapp_modelone" ("id")
)
;
COMMIT;
rpwagner$

Hope this helps.

--Rick

johan.uhIe

unread,
May 3, 2009, 7:54:34 AM5/3/09
to Django users
Thank you for the explanation. I think this trick is not in the
Documentation yet, I've opened a ticket for it ...
http://code.djangoproject.com/ticket/10985

Masklinn

unread,
May 3, 2009, 8:38:25 AM5/3/09
to django...@googlegroups.com
On 3 May 2009, at 13:54 , johan.uhIe wrote:
> Thank you for the explanation. I think this trick is not in the
> Documentation yet

That's because it's pretty basic Python knowledge. I'm sure I've read
on this list that basic Python knowledge isn't supposed to be
documented in Django as it's already part of the official Python
documentation (http://docs.python.org/tutorial/modules.html#packages)


Rick Wagner

unread,
May 3, 2009, 1:01:51 PM5/3/09
to Django users
> > Thank you for the explanation. I think this trick is not in the
> > Documentation yet
>
> That's because it's pretty basic Python knowledge. I'm sure I've read  
> on this list that basic Python knowledge isn't supposed to be  
> documented in Django as it's already part of the official Python  
> documentation (http://docs.python.org/tutorial/modules.html#packages)

Most of it is a knowledge of Python, but the need for adding things
like app_label is not obvious. Once I'm clear on how Django's model
framework introspects the Python classes it finds in an application,
I'll try to write up an internally consistent addition to the docs.

--Rick

Malcolm Tredinnick

unread,
May 3, 2009, 1:48:24 PM5/3/09
to django...@googlegroups.com

The preferred solution is to fix the problem so that app_label doesn't
have to be specified. There's already a ticket open that, I'm sure,
since people keep saying "I'll work on it". It's probably not even that
hard to get right -- although all attempts to do so to date have only
fixed the basic cases and not the general situation (arbitrary levels of
imports).

Regards,
Malcolm


x_O

unread,
May 21, 2009, 6:19:35 AM5/21/09
to Django users
First of all thanks for all responses.

I've still one more question which is connected to that one particular
issue. What if classes are importing each other.

models/
__init__.py
one.py
two.py

====== __init__.py =======

from one import ModelOne
from two import ModelTwo

======= one.py ========

from django.db import models
from two import ModelTwo

class ModelOne(models.Model):
two = models.ForeignKey('ModelTwo')
class Meta:
app_label = 'appname'

def all_one(self):
return ModelTwo.objects.all()


======= two.py ========

from django.db import models
from one import ModelOne

class ModelTwo(models.Model):
one = models.ForeignKey('ModelOne')

class Meta:
app_label = 'appname'

def all_two(self):
return ModelOne.objects.all()


In case above appears problem with cyclic import. I know that example
is a bit silly but I'm trying to use it in real project files with
more than 1000 lines ~300 per class.

==== Traceback ====
./manage.py validate
Traceback (most recent call last):
File "./manage.py", line 11, in <module>
execute_manager(settings)
File "/var/lib/python-support/python2.5/django/core/management/
__init__.py", line 340, in execute_manager
utility.execute()
File "/var/lib/python-support/python2.5/django/core/management/
__init__.py", line 295, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/var/lib/python-support/python2.5/django/core/management/
base.py", line 192, in run_from_argv
self.execute(*args, **options.__dict__)
File "/var/lib/python-support/python2.5/django/core/management/
base.py", line 219, in execute
output = self.handle(*args, **options)
File "/var/lib/python-support/python2.5/django/core/management/
base.py", line 348, in handle
return self.handle_noargs(**options)
File "/var/lib/python-support/python2.5/django/core/management/
commands/validate.py", line 9, in handle_noargs
self.validate(display_num_errors=True)
File "/var/lib/python-support/python2.5/django/core/management/
base.py", line 246, in validate
num_errors = get_validation_errors(s, app)
File "/var/lib/python-support/python2.5/django/core/management/
validation.py", line 28, in get_validation_errors
for (app_name, error) in get_app_errors().items():
File "/var/lib/python-support/python2.5/django/db/models/
loading.py", line 128, in get_app_errors
self._populate()
File "/var/lib/python-support/python2.5/django/db/models/
loading.py", line 57, in _populate
self.load_app(app_name, True)
File "/var/lib/python-support/python2.5/django/db/models/
loading.py", line 72, in load_app
mod = __import__(app_name, {}, {}, ['models'])
File "/.../appname/models/__init__.py", line 1, in <module>
from one import ModelOne
File "/.../appname/models/one.py", line 2, in <module>
from two import ModelTwo
File "/.../appname/distmodels/models/two.py", line 2, in <module>
from one import ModelOne
ImportError: cannot import name ModelOne


Regards
x_O
Reply all
Reply to author
Forward
0 new messages