You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django REST API的Serializer中填充creator_id并用于权限控制?

解决Post请求自动填充Creator及权限验证失效问题

问题背景

需要在Post请求中自动填充creator_id,并用于权限验证。此前在views.py中实现了creator字段的ID填充,数据库中creator列已成功写入ID(如"creator": "2"),但权限验证失效,无法删除自己创建的笔记,因此需要将填充逻辑移至serializers.py中实现自动填充。

问题根源

  1. 序列化配置错误:serializers.py中creator字段设置了source="creator.id",但Model里的creator是CharField(存储字符串ID),字符串类型没有id属性,导致序列化逻辑异常,同时权限验证中obj.creator.id的写法会直接报错。
  2. 视图层修改request.data不规范:直接在views.py中修改request.data的方式不符合DRF最佳实践,容易引发序列化验证冲突。

修正方案

方案一:将Creator改为外键关联User(推荐,符合数据库设计规范)

1. 修改models.py

将creator字段从CharField改为关联User模型的外键:

from django.contrib.auth.models import User
import uuid

class Note(models.Model):
    class NoteTypes(models.TextChoices):
        POST = "Post"
        IDEA = "Idea"

    category = models.CharField(
        max_length=4, choices=NoteTypes.choices, default=NoteTypes.POST
    )
    # 关联User模型,on_delete根据业务需求选择CASCADE/PROTECT等
    creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name="notes")
    content = models.TextField(max_length=500)
    created_date = models.DateTimeField(auto_now_add=True)
    updated_date = models.DateTimeField(auto_now=True)
    uuid = models.UUIDField(default=uuid.uuid4, blank=True, primary_key=True)

    def __str__(self):
        return self.content

    class Meta:
        ordering = ["created_date"]

2. 修改serializers.py,实现自动填充

重写create方法,从上下文中获取当前用户并填充到creator字段:

from rest_framework import serializers
from .models import Note

class NoteSerializer(serializers.ModelSerializer):
    # 返回用户ID,若需返回用户名可改用serializers.StringRelatedField()
    creator = serializers.ReadOnlyField(source="creator.id")

    class Meta:
        model = Note
        fields = ["uuid", "category", "creator", "content", "created_date", "updated_date"]

    def create(self, validated_data):
        # 从上下文获取当前请求用户
        user = self.context['request'].user
        validated_data['creator'] = user
        return super().create(validated_data)

3. 修改views.py,移除手动修改逻辑

初始化序列化器时传入context传递request对象,并添加权限类:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Note
from .serializers import NoteSerializer
from .permissions import IsCreatorOrReadOnly

class NotesList(APIView):
    permission_classes = [IsCreatorOrReadOnly]

    def get(self, request):
        notes = Note.objects.all()
        # 传递context给序列化器
        serializer = NoteSerializer(notes, many=True, context={'request': request})
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = NoteSerializer(data=request.data, context={'request': request})
        # 移除手动修改request.data的代码
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

4. 修改permissions.py,修正权限验证逻辑

直接比较用户对象即可:

from rest_framework import permissions

class IsCreatorOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        # 安全方法(GET/HEAD/OPTIONS)允许所有访问
        if request.method in permissions.SAFE_METHODS:
            return True
        # 验证当前用户是否为笔记创建者
        return obj.creator == request.user

方案二:保留Creator为CharField(适合无需关联用户模型的场景)

1. 修改serializers.py

from rest_framework import serializers
from .models import Note

class NoteSerializer(serializers.ModelSerializer):
    creator = serializers.ReadOnlyField()

    class Meta:
        model = Note
        fields = ["uuid", "category", "creator", "content", "created_date", "updated_date"]

    def create(self, validated_data):
        # 将当前用户ID转为字符串存入creator字段
        user_id = str(self.context['request'].user.id)
        validated_data['creator'] = user_id
        return super().create(validated_data)

2. 修改views.py

同方案一,移除手动修改request.data的代码,并传递context。

3. 修改permissions.py

比较字符串形式的用户ID:

from rest_framework import permissions

class IsCreatorOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        # 比较字符串类型的用户ID
        return obj.creator == str(request.user.id)

验证

  1. 执行数据库迁移(方案一需要):python manage.py makemigrations 及 python manage.py migrate
  2. 发送Post请求创建笔记,数据库中creator字段会自动填充当前用户ID
  3. 尝试删除自己创建的笔记,权限验证会正常生效

内容的提问来源于stack exchange,提问作者nataku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 09:15:22