python Django 中的联合和相交
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/108193/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Union and Intersect in Django
提问by hamdiakoguz
class Tag(models.Model):
name = models.CharField(maxlength=100)
class Blog(models.Model):
name = models.CharField(maxlength=100)
tags = models.ManyToManyField(Tag)
Simple models just to ask my question.
简单的模型只是为了问我的问题。
I wonder how can i query blogs using tags in two different ways.
我想知道如何以两种不同的方式使用标签查询博客。
- Blog entries that are tagged with "tag1" or "tag2":
Blog.objects.filter(tags_in=[1,2]).distinct()
- Blog objects that are tagged with "tag1" and "tag2" : ?
- Blog objects that are tagged with exactly "tag1" and "tag2" and nothing else : ??
- 标记为“tag1”或“tag2”的博客条目:
Blog.objects.filter(tags_in=[1,2]).distinct()
- 用“tag1”和“tag2”标记的博客对象:?
- 完全用“tag1”和“tag2”标记的博客对象:??
Tag and Blog is just used for an example.
标签和博客仅用作示例。
采纳答案by Clint Ecker
You could use Q objects for #1:
您可以将 Q 对象用于 #1:
# Blogs who have either hockey or django tags.
from django.db.models import Q
Blog.objects.filter(
Q(tags__name__iexact='hockey') | Q(tags__name__iexact='django')
)
Unions and intersections, I believe, are a bit outside the scope of the Django ORM, but its possible to to these. The following examples are from a Django application called called django-taggingthat provides the functionality. Line 346 of models.py:
联合和交叉,我相信,有点超出 Django ORM 的范围,但它可能是这些。以下示例来自一个名为django-tagging的 Django 应用程序,该应用程序提供了该功能。models.py 的第 346 行:
For part two, you're looking for a union of two queries, basically
对于第二部分,您正在寻找两个查询的联合,基本上
def get_union_by_model(self, queryset_or_model, tags):
"""
Create a ``QuerySet`` containing instances of the specified
model associated with *any* of the given list of tags.
"""
tags = get_tag_list(tags)
tag_count = len(tags)
queryset, model = get_queryset_and_model(queryset_or_model)
if not tag_count:
return model._default_manager.none()
model_table = qn(model._meta.db_table)
# This query selects the ids of all objects which have any of
# the given tags.
query = """
SELECT %(model_pk)s
FROM %(model)s, %(tagged_item)s
WHERE %(tagged_item)s.content_type_id = %(content_type_id)s
AND %(tagged_item)s.tag_id IN (%(tag_id_placeholders)s)
AND %(model_pk)s = %(tagged_item)s.object_id
GROUP BY %(model_pk)s""" % {
'model_pk': '%s.%s' % (model_table, qn(model._meta.pk.column)),
'model': model_table,
'tagged_item': qn(self.model._meta.db_table),
'content_type_id': ContentType.objects.get_for_model(model).pk,
'tag_id_placeholders': ','.join(['%s'] * tag_count),
}
cursor = connection.cursor()
cursor.execute(query, [tag.pk for tag in tags])
object_ids = [row[0] for row in cursor.fetchall()]
if len(object_ids) > 0:
return queryset.filter(pk__in=object_ids)
else:
return model._default_manager.none()
For part #3 I believe you're looking for an intersection. See line 307 of models.py
对于第 3 部分,我相信您正在寻找一个交叉点。见models.py的第307行
def get_intersection_by_model(self, queryset_or_model, tags):
"""
Create a ``QuerySet`` containing instances of the specified
model associated with *all* of the given list of tags.
"""
tags = get_tag_list(tags)
tag_count = len(tags)
queryset, model = get_queryset_and_model(queryset_or_model)
if not tag_count:
return model._default_manager.none()
model_table = qn(model._meta.db_table)
# This query selects the ids of all objects which have all the
# given tags.
query = """
SELECT %(model_pk)s
FROM %(model)s, %(tagged_item)s
WHERE %(tagged_item)s.content_type_id = %(content_type_id)s
AND %(tagged_item)s.tag_id IN (%(tag_id_placeholders)s)
AND %(model_pk)s = %(tagged_item)s.object_id
GROUP BY %(model_pk)s
HAVING COUNT(%(model_pk)s) = %(tag_count)s""" % {
'model_pk': '%s.%s' % (model_table, qn(model._meta.pk.column)),
'model': model_table,
'tagged_item': qn(self.model._meta.db_table),
'content_type_id': ContentType.objects.get_for_model(model).pk,
'tag_id_placeholders': ','.join(['%s'] * tag_count),
'tag_count': tag_count,
}
cursor = connection.cursor()
cursor.execute(query, [tag.pk for tag in tags])
object_ids = [row[0] for row in cursor.fetchall()]
if len(object_ids) > 0:
return queryset.filter(pk__in=object_ids)
else:
return model._default_manager.none()
回答by Ycros
I've tested these out with Django 1.0:
我已经用 Django 1.0 测试了这些:
The "or" queries:
“或”查询:
Blog.objects.filter(tags__name__in=['tag1', 'tag2']).distinct()
or you could use the Q class:
或者你可以使用 Q 类:
Blog.objects.filter(Q(tags__name='tag1') | Q(tags__name='tag2')).distinct()
The "and" query:
“和”查询:
Blog.objects.filter(tags__name='tag1').filter(tags__name='tag2')
I'm not sure about the third one, you'll probably need to drop to SQL to do it.
我不确定第三个,您可能需要使用 SQL 来完成它。
回答by zuber
Please don't reinvent the wheel and use django-tagging applicationwhich was made exactly for your use case. It can do all queries you describe, and much more.
请不要重新发明轮子并使用专为您的用例制作的django-tagging 应用程序。它可以执行您描述的所有查询,等等。
If you need to add custom fields to your Tag model, you can also take a look at my branch of django-tagging.
如果您需要向 Tag 模型添加自定义字段,您还可以查看我的 django-tagging 分支。
回答by amit
This will do the trick for you
这将为您解决问题
Blog.objects.filter(tags__name__in=['tag1', 'tag2']).annotate(tag_matches=models.Count(tags)).filter(tag_matches=2)