强制在 Django 中使用 PUT 请求只能更改某些属性

Posted

技术标签:

【中文标题】强制在 Django 中使用 PUT 请求只能更改某些属性【英文标题】:Enforce that only certain attributes can be changed using a PUT request in Django 【发布时间】:2021-01-20 11:07:14 【问题描述】:

我想这样做,以便用户能够在我的 Django Rest API 中使用 PUT 请求仅更新某些属性。例如,如果我有以下模型并且只希望用户能够更新他们的名字和姓氏,我该怎么做?

models.py:

class User(models.Model):
    email = models.EmailField('email address', unique = True)
    first_name = models.TextField(max_length = 10)
    last_name = models.TextField(max_length = 20)

(注意他们应该不能更改自动设置的“id”字段)

serializers.py:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'email', 'first_name', 'last_name']

views.py:

class SingleUser(APIView):
    def put(self, request, user_id):
        user = User.objects.get(pk = user_id)
        serializer = UserEditSerializer(user, data = request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status = status.HTTP_200_OK)
        return Response(serializer.errors, status = status.HTTP_400_BAD_REQUEST)

强制用户只能更改这些属性的子集的最佳方法是什么?

谢谢,格雷

【问题讨论】:

您可以定义一个序列化程序,它只包含您希望允许用户更改的字段,然后在处理put 请求时使用该序列化程序 【参考方案1】:

您可以在序列化程序上设置只读字段:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'email', 'first_name', 'last_name']
        read_only_fields = ['id', 'email']

确保在 put 函数中将您的序列化程序设置为部分:

serializer = UserEditSerializer(user, data = request.data, partial=True)

您也可以完全省略序列化程序中的字段,这将使用户根本无法使用这些字段。

【讨论】:

【参考方案2】:

创建一个单独的序列化器并使用它

# serializers.py
class UserPutSerializer(serializers.ModelSerializer): # new serializer class
    class Meta:
        model = User
        fields = ['first_name', 'last_name'] # define required fields

#views.py
class SingleUser(APIView):
    def put(self, request, user_id):
        user = User.objects.get(pk=user_id)
        serializer = UserPutSerializer(user, data=request.data) # use new serializer here
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

【讨论】:

Imo,这很快就会变得一团糟。如果您在模型中添加一个字段,现在您需要再更新一个序列化程序。如果您想要 put、post 和 get 请求的不同行为怎么办?在不知不觉中,您为每个模型维护了 3 个不同的序列化程序。 完全有可能创建一个序列化程序,根据您是创建、读取还是更新模型实例,其行为会有所不同。 是的,有可能。如果我的字段要求不是这样,我还将使用单个类,例如,idusername 用于HTTP GET, id, and first_name` 用于 HTTP POST,emaillast_name 用于HTTP 放置。在这些情况下,我们不能依赖单个序列化程序类。 (是的,可以使用它"somehow",但是,我不认为它是 clean 针对每种情况处理不同字段的方法 除此之外,在这种情况下,我会坚持“单一职责原则”。 @NicoGriffioen 它还可以帮助我们非常轻松地“调试” 事情【参考方案3】:

您可以使用序列化程序的属性read_only_fields。

另一种方法是使用"serializer per action"

【讨论】:

以上是关于强制在 Django 中使用 PUT 请求只能更改某些属性的主要内容,如果未能解决你的问题,请参考以下文章

在前端 PUT 请求中返回内部服务器 500 错误 | Django Vue

Django REST framework框架之GET, POST, PUT, PATCH, DELETE等API请求接口设计

Django REST:OPTIONS 请求注册为 PUT

如何在 Django 中通过 PUT 请求处理文件上传?

Django 强制密码过期

尽管字段具有“空白=真”,但 Django EmbeddedModelField 在执行 PUT 请求时说“此字段可能不是空白”