I have a Post Model contains tags field that have ManyToManyField to categories Model,
when i call REST ListAPIView all post tags returns in pk I have tried to override list function in ListAPIView and map all tags_names for every post but this takes a huge time and destroys the performance
I hope/Believe there something built in for this case
models.py
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=256)
content = RichTextField()
tags = models.ManyToManyField(Categories)
def __str__(self):
return self.title
class Categories(models.Model):
tag_name = models.CharField(max_length=256, unique=True)
def __str__(self):
return self.tag_name
class Meta:
ordering = ('tag_name',)
unique_together = ('tag_name',)
views.py
from .models import Post
from .serializers import NewPostSerializer, PostSerializer
class NewPost(CreateAPIView):
serializer_class = NewPostSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
class PostList(ListAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
serializers.py
class NewPostSerializer(ModelSerializer):
class Meta:
model = Post
fields = ['title', 'content', 'tags']
read_only_fields = ['tags', 'author_id']
when i visit ListApiView link returned results would be like this:
[
{
"id": 30,
"title": "post title test",
"content": "lorem text",
"author": 3,
"tags": [
8, # should be games
3 # should be action
]
}
]
To optimize performance you should use prefetch_related
. This reduces the number of queries to your database to only 1 request to fetch all the related tags for all of your posts.
class PostList(ListAPIView):
queryset = Post.objects.prefetch_related('tags').all()
serializer_class = NewPostSerializer
Now for the serialization of your tags you have to create a new serializer.
class TagSerializer(ModelSerializer):
class Meta:
model = Categories
fields = ['name']
You can then use this serializer in your NewPostSerializer
.
class NewPostSerializer(ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = ['title', 'content', 'tags']
read_only_fields = ['author_id']
The results of this should be "tags": [{"name": "ABC"},{"name": "EFG"}]
.