Django REST框架仅限JavaScript的序列化器字段

jutyujz0  于 2023-11-20  发布在  Go
关注(0)|答案(5)|浏览(142)

我有一个Django模型作为请求描述。它是由REST客户端创建的,用于记录任务的当前状态,并记录客户端接收的历史请求。
这个模型有几个字段用于微调和控制请求的任务(比如,目标对象和操作类型)。显然,我希望客户端在创建对象时控制这些字段,而不是之后(一旦任务开始运行,您就不能更改对象)。
我希望有类似于serializers.ReadOnlyField的东西,所以我可以有类似于这样的东西:

class TaskSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    task_id = serializers.ReadOnlyField()
    target_object = serializers.CreateOnlyField()

字符串
但在文档和谷歌上都找不到。

4si2a6ki

4si2a6ki1#

只是为了扩展Wim的答案,这是一种基于传入请求方法选择不同序列化器的方法:

class RequestViewSet(viewsets.ModelViewSet): 
    serializer_class = RequestModelSerializer 
    model = Request 

    def get_serializer_class(self): 
        serializer_class = self.serializer_class 
        if self.request.method == 'POST': 
            serializer_class = SerializerWithoutCertainFields 
        return serializer_class

字符串

eivgtgni

eivgtgni2#

@fabio.sussetto的答案让我走上了正确的道路。我认为我的答案稍微漂亮一点;我没有直接在类上指定序列化器,而是只在get_serializer_class()中指定。此外,我没有根据HTTP类型(即POST)来切换它,而是根据操作update来切换,我认为这更具声明性。

class RequestViewSet(viewsets.ModelViewSet): 
    model = Request 

    def get_serializer_class(self): 
        if self.action == 'update': 
            return serializer_class = SerializerWithoutCertainFields 
        return RequestModelSerializer

字符串

dgjrabp2

dgjrabp23#

这可以通过使用to_internal_value方法用一个串行器来实现

class TaskSerializer(serializers.ModelSerializer):
    # Field settings here

    def to_internal_value(self, data):
        data = super().to_internal_value(data)
        # Remove target_object if serializer is updating object
        if self.instance:
            data.pop('target_object', None)
        return data

    class Meta:
        model = Task
        fields = ('owner', 'task_id', 'target_object')

字符串

r1wp621o

r1wp621o4#

也可以通过required=False的组合来完成,并在更新时删除字段值,如本例所示:

class SectionSerializer(serializers.ModelSerializer):

    # do not require field lesson when updating
    lesson = serializers.PrimaryKeyRelatedField(queryset=Lesson.objects.all(), required=False)

    # do not allow changing the lesson field
    def update(self, instance, validated_data):
        validated_data.pop("lesson", None)
        return super().update(instance, validated_data)

字符串

fafcakar

fafcakar5#

我能找到的最简单和可重用的解决方案是创建一个允许创建但不允许更新的验证器:

class CreateOnlyValidator:
    """
    Prevent a field from being updated.
    """
    requires_context = True

    def __call__(self, value, serializer_field):
        instance = serializer_field.parent.instance

        if instance is not None:
            if value != getattr(instance, serializer_field.source):
                msg = "This field cannot be updated."
                raise exceptions.ValidationError(msg, code="create-only")

            # if the value is the same, no need to update it
            raise fields.SkipField()

        return value

class TaskSerializer(serializers.ModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    task_id = serializers.ReadOnlyField()
    target_object = serializers.PrimaryKeyRelatedField(
        queryset=Request.objects.all()
        validators=[CreateOnlyValidator()],

    )

字符串
将验证逻辑添加到验证器允许在任何字段类型中使用它。

相关问题