在Django的Queryset

时间:2016-09-19 13:52:35

标签: python django django-1.9 django-taggit

拥有以下型号:

class Post(models.Model):
    title = models.CharField(max_length=250)
    tags = TaggableManager()

,数据是:

**post.title**                          **post.tags**
Django By Example                       python,django,web
Who was Django Reinhardt                python,django,
Test-Driven Development with Python     python,web
Python for Data Analysis                python,data         
Learning Python                         python
Programming Python                      python
Automate the Boring Stuff with Python   python

我尝试在下面编码

>>> alist=Post.objects.filter(tags__name__in=["data","python"])
>>> for i in alist.annotate(sam_tags=Count('tags')):
...     print("\n---",i)
...     print("tags of it : ",i.tags.all())
...     print("value of sam_tags : ",i.sam_tags)
... 

--- Django By Example
tags of it :  [<Tag: django>, <Tag: python>, <Tag: web>]
value of sam_tags :  1

--- Who was Django Reinhardt
tags of it :  [<Tag: django>, <Tag: python>]
value of sam_tags :  1

--- Automate the Boring Stuff with Python
tags of it :  [<Tag: python>]
value of sam_tags :  1

--- Test-Driven Development with Python
tags of it :  [<Tag: python>, <Tag: web>]
value of sam_tags :  1

--- Learning Python
tags of it :  [<Tag: python>]
value of sam_tags :  1

--- Python for Data Analysis
tags of it :  [<Tag: data>, <Tag: python>]
value of sam_tags :  2

--- Programming Python
tags of it :  [<Tag: python>]
value of sam_tags :  1
>>> 

为什么slist [0] .sam_tags(post:Django By Example)的值等于1?

在阅读Django的文档之后,我认为(post:Django By Example)的post对象有三个标签[python,django和web]。

https://docs.djangoproject.com/en/1.10/ref/models/querysets/#count

它表示 Count(表达式)返回通过提供的表达式相关的对象数。 所以代码

>>>alist[0].tags.all() 
[<Tag: django>, <Tag: python>, <Tag: web>]

显示alist [0] .tags中有三个标签,

>>> slist=alist.annotate(sam_tags=Count('tags'))
>>> slist[0].tags.all()
[<Tag: django>, <Tag: python>, <Tag: web>]
>>> slist[0].sam_tags
1

但是我得到的值是1,
为什么呢?

我知道Django只计算&#34; python&#34;和&#34;数据&#34;我包含在我的过滤条款中的标签 - 其他标签不计算在内。

&#34; slist [0] .tags.all()&#34;的输出表明slist [0]有三个与自身相关的标签。因为django的文档说Count(表达式)返回通过提供的表达式相关的对象的数量,slist [0] .sam_tags应该是3根据文档,但是django-taggit make slist [0] .sam_tags to是1.

所以我真正想知道的是django-taggit如何让filter子句中的Count(表达式)只计算过滤条件中的标签数。

2 个答案:

答案 0 :(得分:1)

Django只计算您在过滤器子句中包含的pythondata标记 - 其他标记不计算在内。 (请注意,sam_tags为2的唯一示例是标记为datapython的示例。)这可能是意外行为,但如果考虑如何执行基础SQL则有意义。从与您类似的架构中查看此示例:

>>> a = Article.objects.filter(tags__slug__in=['python']).annotate(num_tags=Count('tags'))[0]
>>> a.num_tags
1
>>> a.tags.count()
2

如果我更改filter子句以过滤除标签以外的某些标签,则其行为符合预期:

>>> Article.objects.filter(pk=a.pk).annotate(num_tags=Count('tags'))[0].num_tags
2
>>> Article.objects.filter(pk=a.pk).annotate(num_tags=Count('tags'))[0].tags.count()
2

答案 1 :(得分:1)

通过print(similar_post.query)查询查询是相对直接的 我们可以看到代码只计算了显示该帖子标签的tag_id。

选择“ blog_post”。“ id”,“ blog_post”。“ title”,“ blog_post”。“ slug”,“ blog_post”。“ author_id”,“ blog_post”。“ body”,“ blog_post”。“发布”,  “ blog_post”。“创建”,“ blog_post”。“更新”,“ blog_post”。“状态”,COUNT(“ taggit_taggeditem”。“ tag_id”)AS“ same_tags”来自“ blog_post”

INNER JOIN“ taggit_taggeditem” ON(“ blog_post”。“ id” =“ taggit_taggeditem”。“ object_id” AND(“ taggit_taggeditem”。“ content_type_id” = 7))

在哪里(“ blog_post”。“状态” =已发布

   AND "taggit_taggeditem"."tag_id" IN (SELECT DISTINCT U0."id" FROM "taggit_tag" 
                                                        U0 INNER JOIN "taggit_taggeditem" U1 ON (U0."id" = U1."tag_id") 
                                                        INNER JOIN "django_content_type" U2 ON (U1."content_type_id" = U2."id") 
                                                        WHERE (U2."app_label" = blog AND U2."model" = post AND U1."object_id" = 8)) 

   AND NOT ("blog_post"."id" = 8)) 

GROUP BY“ blog_post”。“ id”,“ blog_post”。“ title”,“ blog_post”。“ slug”,“ blog_post”。“ author_id”,“ blog_post”。“ body”,“ blog_post”。“ publish“,” blog_post“。”创建“,” blog_post“。”更新“,” blog_post“。”状态“

ORDER BY“ same_tags” DESC,“ blog_post”。“发布” DESC LIMIT 4