I got a model that looks like this:
class Book(models.Model):
author = models.CharField(max_length=100)
chapters = models.IntegerField()
name = models.CharField(max_length=100)
and a "grand child" linked together through a Chapter
model:
class Verse(models.Model):
chapter = models.ForeignKey(Chapter, on_delete=CASCADE)
verse = models.TextField()
verse_number = models.IntegerField()
I wish to get the count of all verses that belongs to a book, and I'm fetching them like this:
Book.objects.annotate(Count('chapters', distinct=True), total_num_verses=Count('chapter__verse', distinct=True))
However, I'm not sure how to get this into my serializer. I was thinking of using a SerializerMethodField
The goal is to get the total_num_verses
as a key/value pair in my json response
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))
I just get 'BookSerializer' object has no attribute 'annotate'
Should I make a @property
method in the Book model class itself?
views.py
is just a plain 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)
An effective way to do that is adding a readonly=True
field in the serializer:
class BookSerializer(serializers.ModelSerializer):
total_verse_count = serializers.IntegerField(read_only=True)
class Meta:
model = Book
fields = ['author', 'chapters', 'name', 'total_verse_count']
In the view, you then pass the annotated queryset to the serializer:
class BookAPIView(APIView):
def get(self, request, format=None):
books = Book.objects.annotate(
total_verse_count=Count('chapter__verse')
)
serializer = BookSerializer(books, many=True)
return Response(serializer.data)