如何使字段在Django REST框架中的创建时可编辑,在更新时只读

时间:2018-11-13 21:25:31

标签: django django-rest-framework

我想实现一种Django模型的常量字段。我希望在创建模型实例(通过REST框架API)时设置该字段,但是在更新时必须禁止更改该字段。在Django本身或REST框架序列化器选项中,是否有一种优雅的方法?

3 个答案:

答案 0 :(得分:2)

覆盖序列化程序中的更新方法并删除字段:

class MySerializer(serializers.ModelSerializer):        
    def update(self, instance, validated_data):
        validated_data.pop('myfield', None)  # prevent myfield from being updated
        return super().update(instance, validated_data)

答案 1 :(得分:1)

上述两种解决方案都有效,但创建可扩展方法来控制任何 CRUD 操作的修改权限的好方法如下:

  1. 创建一个基本的序列化器类:BaseSerializer
  2. 在所有序列化程序类中从此类继承

基本序列化器类中的控件:

class BaseSerializer(DynamicFieldsSerializer):
    # This overrides a built-in base class method
    def get_extra_kwargs(self):
        """Add additional constraints between CRUD methods to
        any particular field

        NB: Use the same extra_kwags dict object in all method calls
        - important to make changes on central object
        """
        extra_kwargs_for_edit = super().get_extra_kwargs()
        
        # Example of making uuid only editable on create, not update 
        self.add_create_only_constraint_to_field("uuid", extra_kwargs_for_edit)
        return extra_kwargs_for_edit

    def add_create_only_constraint_to_field(self, key: str, extra_kwargs: dict) -> dict:
        """Ensures key is only writable on create, not update"""
        action = self.context["view"].action
        if action in ["create"]:
            kwargs = extra_kwargs.get(key, {})
            kwargs["read_only"] = False
            extra_kwargs[key] = kwargs
        elif action in ["update", "partial_update"]:
            kwargs = extra_kwargs.get(key, {})
            kwargs["read_only"] = True
            extra_kwargs[key] = kwargs

     # You could add other constraints to CRUD operations here
     # def another_field_constrained_by_crud_method(self, key: str, extra_kwargs: dict) -> dict:

class SomeModelSerializer(BaseSerializer):
    # Your serializer logic here
    pass

感谢 Nicholas Coles 的回答!

答案 2 :(得分:0)

将序列化程序的 __init__() 方法替换为,

class MySerializer(serializers.ModelSerializer):
    myfield = serializers.CharField()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.context['view'].action == 'create':
            self.fields['myfield'].write_only = True