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

在Django REST Framework中实现角色权限预选(显示名称)并正确处理多对多关系的增改操作

在Django REST Framework中实现角色权限预选(显示名称)并正确处理多对多关系的增改操作

我正在用Django和Django Rest Framework实现基于角色的访问控制(RBAC)。我想通过DRF的可浏览API创建一个带有一组权限的角色,同时需要更新这些权限的功能——包括添加新权限和移除现有权限。在可浏览API中显示角色时,我希望关联的权限是预选状态以便清晰查看,同时还要显示所有其他可用权限方便添加。

我目前的实现

模型代码

这里是我简化后的模型:

class BaseModel(models.Model):
    pkid = models.BigAutoField(primary_key=True, editable=False)
    id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)

    class Meta:
        abstract = True

class Role(BaseModel):
    name = models.CharField(max_length=100)

class Permission(BaseModel):
    name = models.CharField(max_length=100, unique=True)
    description = models.TextField(null=True, blank=True)

class RolePermission(BaseModel):
    role = models.ForeignKey(
        Role, on_delete=models.CASCADE, related_name="role_permissions"
    )
    permission = models.ForeignKey(Permission, on_delete=models.CASCADE)

最初的序列化器

class RoleSerializer(serializers.ModelSerializer):
    permissions = serializers.SlugRelatedField(
        queryset=Permission.objects.all(), many=True, required=False, slug_field="name"
    )
    business = serializers.PrimaryKeyRelatedField(
        queryset=Business.objects.all(), required=False, allow_null=True
    )

    class Meta:
        model = Role
        fields = ("id", "name", "is_default", "permissions", "business")

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        permissions = instance.role_permissions.all().values_list(
            "permission__name", flat=True
        )
        representation["permissions"] = list(permissions)
        return representation

    def to_internal_value(self, data):
        data = data.copy()
        permissions_data = data.pop("permissions", [])
        permissions_qs = Permission.objects.filter(name__in=permissions_data)
        data["permissions"] = [permission.id for permission in permissions_qs]
        return super().to_internal_value(data)

遇到的问题

当我发送更新请求修改权限时,会收到如下错误:

{
    "permissions": [
        "Object with name=[UUID('e4ac49c0-093a-4281-96b0-0846917fc62b')] does not exist."
    ]
}

修改后的序列化器

我重写了序列化器来修复这个错误:

class RoleSerializer(serializers.ModelSerializer):
    permissions = serializers.PrimaryKeyRelatedField(
        queryset=Permission.objects.all(), many=True, required=False
    )
    business = serializers.PrimaryKeyRelatedField(
        queryset=Business.objects.all(), required=False, allow_null=True
    )

    class Meta:
        model = Role
        fields = ("id", "name", "is_default", "permissions", "business")

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        permissions = instance.role_permissions.all().values_list(
            "permission", flat=True
        )
        representation["permissions"] = list(permissions)
        return representation

    def to_internal_value(self, data):
        data = data.copy()
        permissions_data = data.pop("permissions", [])
        internal_value = super().to_internal_value(data)
        internal_value["permissions"] = permissions_data
        return internal_value

但这样修改后,返回的JSON里权限变成了ID而不是名称:

{
    "id": "0b3de100-82ef-4a02-b94e-659cb6dd4314",
    "name": "neweee",
    "is_default": false,
    "business": null,
    "permissions": [
        1,
        2
    ]
}

我的问题

如何在DRF可浏览API中正确地将关联字段(权限)以名称形式预选,同时还能无错误地进行创建/更新操作?

谢谢!

备注:内容来源于stack exchange,提问作者nabroleonx

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:38:02