Django 组合可变数量的查询集

发布于 2024-11-14 00:12:14 字数 1230 浏览 4 评论 0原文

有没有办法将未知数量的查询集连接到一个列表中?

这是我的模型:

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. items = Item.objects.filter(brands__in=brands)

  2. < p>items = Item.objects.filter(tags__name='80s').filter(tags__name='comedy')

对于第二种查询,用户可以保存搜索(例如“80s喜剧”),并且可以在同时,所以我需要为他们保存的每个搜索创建一个查询。

我最初想尝试构建一个可以处理这两种情况的单个查询(请参阅 Django 将 AND 和 OR 查询与 ManyToMany 字段组合 ),但我现在认为最好的方法是将所有查询合并到一个列表中。

我喜欢@akaihola 在这里的建议: 如何组合 2 个或多个Django 视图中的查询集? 但我不知道如何将 itertools.chain 与可变数量的查询一起使用。

有谁知道实现这一目标的最佳方法?

编辑:忘了提及,我正在寻找的是具有特定品牌或具有所有必需标签的物品。

Is there a way to concatenate a unknown number of querysets into a list?

Here are my 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 have two types of queries that I'm working with:

  1. items = Item.objects.filter(brands__in=brands)

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

With regards to the second type of query, users can save searches (for example "80s comedy"), and can save multiple searches at the same time, so I will need to create a query for each search that they have saved.

I originally wanted to try and construct a single query that will handle both cases (see Django Combining AND and OR Queries with ManyToMany Field ), but I now think the best way to do this would be to combine all queries into a list.

I like what @akaihola suggests here:
How to combine 2 or more querysets in a Django view? but I can't figure out how to use itertools.chain with a variable number of queries.

Does anyone know the best way to accomplish that?

EDIT: Forgot to mention, what I'm looking for are items that have a certain brand OR have all of the required tags.

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

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

发布评论

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

评论(1

软糖 2024-11-21 00:12:14

有点不正统,但你可以使用递归。因此,在您的示例中:

def recursive_search(tags, results_queryset):
    if len(tags) > 0:
        result_qs = result_queryset.filter(tags_name=tags[0])
        if result_queryset.exists():
            return filter_recursion(tags[1:],result_queryset)
        else:
            return None
    return result_queryset

tags = ["comedy", "80s", "action", "thriller"]  # This can be variable
result_queryset = Item.objects.filter(brands__in=brands) # Could be Item.objects.all()
print recursive_search(tags, result_queryset)

因此,您从要搜索的标签列表以及可能符合您条件的所有商品的查询集开始(在本例中,我们从特定品牌的商品列表开始)

然后,您将一一递归地浏览标签列表并缩减查询集。对于每个级别,您将整个查询集重新过滤为仅包含所有提到的标签的项目。

所以:

  • 第一个调用/级别将针对具有标签 favourite 的所有项目,
  • 第二个调用/级别将针对具有标签 favourite 的所有项目,并且loudest
  • 等。

如果过滤器返回的queryset为None,则表示不存在包含所有所需标签的项目,该方法将退出并返回None(即在第一个可能的情况下退出)失败的实例)。此外,应该只对数据库进行一次点击(我认为!)

我已经对此进行了测试,它应该可以工作,所以尝试一下

编辑

来连接从品牌返回的查询集( q1) 和上面使用 itertools (q2) 创建的查询集:

list = []
for item in itertools.chain(q1, q2):
    list.append(item)

编辑 2

这是否无法在一个查询中实现您所需的功能?

# list of tags = ['comedy','80s']
qs = Item.objects.all( Q(brand__iexact="brand name") | Q(tags__name__in=[tag for tag in list_of_tags]) )

Slightly unorthodox, but you could use recursion. So in your example:

def recursive_search(tags, results_queryset):
    if len(tags) > 0:
        result_qs = result_queryset.filter(tags_name=tags[0])
        if result_queryset.exists():
            return filter_recursion(tags[1:],result_queryset)
        else:
            return None
    return result_queryset

tags = ["comedy", "80s", "action", "thriller"]  # This can be variable
result_queryset = Item.objects.filter(brands__in=brands) # Could be Item.objects.all()
print recursive_search(tags, result_queryset)

So you start off with a list of the tags you are searching for, and a queryset of ALL of your items that could possibly fit your criteria (in this case we start with the list of items of a particular brand)

You then recursively go through the list of tags one by one and cut the queryset down. For each level, you re-filter the entire queryset to only those items which have all the mentioned tags.

so:

  • the first call/level would be for all the items that have the tag favourite,
  • the second call/level would be for all the items that have the tags favourite and loudest,
  • etc.

If the queryset returned by the filter is None, it means there are no items that have all the required tags, and the method will quit and return None (i.e. it quits at the first possible instance of failure). Furthermore, there should only be a single hit to the database (I think!)

I've tested this out and it should work, so give it a shot

EDIT

To concatonate the queryset returned from the brands (q1) and the queryset created above using itertools (q2):

list = []
for item in itertools.chain(q1, q2):
    list.append(item)

EDIT 2

does this not accomplish what you need in one query?

# list of tags = ['comedy','80s']
qs = Item.objects.all( Q(brand__iexact="brand name") | Q(tags__name__in=[tag for tag in list_of_tags]) )
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文