django 如何选择特定字段以显示在嵌套的序列化程序关系中?(无附加序列化器)

dxpyg8gm  于 2023-05-08  发布在  Go
关注(0)|答案(4)|浏览(114)

我有一个序列化程序

class CategoryListSerializer(serializers.ModelSerializer):
class Meta:
    model = Category
    fields = ["id", "name", "name_en", "about", "parent",]

它用于两个位置:
1.所有类别API:用于查看有关类别的详细信息。
1.所有帖子API:以前只知道类别的名称。
在我的Posts Serializer中,我使用了:

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只返回相关Categories中的“name”字段,而不必定义另一个只选择“name”字段的CategorySimpleSerializer。(我仍然需要另一个API中的CategoryListSerializer字段)
有可能吗?

**注意:**这只是一个例子,我会有更多的用例,我想提前知道我是否需要创建许多自定义的“待嵌套”序列化器,以避免将一些不必要的数据暴露给 * 一些 * 的API。如果模型或API以后需要更改,那么看起来会有很多冗余的更新工作。

yvfmudvl

yvfmudvl1#

正如@mtzd在评论中提到的:
创建一个通用的动态序列化器类(如在DRF文档这里)工作!
我的分类序列化器现在看起来像这样:

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变量中,我只添加了fields属性:

categories = CategoryListSerializer(many=True, fields=['name',])

因此,现在我可以管理要向我使用的每个View API显示哪些字段,从我可以修改/更新一次的单一模型序列化程序。

bvn4nwqk

bvn4nwqk2#

对于您的用例,您应该使用如下所述的序列化程序。

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")

idfiyjo8

idfiyjo83#

class Meta:
    read_only_fields = (
        "id",
        "slug",
    )
qvtsj1bj

qvtsj1bj4#

在类别模型中,可以定义一个方法,该方法返回类别名称,如下所示

class Category(models.Model):
     name=models.CharField()
     ``rest of attributes``
     def __str__(self):
       return self.name

如docs stringrelatedfield中所述,在序列化器中:

class PostListSerializer(serializers.ModelSerializer):
  categories = serializers.StringRelatedField(many=True)

  class Meta:
     model = Post
     fields = ["id", "title", "description", "publish_date", "thumbnail", 
              "owner", "categories", ]

在PostViewset中,因为你只需要只读模式,所以不需要更多的修改,但是如果它将用于创建帖子,你应该在www.example.com()方法中发送类别IDserializer.save,如下所示:

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)

相关问题