过滤外键和多对多连接表

时间:2014-04-25 20:11:13

标签: django django-orm

我有模型,其中对象与日期有关,但它们之间的关系依赖于日期。所以,仅仅是为了说明,我可能有

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)

现在该组可能从日期A到日期Z存在,但成员资格在日期B和日期C可能不同,这由GroupMember中的开始和结束字段反映。现在,在我正在使用

处理时,很容易找到活动的组
groups = Group.valid_objects.all()

但我无法找到一个简单的方法来让小组成员在给定日期之前

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)
        )

迅速变得笨拙并且违反了DRY的基础知识。我在use_for_related_fields上设置了ValidCommonManager,但Django docs承诺在过滤的管理员身上做出令人讨厌的事情。

1 个答案:

答案 0 :(得分:1)

相关管理员只是为了方便起见,您始终可以为Manager定义一个可以执行相同操作的自定义Person。 (另请注意,从Django 1.7开始,您可以根据具体情况指定要用于相关查找的管理器。有关详细信息,请参阅the docs。)

即,

group_members = Group.group_members.filter(...)

相当于:

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)

另一种方法是使用子查询:

group_members = Person.objects.filter(groupmember__in=
                    GroupMember.valid_objects.filter(group=group))