Django 将 AND 和 OR 查询与 ManyToMany 字段相结合

发布于 2024-11-11 16:28:05 字数 1542 浏览 2 评论 0原文

希望有人能帮我解决这个问题。

我试图弄清楚是否可以构建一个查询,该查询允许我同时根据foreignkey字段和ManyToManyField从数据库中检索项目。具有挑战性的部分是它需要过滤多个 ManyToMany 对象。

希望通过一个例子可以使这一点更加清楚。这是我的(简化的)模型:

class Item(models.Model):
    name = models.CharField(max_length=200)
    brand = models.ForeignKey(User, related_name='brand')
    tags = models.ManyToManyField(Tag, blank=True, null=True)
    def __unicode__(self):
        return self.name
    class Meta:
        ordering = ['-id']

class Tag(models.Model):
    name = models.CharField(max_length=64, unique=True)
    def __unicode__(self):
        return self.name

我想构建一个查询,根据两个条件检索项目:

  1. 由用户关注的用户上传的项目(在模型中称为“品牌”)。因此,例如,如果用户关注派拉蒙用户帐户,我会想要品牌 = 派拉蒙的所有项目。

  2. 与已保存搜索中的关键字匹配的项目。例如,用户可以进行并保存以下搜索:“80 年代喜剧”。在这种情况下,我想要标签同时包含“80 年代”和“喜剧”的所有项目。

现在我知道如何独立地为每个构造查询。对于#1,它是:

items = Item.objects.filter(brand=brand)

对于#2(基于文档):

items = Item.objects.filter(tags__name='80s').filter(tags__name='comedy')

我的问题是:是否可以将其构造为单个查询,这样我就不必将每个查询转换为列表,加入它们并删除重复项?

挑战似乎是,当您需要项目的多位字段(在本例中为标签)来匹配多个值时,无法使用 Q 对象来构造查询。以下查询:

items = Item.objects.filter(Q(tags__name='80s') & Q(tags__name='comedy')) 

不起作用。

(参见:https://docs.djangoproject .com/en/dev/topics/db/queries/#spanning-multi-valued-relationships

提前感谢您对此的帮助!

hoping someone can help me out with this.

I'm trying to figure out whether I can construct a query that will allow me to retrieve items from my db based on a ForeignKey field and a ManyToManyField at the same time. The challenging part is that it will need to filter on multiple ManyToMany objects.

An example will hopefully make this clearer. Here are my (simplified) models:

class Item(models.Model):
    name = models.CharField(max_length=200)
    brand = models.ForeignKey(User, related_name='brand')
    tags = models.ManyToManyField(Tag, blank=True, null=True)
    def __unicode__(self):
        return self.name
    class Meta:
        ordering = ['-id']

class Tag(models.Model):
    name = models.CharField(max_length=64, unique=True)
    def __unicode__(self):
        return self.name

I would like to build a query that retrieves items based on two criteria:

  1. Items that were uploaded by users that a user is following (called 'brand' in the model). So for example if a user is following the Paramount user account, I would want all items where brand = Paramount.

  2. Items that match the keywords in saved searches. For example the user could make and save the following search: "80s comedy". In this case I would want all items where the tags include both "80s" and "comedy".

Now I know how to construct the query for each independently. For #1, it's:

items = Item.objects.filter(brand=brand)

And for #2 (based on the docs):

items = Item.objects.filter(tags__name='80s').filter(tags__name='comedy')

My question is: is it possible to construct this as a single query so that I don't have to take the hit of converting each query into a list, joining them, and removing duplicates?

The challenge seems to be that there is no way to use Q objects to construct queries where you need an item's manytomany field (in this case tags) to match multiple values. The following query:

items = Item.objects.filter(Q(tags__name='80s') & Q(tags__name='comedy')) 

does NOT work.

(See: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships)

Thanks in advance for your help on this!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

国际总奸 2024-11-18 16:28:05

经过大量研究,我找不到将其组合到单个查询中的方法,因此我最终将查询集转换为列表并将它们组合起来。

After much research I could not find a way to combine this into a single query, so I ended up converting my QuerySets into lists and combining them.

情归归情 2024-11-18 16:28:05

Django 的过滤器自动 AND。仅当您尝试添加 OR 时才需要 Q 对象。此外,__in 查询过滤器将为您提供很多帮助。

假设用户有多个他们喜欢的品牌,并且您想返回他们喜欢的任何品牌,您应该使用:

`brand__in=brands`

其中 brands 是由 someuser.brands.all()

同样的方法也可用于您的搜索参数:

`tags__name__in=['80s','comedy']`

这将返回标有“80 年代”或“喜剧”标签的内容。如果您需要两者(同时标记为“80 年代”和“喜剧”的内容),则必须在连续的过滤器中传递每一个:

keywords = ['80s','comedy']
for keyword in keywords:
    qs = qs.filter(tags__name=keyword)

PS lated_name 值应始终指定相反的关系。你目前的做法将会出现逻辑问题。例如:

brand = models.ForeignKey(User, related_name='brand')

意味着 somebrand.brand.all() 将实际返回 Item 对象。应该是:

brand = models.ForeignKey(User, related_name='items')

然后,您可以使用 somebrand.items.all() 获取品牌的商品。更有意义。

Django's filters automatically AND. Q objects are only needed if you're trying to add ORs. Also, the __in query filter will help you out alot.

Assuming users have multiple brands they like and you want to return any brand they like, you should use:

`brand__in=brands`

Where brands is the queryset returned by something like someuser.brands.all().

The same can be used for your search parameters:

`tags__name__in=['80s','comedy']`

That will return things tagged with either '80s' or 'comedy'. If you need both (things tagged with both '80s' AND 'comedy'), you'll have to pass each one in a successive filter:

keywords = ['80s','comedy']
for keyword in keywords:
    qs = qs.filter(tags__name=keyword)

P.S. related_name values should always specify the opposite relationship. You're going to have logic problems with the way you're doing it currently. For example:

brand = models.ForeignKey(User, related_name='brand')

Means that somebrand.brand.all() will actually return Item objects. It should be:

brand = models.ForeignKey(User, related_name='items')

Then, you can get a brands's items with somebrand.items.all(). Makes much more sense.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文