我正在为QuerySet中的每个项生成聚合:
def get_queryset(self):
from django.db.models import Count
queryset = Book.objects.annotate(Count('authors'))
return queryset
但我没有在JSON响应中获得计数。
提前谢谢。
答案 0 :(得分:52)
接受的解决方案会在返回结果时多次访问数据库。对于每个结果,将对数据库进行count
查询。
问题是关于向序列化程序添加注释,这比对响应中的每个项目执行count
查询更有效。
解决方案:
<强> models.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...
...
<强> serializers.py 强>
class BookSerializer(serializers.ModelSerializer):
authors = serializers.IntegerField()
class Meta:
model = Book
fields = ('id', 'title', 'authors')
<强> views.py 强>
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.annotate(authors=Count('author'))
serializer_class = BookSerializer
...
这将使数据库级别的计数,避免命中数据库以检索每个返回的Book
项目的作者计数。
答案 1 :(得分:20)
从get_queryset返回的查询集提供了将通过序列化程序的事物列表,该序列化程序控制对象的表示方式。尝试在Book序列化程序中添加其他字段,例如:
author_count = serializers.IntegerField(
source='author_set.count',
read_only=True
)
编辑:正如其他人所说,对于返回许多结果的情况,这不是最有效的方法,因为它会为每个实例命中数据库。请查看@José的答案,以获得更有效的解决方案。
答案 2 :(得分:7)
Fiver的解决方案将针对查询集中的每个实例点击数据库,因此如果您有一个大型查询集,他的解决方案将创建大量查询。
我会覆盖Book序列化程序的 to_representation ,它会重复使用 注释 的结果。它看起来像:
class BookSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
return {'id': instance.pk, 'num_authors': instance.authors__count}
class Meta:
model = Book
答案 3 :(得分:0)
所以,如果你做这样的注释
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;