仅当一个查询中存在关系时才过滤 ManyToManyField
Posted
技术标签:
【中文标题】仅当一个查询中存在关系时才过滤 ManyToManyField【英文标题】:Filter on ManyToManyField only if relations exist in one query 【发布时间】:2012-12-23 12:24:03 【问题描述】:我正在尝试将以下visible
函数中的两个计数查询合并为一个查询。
如果没有关系或存在关系并且某些特定过滤为真,则函数应返回 True。
class OtherModel(models.Model):
starts = models.DateField()
ends = models.DateField()
class MyModel(models.Model):
m2m = models.ManyToManyField('OtherModel', blank=True, )
def visible(self):
# Should always return True if no relations to OtherModel are present.
if self.m2m.exists():
# If relations to OtherModel are present check for starts and ends.
# The reason for the first check is that if there are no relations
# and the below query returns 0 the function will return False
today = datetime.date.today()
return self.m2m.filter(starts__lte=today, ends__gte=today).exists()
return True
编辑:更多代码和 cmets,将 count 替换为存在。
m2m 关系用于日期限制,但如果没有可用的日期限制,则该函数应返回 True(如果完全没有限制,则对象可见,但如果存在限制但不匹配当前日期,则不可见)。
示例代码只是一个简化的示例,我需要这样做并实际返回查询集。
【问题讨论】:
还有什么问题?有什么错误吗? 不,我只是想避免做两个数据库查询 【参考方案1】:不确定您的实际要求是什么,但我认为您想避免 self.m2m.count() > 0
额外检查并希望从函数返回一个布尔值(如果它存在与否),那么您需要 .exists 它将返回 True
如果 QuerySet 包含任何结果,False
如果不包含:
def visible(self):
# return True or False
return self.m2m.filter(some_filter=some_value).exists()
【讨论】:
【参考方案2】:用 Q 和聚合解决它,感谢 Aamir 的存在():
def visible(self):
today = datetime.date.today()
return MyModel.objects.annotate(num_m2m=Count('m2m')).filter(
Q(pk=self.pk) &
(
Q(m2m__starts__lte=today) &
Q(m2m__ends__gte=today) |
Q(num_m2m=0)
)
).exists()
【讨论】:
以上是关于仅当一个查询中存在关系时才过滤 ManyToManyField的主要内容,如果未能解决你的问题,请参考以下文章