我有一个序列化器
class CategoryListSerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ["id", "name", "name_en", "about", "parent",]
用在两个地方:
在我的帖子序列化程序中,我使用了:
class PostListSerializer(serializers.ModelSerializer):
categories = CategoryListSerializer(many=True, )
class Meta:
model = Post
fields = ["id", "title", "description", "publish_date", "thumbnail", "owner", "categories", ]
在我的 Post ViewSet 中:
class PostViewSet(ReadOnlyModelViewSet):
queryset = Post.objects.all().filter(is_published=True)
serializer_class = PostListSerializer
这将返回
CategoryListSerializer
中提到的所有类别详细信息的所有帖子,因为它应该是。
问题:
我希望
PostListSerializer
只返回相关类别中的“名称”字段,而不必定义另一个仅选择“名称”字段的CategorySimpleSerializer
。 (我仍然需要另一个 API 中的 CategoryListSerializer
字段)
可以吗?
注意: 这只是一个例子,我会有更多的用例,如果我必须创建许多自定义的“待嵌套”序列化器,我想提前知道,以避免暴露一些不必要的数据一些 API。如果稍后需要更改模型或 API,似乎有很多冗余更新工作。
正如@mtzd 在评论中提到的那样:
创建一个通用的动态序列化程序类(如 DRF 文档中)有效!
My Category Serializer 现在看起来像这样:
class DynamicFieldsCategorySerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super().__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
class CategoryListSerializer(DynamicFieldsCategorySerializer):
class Meta:
model = Category
fields = [ "name", "name_en", "about",]
在
PostListSerializer
类别变量中,我只添加了字段属性:
categories = CategoryListSerializer(many=True, fields=['name',])
所以现在我可以管理向我使用的每个 View API 显示的字段,从我可以修改/更新一次的单一模型序列化程序。
您应该使用下面描述的序列化程序来处理您的用例。
class PostListSerializer(serializers.ModelSerializer):
categories = serializers.SerializerMethodField('get_categories')
class Meta:
model = Post
fields = ["id", "title", "description", "publish_date", "thumbnail", "owner", "categories", ]
def get_categories(self, obj):
return obj.categories.all().values("name")
你还需要优化你的
Post.objects.all().filter(is_published=True)
到 Post.objects.filter(is_published=True).select_related("categories")
class Meta:
read_only_fields = (
"id",
"slug",
)
在您的类别模型中,您可以定义一个返回类别名称的方法,如下所示
class Category(models.Model):
name=models.CharField()
``rest of attributes``
def __str__(self):
return self.name
在您的序列化程序中,如文档中所述stringrelatedfield:
class PostListSerializer(serializers.ModelSerializer):
categories = serializers.StringRelatedField(many=True)
class Meta:
model = Post
fields = ["id", "title", "description", "publish_date", "thumbnail",
"owner", "categories", ]
在 PostViewset 中,因为您只需要只读模式,不需要更多修改,但如果它将用于创建帖子,您应该在 serializer.save() 方法中发送类别 ID,如下所示:
def create(self, request):
serializer = self.get_serializer(data=request.data)
category = Category.objects.get(pk=request.data['category'])
if serializer.is_valid():
serializer.save(category=category)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)