如何在django-rest-framework查询集响应中添加注释数据?

pan*_*ore 37 python django django-rest-framework

我正在为QuerySet中的每个项生成聚合:

def get_queryset(self):
    from django.db.models import Count
    queryset = Book.objects.annotate(Count('authors'))
    return queryset
Run Code Online (Sandbox Code Playgroud)

但我没有得到JSON响应中的计数.

先感谢您.

Jos*_*iño 58

接受的解决方案将在返回结果时多次访问数据库.对于每个结果,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...
    ...
Run Code Online (Sandbox Code Playgroud)

serializers.py

class BookSerializer(serializers.ModelSerializer):
    authors = serializers.IntegerField()

    class Meta:
        model = Book
        fields = ('id', 'title', 'authors')
Run Code Online (Sandbox Code Playgroud)

views.py

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.annotate(authors=Count('author'))
    serializer_class = BookSerializer
    ...
Run Code Online (Sandbox Code Playgroud)

这将使数据库级别的计数,避免命中数据库以检索每个返回Book项目的作者计数.

  • 我想`serializers.IntegerField()` 需要有`read_only=True`。 (2认同)

Fiv*_*ver 25

从get_queryset返回的查询集提供了将通过序列化程序的事物列表,该序列化程序控制对象的表示方式.尝试在Book序列化程序中添加其他字段,例如:

author_count = serializers.IntegerField(
    source='author_set.count', 
    read_only=True
)
Run Code Online (Sandbox Code Playgroud)

编辑:正如其他人所说的,这不是为返回许多结果的情况添加计数的最有效方法,因为它将为每个实例命中数据库.请查看@José的答案,以获得更有效的解决方案.


Tob*_*ias 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
Run Code Online (Sandbox Code Playgroud)

  • 你能解释一下 - 为什么Fiver的解决方案会产生很多疑问?我认为在执行queryset之后将处理序列化程序字段,这将进行正确的连接/分组? (5认同)