在 json 响应中添加注释值(django rest)?

Add annotated value in json response (django rest)?

我得到了一个看起来像这样的模型:

class Book(models.Model):
    author = models.CharField(max_length=100)
    chapters = models.IntegerField()
    name = models.CharField(max_length=100)

和一个通过 Chapter 模型联系在一起的“孙子”:

class Verse(models.Model):
    chapter = models.ForeignKey(Chapter, on_delete=CASCADE)
    verse = models.TextField()
    verse_number = models.IntegerField()

我希望得到属于一本书的所有经文的计数,我正在这样获取它们:

Book.objects.annotate(Count('chapters', distinct=True), total_num_verses=Count('chapter__verse', distinct=True))

但是,我不确定如何将它放入我的序列化程序中。我正在考虑使用 SerializerMethodField 目标是在我的 json 响应

中将 total_num_verses 作为 key/value 对
class BookSerializer(serializers.ModelSerializer):
    total_verse_count = serializers.SerializerMethodField()

    class Meta:
        model = Book
        fields = "__all__"

    # this doesn't work..
    def get_total_verse_count(self, obj):
        print(obj.get_verses)
        return self.annotate(Count('chapters', distinct=True), total_num_verses=Count('chapter__verse', distinct=True))

我刚刚得到'BookSerializer' object has no attribute 'annotate'

我应该在 Book 模型 class 本身中创建一个 @property 方法吗?

views.py 只是一个普通的 APIView

class BookAPIView(APIView):
    """
    List all books
    """

    def get(self, request, format=None):
        books = Book.objects.all()
        serializer = BookSerializer(books, many=True)
        return Response(serializer.data)

一种有效的方法是在序列化程序中添加一个 readonly=True 字段:

class BookSerializer(serializers.ModelSerializer):
    <strong>total_verse_count</strong> = serializers.IntegerField(read_only=True)

    class Meta:
        model = Book
        fields = ['author', 'chapters', 'name', <strong>'total_verse_count'</strong>]

在视图中,然后将带注释的查询集传递给序列化程序:

class BookAPIView(APIView):

    def get(self, request, format=None):
        books = Book.objects.annotate(
            <strong>total_verse_count=Count('chapter__verse')</strong>
        )
        serializer = BookSerializer(books, many=True)
        return Response(serializer.data)