ManyToManyField对象上的Django可变数量的过滤器?
Posted
技术标签:
【中文标题】ManyToManyField对象上的Django可变数量的过滤器?【英文标题】:Django variable number of filters on ManyToManyField objects? 【发布时间】:2021-04-19 14:49:17 【问题描述】:我想使用 ManyToManyFeild 指向的对象的两个属性来过滤 ManyToManyField 上的对象。看下面的模型,这是一个经典的用户-项目关系
from django.db import models
class Person(models.Model):
# user = models.OneToOneField(User)
name = models.CharField(max_length=50, blank=False, null=False, default=None, unique=True)
ratings = models.ManyToManyField('Rating',
related_name="persons"
)
class Movie(models.Model):
title = models.CharField(max_length=50, blank=False, null=False, default=None, unique=True)
def __str__(self):
return f"self.title"
class Rating(models.Model):
movie = models.ForeignKey(Movie, models.CASCADE)
value = models.SmallIntegerField(blank=False, null=False, default=None)
def __str__(self):
return f"self.movie:self.value"
所以,我想找到所有对 Movie1 的评分高于特定评分且对 Movie2 评分高于特定评分的所有用户。
我可以用级联过滤器做到这一点:
>>> Person.objects\
.filter(ratings__movie__title='Movie1', ratings__value__gte=5)\
.filter(ratings__movie__title='Movie2', ratings__value__gte=1)\
.all()
[[A<QuerySet [<Person: Person object (1)>]>
但我正在寻找一种方法来过滤任意数量的评级,而不仅仅是 2。
我尝试过使用 Q(在所有情况下都是单个 filter()
),但以下方法不起作用:
>>> Person.objects.filter(
Q(ratings__movie__title='Movie1') & Q(ratings__value__gte=5),\
Q(ratings__movie__title='Movie2') & Q(ratings__value__gte=1)
).all()
<QuerySet []>
更新:
我发现,由于过滤器是惰性的,我可以在一个循环中级联所需数量的过滤器,然后最后调用.all()
,如下所示:
my_filters = [("Movie1", 2), ("Movie2", 3)]
f = Person.objects
for m,r in my_filters:
f = f.filter(ratings__movie__title=m, ratings__value__gte=r)
selected_persons = f.all()
当然,问题仍然存在,该查询的效率如何......所以问题仍然是如何以最佳效率执行此操作。
感谢您的帮助!
【问题讨论】:
可以动态生成一些Q对象。检查这个答案:***.com/a/13076894/4151233 是的,但我很难为我的案例做出正确的 Q 表达式。我最后给出的那个渲染空集,而带有级联过滤器的那个可以正常工作。 【参考方案1】:您想要或 Q 对象是您当前的尝试和它们,这基本上意味着电影标题必须是 Movie1 AND Movie2 并且评级必须是 5 AND 1。 这可能会如您所愿:-
Person.objects.filter(
(Q(ratings__movie__title='Movie1') & Q(ratings__value__gte=5)) | (Q(ratings__movie__title='Movie2') & Q(ratings__value__gte=1))
).all()
【讨论】:
但我认为这意味着我搜索将 >=rating1 给 movie1 或 >=rating2 给 movie2 的用户,但我想搜索同时评论了 Movie1 和 Movie2 并分别在上面给出的用户rating1 和 rating2。 在这种情况下,您使用级联过滤器的方法是我能想到的唯一方法。即使我们只考虑 SQL,我能想到的唯一方法就是对评级表进行多个连接。另外,为什么要在 Person 中设置多对多字段,更好的方法是将 Person 的外键放在 Rating 中。 是的,您对 fereign 密钥的看法是正确的。我想我需要重新考虑模型,因为我概述的搜索案例是我的主要目标......以上是关于ManyToManyField对象上的Django可变数量的过滤器?的主要内容,如果未能解决你的问题,请参考以下文章
Django:ManyToManyField,如果对象不存在则添加它
删除 django 模型中不相关的对象(manytomanyfield)
Django 计数嵌套的 ManyToManyField 对象
Django:在ManyToManyField中获取属于模型对象的第一个项目
如何在 Django RestFramework API 中将 manytomanyfield 作为对象返回
Django 上的用户追随者模型。不能在指定中间模型的 ManyToManyField 上使用 add()。改用accounts.Contact的经理