django – 在qs.excude()中通过span关系评估同一个对象

django – 在qs.excude()中通过span关系评估同一个对象,第1张

概述考虑一个带房间对象的酒店和这些房间的预订对象.我想找到哪个房间在特定时期可用,或者(从下面的例子中),从哪个日期开始. 可以“删除”预约,这可以通过设置“实时”字段获得.所以它们实际上并没有删除,只是处于非活动状态,这需要保持这种状态. >>> indate = "20141225">>> Room.objects.exclude((models.Q(reservation__live=Tru 考虑一个带房间对象的酒店和这些房间的预订对象.我想找到哪个房间在特定时期可用,或者(从下面的例子中),从哪个日期开始.

可以“删除”预约,这可以通过设置“实时”字段获得.所以它们实际上并没有删除,只是处于非活动状态,这需要保持这种状态.

>>> indate = "20141225">>> Room.objects.exclude((models.Q(reservation__live=True,reservation__date_out__gt=indate) | models.Q(reservation__date_out__isnull=True,reservation__live=True)))

问题陈述:上面的代码有一个令人遗憾的副作用:当有一个生命值= True的预订超出期限,并且当同一个房间的期间内有另一个预约live = False时,那个房间将被排除在外.情况并非如此:由于我要求的期间内的预订未设置为live = True,因此不应将其考虑在内.

看起来我上面的查询在通过房间预订关系进行(live = True和date_out__gt = indate)比较时没有考虑相同的预留.

问题:在exclude()中是否有一种方法可以确保在比较中考虑相同的保留?

我试着玩负模型.Q(~Models.Q)无济于事.
请注意,上面只是一个更大的查询中的代码提取(问题所在的位置).因此我不能简单地做qs.filter(reservation__live = True).移动查询以过滤而不是排除似乎不是一个选项.

编辑:根据请求添加我的简化模型,如下所示.
Edit2:添加一些解释问题的测试数据,并根据@ knbk的建议添加一个链式exclude().

class AvailableRoomManager(models.Manager):    def available_with_Q(self,indate,outdate):        qs = super(AvailableRoomManager,self).get_queryset()        if indate and outdate:            qs = qs.exclude(models.Q(reservation__date_out__gt=indate,reservation__date_in__lt=outdate,reservation__live=True)                            | models.Q(reservation__date_out__isnull=True,reservation__date_in__isnull=False,reservation__live=True))        elif indate and not outdate:            qs = qs.exclude((models.Q(reservation__date_out__gt=indate,reservation__live=True)))        return qs    def available_with_chained_excludes(self,self).get_queryset()        if indate and outdate:            qs = qs.exclude(reservation__date_out__gt=indate,reservation__live=True) \                   .exclude(reservation__date_out__isnull=True,reservation__live=True)        elif indate and not outdate:            qs = qs.exclude(reservation__date_out__gt=indate,reservation__live=True)        return qsclass Room(models.Model):    name = models.CharFIEld(max_length=30,unique=True)    objects = models.Manager()    available_rooms = AvailableRoomManager()    def __str__(self):        return self.nameclass Reservation(models.Model):     date_in = models.DateFIEld()    date_out = models.DateFIEld(blank=True,null=True)    room = models.ForeignKey(Room)    live = liveFIEld()  # See django-livefIEld; to do deletion. Basically adds a fIEld "live" to the model.    objects = liveManager()    all_objects = liveManager(include_soft_deleted=True)

当搜索周期之外存在活动(live = True)时,以及在我正在搜索的时间段内存在非活动(live!= True)时,上述exclude()语句中会d出该问题.

一些简单的测试数据使用上述模型,显示问题所在:

# Let's make two rooms,R001 and R002>>> room1 = Room.objects.get_or_create(name="R001")[0]>>> room2 = Room.objects.get_or_create(name="R002")[0]# First reservation,with no date_out,is created but then "deleted" by setting fIEld 'live' to False>>> res1 = Reservation.objects.get_or_create(date_in="2014-12-01",date_out=None,room=room1)[0]>>> res1.live = False>>> res1.save()# Second reservation in same room is created with date_out set to Dec 15th>>> res2 = Reservation.objects.get_or_create(date_in="2014-12-01",date_out="2014-12-15",room=room1)[0]# Here I'd expect to have R001 Listed as well... this is not the case>>> Room.available_rooms.available_with_Q("2014-12-16","")[<Room: R002>]>>> Room.available_rooms.available_with_chained_excludes("2014-12-16","")[<Room: R002>]# As a test,when changing "deleted" res1's Room to room2,the manager does return R001>>> res1.room = room2>>> res1.save()>>> Room.available_rooms.available_with_Q("2014-12-16","")[<Room: R001>,<Room: R002>]>>> Room.available_rooms.available_with_chained_excludes("2014-12-16",<Room: R002>]
解决方法 我用你的github项目测试了它,我得到了和你一样的结果.看来,当过滤器正确地将多个相关对象过滤器转换为INNER JOIN时,exclude会在某种子查询中转换它,其中每个过滤器(即使在同一个调用中)都会自行检查.

我找到了一个解决方法,那就是显式创建保留子查询:

elif indate and not outdate:    ress = Reservation.objects.filter(Q(live=True,date_in__isnull=False),Q(date_out__gt=indate) | Q(date_out__isnull=True))    rooms = Room.objects.exclude(reservation__in=ress)etc...

顺便说一句,如果您需要使用过滤器而不是排除,以下查询总是相同的,事实上,这就是Django在内部所做的事情:

Room.objects.exclude(<some_filter>)Room.objects.filter(~Q(<some_filter>))
总结

以上是内存溢出为你收集整理的django – 在qs.excude()中通过span关系评估同一个对象全部内容,希望文章能够帮你解决django – 在qs.excude()中通过span关系评估同一个对象所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1197200.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存