我正在为 QuerySet 中的每个项目生成聚合:
def get_queryset(self):
from django.db.models import Count
queryset = Book.objects.annotate(Count('authors'))
return queryset
但我没有得到 JSON 响应中的计数。
先感谢您。
我正在为 QuerySet 中的每个项目生成聚合:
def get_queryset(self):
from django.db.models import Count
queryset = Book.objects.annotate(Count('authors'))
return queryset
但我没有得到 JSON 响应中的计数。
先感谢您。
接受的解决方案将在返回结果时多次访问数据库。对于每个结果,count
将对数据库进行查询。
count
问题是关于向序列化程序添加注释,这比对响应中的每个项目进行查询更有效。
一个解决方案:
模型.py
class Author(models.Model):
name = models.CharField(...)
other_stuff = models...
...
class Book(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(...)
publication_year = models...
...
序列化程序.py
class BookSerializer(serializers.ModelSerializer):
authors = serializers.IntegerField()
class Meta:
model = Book
fields = ('id', 'title', 'authors')
视图.py
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.annotate(authors=Count('author'))
serializer_class = BookSerializer
...
这将在数据库级别进行计数,避免访问数据库以检索每个返回Book
项目的作者计数。
从 get_queryset 返回的查询集提供将通过序列化程序的事物列表,序列化程序控制对象的表示方式。尝试在您的 Book 序列化程序中添加一个附加字段,例如:
author_count = serializers.IntegerField(
source='author_set.count',
read_only=True
)
编辑:正如其他人所说,这不是为返回许多结果的情况添加计数的最有效方法,因为它会针对每个实例访问数据库。请参阅@José 的答案以获得更有效的解决方案。
Fiver 的解决方案将为查询集中的每个实例命中数据库,因此如果您有一个大型查询集,他的解决方案将创建大量查询。
我会覆盖您的 Book 序列化程序的to_representation ,它会重用annotation的结果。它看起来像:
class BookSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
return {'id': instance.pk, 'num_authors': instance.authors__count}
class Meta:
model = Book
所以,如果你做一个像这样的注释
Model.objects.annotate(
some_new_col=Case(
When(some_field=some_value, then=Value(something)),
# etc...
default=Value(something_default),
output_field=SomeTypeOfField(),
)
).filter()#etccc
并且解释器抛出一个something
不是相关模型字段的错误serializer
,有一个解决方法。这不好,但如果你添加一个方法some_new_col
,它会识别上面查询中的值。以下将做得很好。
def some_new_col(self):
pass;