views:

717

answers:

3

I am in the middle of developing a Django application, which has quite complicated models (it models a university - courses, modules, lectures, students etc.)

I have separated the project into apps, to make the whole thing more organised (apps are courses, schools, people, modules and timeperiods). I am having a problem whereby a model in one app may depend on a model in another - so I must import it. The second app then in turn depends on a model in the first, so there is a cycle and Python throws up an error.

How do people deal with this? I understand that apps should be relatively "independent", but in a system like this it doesn't make sense, for example, to use ContentTypes to link students to a module.

Does anyone have a similar project that could comment on this case?

+1  A: 

Normally I advocate for splitting functionality into smaller apps, but a circular dependence between models reflects such a tight integration that you're probably not gaining much from the split and might just consider merging the apps. If that results in an app that feels too large, there may be a way to make the split along a different axis, resulting in a more sane dependency graph.

Carl Meyer
+2  A: 

If you're seeing circular model dependency I'm guessing that one of three things is happening:

  • You've defined an inverse relationship to one that's already defined (for instance both course has many lectures and lecture has one course) which is redundant in django
  • You have a model method in the wrong app
  • You're providing functionality in a model method that ought to be in a manager

Maybe you could show us what's happening in these models and we can try to figure out why the problem is arising. Circular model dependency is rarely an indication that you need to combine two apps - it's more likely (though not definitely the case) that there's a problem with one of your model definitions.

p.s. I am working on a similar django application, but my app structure is probably quite different to your's. I'd be happy to give you a high-level description of it if you're interested.

ozan
Interesting. The problem I am having in detail, is that a Module (modules app) has a ForeignKey to Person (people app), for its students. TutorGroup in the people app then has a ForeignKey to Module - to assign a tutor group to a particular module. This is what's resulting in the dependency cycle. I can post a diagram of the models also if its still unclear.I'd love to see the general structure of your project - it's really useful to see how others do things.
Rob Golding
So is the relationship between Module and Person many-to-many (seems like it should be)? If so, you could define the relationship in Person with the related_name parameter set to 'students'. Then module_instance.students.all() would give you the queryset that I think you're looking for.In my case, I don't have a Person model. I have two m2m relations from Course to User, one for students and another for teachers. Keeps it super simple.
ozan
Yeah it works with ManyToManyField's at present - and I could move it over to the Person model - but it just seems less "neat" - it makes sense to have it on the Module model. I have to have a "Person" as it extends Django's User, so I can add more functionality (like Job Descriptions etc.) I could have use profiles but this is simpler after some middleware I wrote to return People instead of Users :)
Rob Golding
+13  A: 

If your dependency is with foreign keys referencing models in other applications, you don't need to import the other model. You can use a string in your ForeignKey definition:

class MyModel(models.Model):
    myfield = models.ForeignKey('myotherapp.MyOtherModel')

This way there's no need to import MyOtherModel, so no circular reference. Django resolves the string internally, and it all works as expected.

Daniel Roseman
Fantastic. This is exactly what I was looking for. Funnily enough I knew you could do this - as I use it in places where the ForeignKey references something that is defined later in the file, but I never thought of using it in this way. Thank you very much!
Rob Golding
Thank you thank you. Much aggravation has been averted.
DGGenuine
Hooray! This should be better documented on http://docs.djangoproject.com
slacy
Was absolutely stuck trying to get models to validate until I found your post. All it was giving me was Error: cannot import name <model> Thank you!