DRF 如何将 select 特定字段显示在嵌套序列化程序关系中? (没有额外的序列化器)
DRF How to select specific fields to display in a nested serializer relationship? (without additional serializers)
我有一个序列化程序
class CategoryListSerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ["id", "name", "name_en", "about", "parent",]
它用在两个地方:
- 所有类别API:用于查看有关类别的丰富详细信息。
- 所有Posts API: 用于仅知道类别的名称。
在我的 Posts 序列化程序中,我使用了:
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
returns 所有帖子,所有类别详细信息在 CategoryListSerializer
中提及,这是应该的。
问题:
我希望 PostListSerializer
到 return 仅来自相关类别的“名称”字段,而不必定义另一个仅选择“名称”字段的 CategorySimpleSerializer
。 (我仍然需要另一个 API 中的 CategoryListSerializer
字段)
可以吗?
注意:这只是一个例子,我会有更多的用例,我想提前知道我是否必须创建许多自定义的“未来-嵌套”序列化程序,以避免将一些不必要的数据暴露给 API 的 some。如果稍后需要更改模型或 API,似乎有很多冗余更新工作。
如评论中@mtzd所述:
创建通用动态序列化器Class(如DRF Docs here)成功!
我的类别序列化器现在看起来像这样:
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
类别变量中,我只添加了 fields 属性:
categories = CategoryListSerializer(many=True, fields=['name',])
所以现在我可以管理要向我使用的每个视图 API 显示哪些字段,从我可以 modify/update 一次的单一模型序列化程序。
对于您的用例,您应该使用下文所述的序列化程序。
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 CategoryListSerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ["id", "name", "name_en", "about", "parent",]
它用在两个地方:
- 所有类别API:用于查看有关类别的丰富详细信息。
- 所有Posts API: 用于仅知道类别的名称。
在我的 Posts 序列化程序中,我使用了:
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
returns 所有帖子,所有类别详细信息在 CategoryListSerializer
中提及,这是应该的。
问题:
我希望 PostListSerializer
到 return 仅来自相关类别的“名称”字段,而不必定义另一个仅选择“名称”字段的 CategorySimpleSerializer
。 (我仍然需要另一个 API 中的 CategoryListSerializer
字段)
可以吗?
注意:这只是一个例子,我会有更多的用例,我想提前知道我是否必须创建许多自定义的“未来-嵌套”序列化程序,以避免将一些不必要的数据暴露给 API 的 some。如果稍后需要更改模型或 API,似乎有很多冗余更新工作。
如评论中@mtzd所述:
创建通用动态序列化器Class(如DRF Docs here)成功!
我的类别序列化器现在看起来像这样:
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
类别变量中,我只添加了 fields 属性:
categories = CategoryListSerializer(many=True, fields=['name',])
所以现在我可以管理要向我使用的每个视图 API 显示哪些字段,从我可以 modify/update 一次的单一模型序列化程序。
对于您的用例,您应该使用下文所述的序列化程序。
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")