【问题标题】:Dynamically create serializer based on model field value根据模型字段值动态创建序列化程序
【发布时间】:2022-02-11 01:25:08
【问题描述】:

我有一个这样的模型:

class A:
    name = models.CharField()
    group = models.ForeignKey('SomeModel', null=True, blank=True)

当我对此进行序列化时,我希望序列化器根据“组”字段是否为空白而具有不同的格式。当然,这可以通过为不同格式设置不同的序列化程序并在视图层中根据需要调用它们来实现:

class TypeASerializer(serializers.ModelSerializer)

    class Meta:
        model = A
        fields = ('id', 'name')

class TypeBSerializer(serializers.ModelSerializer)

    class Meta:
        model = A
        fields = ('id', 'name', 'group')

但我想在序列化程序层本身中处理它,并为此使用一个序列化程序。这可能吗?

【问题讨论】:

  • 您可以将每个字段声明为 SerializerMethodField 并根据您的条件返回值或None
  • @vishes_shell 最好能写出答案以免混淆。

标签: django django-rest-framework


【解决方案1】:

Serializer.instance 在某些情况下可能是None

并且get_fields() 只被调用一次,因为Serializer.fields 是从 django-rest-framework 3.10 缓存的:https://github.com/encode/django-rest-framework/commit/7232586c7caf66f20f56b36f1c6a9c9648eb94a4

换句话说,当一个序列化器被many=True(在ListModelMixin中,或者作为另一个序列化器的一个字段)用作列表时,列表中所有项的字段由第一个实例确定。

在这种情况下,解决方案是覆盖to_representation()

class TypeASerializer(serializers.ModelSerializer)
    class Meta:
        model = A
        fields = ('id', 'name', 'group')

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        if not instance.group:
            del ret['group']
        return ret

这个解决方案效率有点低,因为所有字段和值都是从super().to_presentation() 获取的,但其中一些又被删除了。你可以考虑完全实现to_representation()而不调用super。

【讨论】:

    【解决方案2】:

    您可以覆盖序列化程序的 get_fields 方法

    class YourSerializer(serializers.ModelSerializer):
       id = serializers.SerializerMethodField()
       name = serializers.SerializerMethodField()
       group = serializers.SerializerMethodField()
    
       class Meta:
          model = A
          fields = ('id', 'name', 'group')
    
       def get_fields(self):
          fields = super().get_fields()
          # delete all the unnecessary fields according to your logic.
          if self.instance.group:  # if this is detials view other wise pass object in context
             del fields['group']
          return fields 
    

    【讨论】:

    • 如何在 get_fields 中使用对象实例中的值?如果您还写了如何删除字段并包含逻辑,那将会更有帮助。
    • 请检查,我提到了一个条件。
    • 是的,但这不是我在问题中所说的条件。此外,您还没有使用我需要知道的对象实例。删除组字段的条件是检查该特定实例的组字段是否为无。你能告诉我怎么做吗?
    • 另外,我认为应该是:fields = super(YourSerializer, self).get_fields()
    • 你可以从视图中传递序列化程序上下文中的对象实例,然后你可以在序列化程序中访问它,或者如果你在序列化程序中传递实例而不是从 self.instance 访问
    【解决方案3】:

    您可以将序列化程序的每个字段声明为SerializerMethodField,如下所示:

    class YourSerializer(serializers.ModelSerializer):
        id = serializers.SerializerMethodField()
        name = serializers.SerializerMethodField()
        group = serializers.SerializerMethodField()
    
        class Meta:
            model = A
            fields = ('id', 'name', 'group')
    
        def id(self, obj):
            if yourcondition(obj.group):
                return obj.id
            return another_value
        ...
    

    【讨论】:

    • 但这不会仍然包含“组”作为字段吗?您能否完成解决方案并包括我在问题中提到的条件?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 2017-08-10
    • 1970-01-01
    相关资源
    最近更新 更多