关于django过滤注释器摸索记录
关于djangoa nnotate中Count('blog', filter=Q(blog__name='小王')), Case(When(blog__name='小王', then=1)) 这些过滤注释器摸索记录。
最近碰到一个需求,用django文档的代码来举例子:
数据表:
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
class Book(models.Model):
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
authors = models.ManyToManyField(Author)
pubdate = models.DateField()
需求:
1.列出所有作者
2.统计每个作者出版的书籍页数,并且书籍的价格是小于10元的数据。
一开始我是这样写的:
Author.objects.fliter(book__price__lt=10).annotate(Sum('book__pages'))
先过滤小于10元书籍,然后再进行统计页数,但是这样写达不到第1点需求。
于是我修改了一下代码:
Author.objects.annotate(Sum('book__pages', filter=Q(book__price__lt=10)))
这是django文档里介绍到的写法
>>> highly_rated = Count('book', filter=Q(book__rating__gte=7))
>>> Author.objects.annotate(num_books=Count('book'), highly_rated_books=highly_rated)
在annotate 统计的时候使用filter=Q()语法来过滤注释器。但是后来我发现,无论我做任何的修改,如filter=Q(age=18),表里并没有age这个字段,仍然可以正常运行,这段代码s直接被django忽略掉。
找了很多资料,有人说django2.0以上的版本才支持,我将django的版本从1.11 升级到了3.1.1后发现,过滤器确实是生效了。
原因锁定,Count(‘book’, filter=Q(book__price__lt=10))) 这种写法是django2.0之后的版本才支持的,但是django文档上并没有找到相关的说明。
但是我的项目环境是运行在1.11版本的,所以需要寻找支持1.11的方法,百度了一下发现Case() When() 这两个方法的组合很适合过滤注释器。
改造一下代码:
Author.objects.annotate(
pags=Sum(
Case(
When(book__price__lt=10, then=F('pages')),
output_field=IntegerField())
)
)
这样写就达到了前面所说的两个需求。
关于Case()这个方法具体的文档资料大家可以百度,这里就不多做介绍了。
希望能给大家一些帮助,如有不对的地方欢迎大家指出。