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

时间:2013-08-25 22:35:18

标签: python django django-rest-framework

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

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

但我没有在JSON响应中获得计数。

提前谢谢。

4 个答案:

答案 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;