如何用django ORM模仿Python集?

时间:2010-08-02 09:46:02

标签: python django django-orm

我正在处理会员申请。我想提出会员提醒。 (成员在一段时间内不是另一段时间的成员)。

目前,我正在使用set进行此计算。请参阅下面的代码。

class Member(models.Model):
     ...

class Membership(models.Model):
    member = models.ForeignKey(Member, verbose_name=_("Member"))
    start_date = models.DateField(_("Start date"))
    end_date = models.DateField(_("End date"))

x = Member.objects.filter(Q(membership__start_date__lte=dt1) & Q(membership__end_date__gte=dt1))
y = Member.objects.filter(Q(membership__start_date__lte=dt2) & Q(membership__end_date__gte=dt2))
result = set(x) - set(y)

我想知道我只能通过使用django ORM(filter,exclude,annotate,distinct ...)来实现它?

提前感谢您的帮助

更新

事实上,我的模型有点复杂。我也有报纸外键。

class Member(models.Model):
     ...

class Newspaper(models.Model):
     ...

class Membership(models.Model):
    member = models.ForeignKey(Member, verbose_name=_("Member"))
    start_date = models.DateField(_("Start date"))
    end_date = models.DateField(_("End date"))
    newspaper = models.ForeignKey(Newspaper)

我希望得到一份特定报纸的提醒。在这种情况下,工作查询是

sin = models.Membership.objects.filter(start_date__lte=dt1,
                                               end_date__gte=dt1,
                                               newspaper__id=2)

sout = models.Membership.objects.filter(start_date__lte=dt2,
                                          end_date__gte=dt2,
                                          newspaper__id=2)
result = models.Member.objects.filter(membership__in=sin).exclude(membership__in=sout)

我认为这个答案更加冗长,Ghislain Leveque对我来说也很好。

感谢S.Lott和KillianDS提供了非常有价值的答案,并对不太明确的问题表示抱歉:)

3 个答案:

答案 0 :(得分:6)

是不是简单地否定了第二个表达式并将其放在同一个过滤器中?所以你有类似的东西!(a& b),等于(!a)|(!b),在这种情况下:

result = Member.objects.filter(membership__start_date__lte=dt1, membership__end_date__gte=dt1, ~Q(membership__start_date__lte=dt2) | ~Q(membership__end_date__gte=dt2))

请注意,对于简单的anding和基本查找,您不需要Q对象,就像我使用前两个查找参数一样。 Anding只是通过传递多个参数来实现,需要Q对象来否定和OR'ing查找。

答案 1 :(得分:3)

关系数据库表 是一个集合 - 按定义。在SQL中设置-where not exists,在Django的ORM中为exclude

似乎(没有测试)你正在这样做。

result = Member.objects.filter(
    Q(membership__start_date__lte=dt1) & Q(membership__end_date__gte=dt1)
).exclude(
    Q(membership__start_date__lte=dt2) & Q(membership__end_date__gte=dt2)
)

答案 2 :(得分:1)

你应该尝试:

result = Member.objects.\
    filter(
        membership__start_date__lte = dt1,
        membership__end_date__gte=dt1).\
    exclude(
        pk__in = \
            Member.objects.filter(
                membership__start_date__lte = dt2,
                membership__end_date__gte = dt2).\
    values_list('pk')