代码之家  ›  专栏  ›  技术社区  ›  luc

如何用django orm模拟python集?

  •  1
  • luc  · 技术社区  · 15 年前

    我正在申请会员资格。我想做一个会员提醒。(成员在另一段时间内不是成员)。

    目前,我正在使用 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)
    

    我认为这是一个更详细的版本的答案给出了吉斯莱文,这也很适合我。

    感谢S.Lott和Killiands提供了非常有价值的答案,并为不清楚的问题感到抱歉:)

    3 回复  |  直到 15 年前
        1
  •  1
  •   Ghislain Leveque    15 年前

    您应该尝试:

    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')
    
        2
  •  6
  •   KillianDS    15 年前

    它不是简单地否定第二个表达式并将其放入同一个过滤器吗?所以你有点像!(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对象,就像我用前两个查找参数显示的那样。and ing只通过传递多个参数来实现,q对象需要用于否定和/或查找。

        3
  •  3
  •   S.Lott    15 年前

    关系数据库表 一套——根据定义。集合 - where not exists 在SQL中,即 exclude 在Django的ORM中。

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

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