Django App Dependency Cycle

2019-01-16 16:59发布

问题:

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:

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.



回答2:

This may not be well-suited to your situation, but ignoring the Django aspect to your question, the general technique for breaking circular dependencies is to break out one of the cross-referenced items into a new module. For example:

moduleA: class1, class2
           |        ^
           v        |
moduleB: class3, class4

could become:

moduleC: class 3
           ^
           |
moduleA: class 1, class 2
                     ^
                     |
moduleB:          class 4

(Or alternatively, you could have broken class 2 out into its own module. Or both!)

Of course, this is no help if class A & B depend on each other. In that case, maybe they should be in the same module, or better still, maybe some part of these classes could be broken out into a third module, which both classes depend upon.



回答3:

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.



回答4:

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.