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",]

它用在两个地方:

  1. 所有类别API:用于查看有关类别的丰富详细信息。
  2. 所有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")