Reputation: 419
I have Django Rest API serializers based on 2 models, Book and Chapter
class Book(models.Model):
title = models.TextField(unique=True)
description = models.TextField(blank=True, null=True)
published_at = models.DateTimeField(default=timezone.now, db_index=True)
added_at = models.DateTimeField(auto_now_add=True, db_index=True)
modified_at = models.DateTimeField(auto_now=True, db_index=True)
class Chapter(models.Model):
book = models.ForeignKey(
Book, on_delete=models.CASCADE,
related_name='chapters', db_index=True
)
published_at = models.DateTimeField(default=timezone.now, db_index=True)
added_at = models.DateTimeField(auto_now_add=True, db_index=True)
modified_at = models.DateTimeField(auto_now=True, db_index=True)
In the Book serializer I want 2 custom fields
first_chapter
last_chapter
Each having objects of model Chapter
as you can understand from the field name first and last objects order by published_at
field
The Chapter model has a Foreign Key to Book.
I tried something like below to get the last chapter
class LastChapterField(serializers.RelatedField):
def get_queryset(self):
return core_models.Chapter.objects\
.filter(book=M.OuterRef("pk"))\
.select_related("number")\
.order_by("-published_at")[:1]
But I don't see the last chapter included in my results even though it is explicitly mentioned in fields
of Book Serializer
I want the complete object in returning result and I want to be able to use order by on one of these nested fields (first_chapter or last_chapter) of Chapter
model object.
Upvotes: 2
Views: 124
Reputation: 870
You can do this by using a SerializerMethodField that will retrieve the objects you want and use an other serializer in it:
# serializers.py
from rest_framework import serializers
class ChapterSerializer(serializers.ModelSerializer):
class Meta:
model = Chapter
fields = ('published_at', 'modified_at', 'added_at',)
class BookSerializer(serializers.ModelSerializer):
first_chapter = serializers.SerializerMethodField()
last_chapter = serializers.SerializerMethodField()
def get_first_chapter(self, instance):
return ChapterSerializer(instance.chapters.order_by('published_at').first()).data
def get_last_chapter(self, instance):
return ChapterSerializer(instance.chapters.order_by('published_at').last()).data
class Meta:
model = Book
fields = ('first_chapter', 'last_chapter',
[...] # Add the other fields you want to display here
)
Then you can use your serializer in your views, e.g.:
# views.py
from .serializers import BookSerializer
from .models import Book
from rest_framework.generics import RetrieveAPIView
class BookRetrieveView(RetrieveAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
Upvotes: 1