评估查找已知对象

问题描述:

我沿着这些线路滤波器:评估查找已知对象

class EventManager(models.Manager): 
    def joinable(self, current_time): 
     query = Q(join_time__lte=current_time) & Q(end_time__gte=current_time) 
     return self.filter(query) 

所以,对于一个时间,返回,你可以参加活动。我也想一个can_join方法添加到事件:

class Event(models.Model): 
    def is_joinable(self, current_time): 
     return self.join_time <= current_time & self.end_time >= current_time 

但我想,以避免重复在此逻辑(实际逻辑是一个有点复杂,它可能会发生变化)。 is_joinable有没有方法来评估查询并确定self是否会通过它?或者我可以在其他方法上写两种方法吗?很显然,我可以做类似

query = Q(id=self.id) & joinable_query 
return Event.objects.filter(query).exists() 

但似乎对我已经在我的指尖记录无谓的额外的数据库查询。

您可以使用query expression在数据库上执行该计算,并将结果注释为布尔型字段,然后过滤该字段。

喜欢的东西:

class EventManager(models.Manager): 
    def get_queryset(self): 
     return self.annotate(
      joinable=Case(
       When(start_date__lte=now, end_date__gte=now, then=Value(True)), 
       default=Value(False), 
       output_field=models.BooleanField() 
     )) 

现在你可以在Event.objects.filter(joinable=True)过滤,每个事件对象将永远有一个joinable场与TRUE或FALSE值。 (注意,由于该字段是由数据库计算出来的,如果一个事件在内存中改变了它的可连接状态 - 或者是因为你明确地改变了日期,或者是因为日期到期了 - 可连接的字段不会是在实践中这应该不是什么大问题。)

+0

这是非常有趣的,但是与“现在”紧紧相连。因此,如果在对象的生命期间它改变状态(因为时间流逝,而这些对象被长期存在的芹菜任务使用),它不会更新。我一直在避免让模型自己单独看“现在”,因为它让单元测试变得如此脆弱;这就是为什么我将current_time传递给is_joinable函数的原因。尽管如此,仍然非常有趣。 (无论如何,长寿命的模型对象都是一个问题,因为它们可能会以其他方式在我背后改变。) –

+0

是的,我在我的答案中注意到了这一点。我没有看到有什么替代方法:要么将数据库中的值作为查询的一部分进行计算,要么将其作为Python方法进行计算,或者重复逻辑。 –