Reputation: 4495
I have x models.py
files, in x different Django apps. I have certain queries related to said models thatI call throughout my app. I figured the best way to DRY-ify this is to have the query be called by a method inside the model.
These query methods actually query /other/ models inside /other/ apps (and therefore other models.py
files). I understand that this increases coupling, but it's a large and highly specialised project, so I can't really write generic reusable apps for a lot of the stuff.
For example:
class Mentor(models.Model):
# ...
def get_future_shifts(self):
return Shift.objects.filter(mentor = self, session__date__gt = timezone.now())
I've ended up with a circular dependency (it spans along 4 apps so I figured it was too long to post ALL that code here unless absolutely necessary).
The usual circular dependency advice for Django models on SO is related to models.ForeignKey
and that is not my issue. I need to actually access the 'foreign' model.
I'm told that a circular dependency is a sign of bad design, and my bad design is that I have too many dynamic helper methods in my models? Django doesn't really provide anywhere else to put these without adhering to DRY.
Upvotes: 1
Views: 540
Reputation: 77892
Your get_future_shifts()
method implies that Shift
has a FK on Mentor
. In this case, you don't need to import Shift
in the module containing Mentor
, you can just use the reverse relationship ie:
class Mentor(models.Model):
# ...
def get_future_shifts(self):
return self.shift_set.filter(session__date__gt=timezone.now())
but this will only "technically" solve the circular dependency, since it means that Mentor
has some direct knowledge of another app that itself depends on the app where Mentor
is defined and the whole thing will break if you remove this other app from your settings.
Another solution is to define get_future_shifts
in the same app as Shift' and monkeypatch
Mentor`, ie:
from otherapp.models import Mentor
class Shift(models.Model):
mentor = models.ForeignKey(Mentor)
# Extend Mentor with get_future_shifts helper
def get_future_shifts(mentor):
return mentor.shift_set.filter(session__date__gt=timezone.now())
Mentor.get_future_shifts = get_future_shifts
Some will frown upon extending a class from another module / app, but just defining a FK on Mentor here is already extending Mentor
, so at least we keep related stuff together and now Mentor
has no direct dependency on Shift
- as long as nothing in Mentor
's app's views etc depends on get_future_shifts()
at least, but then it means that Shifts
should really belong to the same app as Mentor
.
Upvotes: 0
Reputation: 4495
There exists a method, django.db.models.get_model()
, that gets a model given its name. This'll fix it as you aren't actually importing the model.
Upvotes: 2