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
If you're seeing circular model dependency I'm guessing that one of three things is happening:
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.
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.
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.
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.