【问题标题】:How to make a field editable=False in DRF如何在 DRF 中使字段可编辑 = False
【发布时间】:2025-12-02 19:55:02
【问题描述】:

我有一个序列化器。我想限制更新字段。我该怎么做?

class ABCSerializer(serializers.ModelSerializer):
    class Meta:
        """Meta."""

        model = ModelA
        fields = ('colA', 'colB', 'colC',)

colA 是创建对象时的必填字段。但是,它不应该被允许更新。我该怎么做??

【问题讨论】:

标签: python django django-rest-framework


【解决方案1】:

您可以使用 Django REST Frameworks field-level validation 通过验证该字段在更新时没有更改,如下所示:

from rest_framework.exceptions import ValidationError

class ABCSerializer(serializers.ModelSerializer):
    colA = serializers.CharField(max_length=100)

    def validate_colA(self, value):
        if self.instance and self.instance.colA != value:
            raise ValidationError("You may not edit colA")
        return value

    class Meta:
        """Meta."""

        model = ModelA
        fields = ('colA', 'colB', 'colC',)

这将检查这是否是更新(通过检查是否在序列化程序上填充了实例),如果是,它将检查您是否对该字段进行了更改,如果有,则会抛出ValidationError。这种方法的好处是您可以保持视图代码与以前相同,并继续在序列化程序中保持验证行为。

【讨论】:

    【解决方案2】:

    您可以覆盖序列化程序的 update 方法以仅更新您想要的字段。

    class ABCSerializer(serializers.ModelSerializer):
        def update(self, instance, validated_data):
            instance.colB = validated_data.get('colB', instance.colB)
            instance.colC = validated_data.get('colC', instance.colC)
            # do nothing to instance.colA
            instance.save()
            return instance
    
        class Meta:
            model = ModelA
            fields = ('colA', 'colB', 'colC',)
    

    或者,如果您有很多字段,并且只想省略更新 colA,您可以像这样编写您的 update 方法:

    def update(self, instance, validated_data):
        validated_data.pop('colA') # validated_data no longer has colA
        return super().update(instance, validated_data)
    

    您可以在此处阅读有关覆盖 update 的更多信息:https://www.django-rest-framework.org/api-guide/serializers/#saving-instances

    【讨论】:

      【解决方案3】:

      听起来您需要为 PUTPOST 方法使用不同的序列化程序。在PUT 方法的序列化程序中,您可以将colA 字段设置为readonly

      class ABCViewSet(ModelViewSet):
          serializer_class = ABCSerializer
      
          def get_serializer_class(self):
              serializer_class = self.serializer_class
              if self.request.method == 'PUT':
                  serializer_class = SerializerWithReadOnlyColA
              return serializer_class
      

      【讨论】:

        【解决方案4】:

        您可以使用read_only_fieldsoption 来做到这一点

        class ABCSerializer(serializers.ModelSerializer):
            class Meta:
                """Meta."""
        
                model = ModelA
                fields = ('colB', 'colC',)
                read_only_fields = ('colA',)
        

        【讨论】:

        • 我希望colA 是创建对象时的必填字段。但是,您的解决方案不会向我提供write 它。