DRF ListAPIView return manytomany 值名称而不是 pk
DRF ListAPIView return manytomany value names instead of pk
我有一个 Post 模型包含标签字段,该字段具有 ManyToManyField 类别模型,
当我调用 REST ListAPIView all post tags returns in pk
我试图覆盖 ListAPIView 中的列表函数并为每个 post 映射所有 tags_names
但这会花费大量时间并破坏性能
我 hope/Believe 为这种情况内置了一些东西
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']
当我访问 ListApiView link 时返回的结果是这样的:
[
{
"id": 30,
"title": "post title test",
"content": "lorem text",
"author": 3,
"tags": [
8, # should be games
3 # should be action
]
}
]
要优化性能,您应该使用 prefetch_related
。这将对您的数据库的查询数量减少到只有 1 个请求来获取您所有帖子的所有相关标签。
class PostList(ListAPIView):
queryset = Post.objects.prefetch_related('tags').all()
serializer_class = NewPostSerializer
现在要对标签进行序列化,您必须创建一个新的序列化程序。
class TagSerializer(ModelSerializer):
class Meta:
model = Categories
fields = ['name']
然后您可以在 NewPostSerializer
.
中使用此序列化程序
class NewPostSerializer(ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = ['title', 'content', 'tags']
read_only_fields = ['author_id']
这个结果应该是"tags": [{"name": "ABC"},{"name": "EFG"}]
。
您可以简单地使用 SlugRelatedField,这将 return 名称列表而不是 pks 列表
from rest_framework import serializers
class NewPostSerializer(ModelSerializer):
tags = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='tag_name'
)
class Meta:
model = Post
fields = ['title', 'content', 'tags']
read_only_fields = ['author_id']
我有一个 Post 模型包含标签字段,该字段具有 ManyToManyField 类别模型,
当我调用 REST ListAPIView all post tags returns in pk 我试图覆盖 ListAPIView 中的列表函数并为每个 post 映射所有 tags_names 但这会花费大量时间并破坏性能
我 hope/Believe 为这种情况内置了一些东西
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']
当我访问 ListApiView link 时返回的结果是这样的:
[
{
"id": 30,
"title": "post title test",
"content": "lorem text",
"author": 3,
"tags": [
8, # should be games
3 # should be action
]
}
]
要优化性能,您应该使用 prefetch_related
。这将对您的数据库的查询数量减少到只有 1 个请求来获取您所有帖子的所有相关标签。
class PostList(ListAPIView):
queryset = Post.objects.prefetch_related('tags').all()
serializer_class = NewPostSerializer
现在要对标签进行序列化,您必须创建一个新的序列化程序。
class TagSerializer(ModelSerializer):
class Meta:
model = Categories
fields = ['name']
然后您可以在 NewPostSerializer
.
class NewPostSerializer(ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
class Meta:
model = Post
fields = ['title', 'content', 'tags']
read_only_fields = ['author_id']
这个结果应该是"tags": [{"name": "ABC"},{"name": "EFG"}]
。
您可以简单地使用 SlugRelatedField,这将 return 名称列表而不是 pks 列表
from rest_framework import serializers
class NewPostSerializer(ModelSerializer):
tags = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='tag_name'
)
class Meta:
model = Post
fields = ['title', 'content', 'tags']
read_only_fields = ['author_id']