Reputation: 182772
I've got models where the objects are date dependent, but also the relationship between them is date dependent. So, just for illustration, I might have
class ValidCommonManager(models.Manager):
ValidCommonManager(self, date):
self.date = date
def get_query_set(self):
return super(ValidCommonManager, self).get_query_set().filter(
models.Q(start__isnull=True)|
models.Q(start__lte=self.date)
).filter(
models.Q(end__isnull=True)|
models.Q(end__gte=self.date)
)
class CommonModel(models.Model):
start = models.DateTimeField(null=True)
end = models.DateTimeField(null=True)
valid_objects = ValidCommonManager(now())
objects = models.Manager()
class Group(CommonModel):
name = models.CharField(max_length=25)
description = models.TextField(blank=True)
group_members = models.ManyToManyField(
'Person', through='GroupMember')
class GroupMember(CommonModel):
group = models.ForeignKey(Group)
member = models.ForeignKey(Person)
class Person(CommonModel):
name = models.CharField(max_length=100)
Now the group might exist from date A to date Z, but the membership might be different at date B and date C, which is reflected by the start and end fields in GroupMember. Now it's easy to find groups that are active at the time I'm currently processing using
groups = Group.valid_objects.all()
But I can't figure out an easy way to get the members of the group at a given date short of
members_of_my_group = group.group_members.filter(
models.Q(start__isnull=True)|
models.Q(start__lte=date)
).filter(
models.Q(end__isnull=True)|
models.Q(end__gte=date)
).filter(
models.Q(group_member__start__isnull=True)|
models.Q(group_member__start__lte=date)
).filter(
models.Q(group_member__end__isnull=True)|
models.Q(group_member__end__gte=date)
)
which rapidly gets clumsy and violates the basics of DRY. I'd set use_for_related_fields
on ValidCommonManager
, but the Django docs promise nasty things if you do that on a manager that filters.
Upvotes: 1
Views: 116
Reputation: 48922
Related managers are just for convenience, you could always define a custom Manager
for Person
that would do the same thing. (Also note that as of Django 1.7 you can specify the manager you want to use for related lookups on a case-by-case basis. See the docs for more information.)
That is,
group_members = Group.group_members.filter(...)
is equivalent to:
class PersonManager(models.Manager):
def get_valid_members(self, group):
return self.filter(groupmember__group=group,
Q(groupmember__start__isnull=True)...
group_members = Person.objects.get_valid_members(group)
Another approach would be to use subqueries:
group_members = Person.objects.filter(groupmember__in=
GroupMember.valid_objects.filter(group=group))
Upvotes: 1