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

Django中如何基于模型实例字段动态生成自定义权限

结论

该需求完全可以实现,你遇到报错的核心原因是用错了权限的定义位置。


问题原因

Meta类中的permissions属性是模型类级别的配置,Django会在项目启动、加载模型定义的阶段就解析该配置,此时还没有任何Institute类的实例对象,self指向的实例根本不存在,自然会报NameError。permissions原本的设计是用来定义整个模型通用的全局固定权限,不支持动态绑定实例字段值。


实现方案

和你动态创建用户组的逻辑一致,把动态权限的创建逻辑放到实例的save方法中即可,此时实例已经完成保存,可以正常获取self.name等字段值,你需要调用Django原生的Permission和ContentType模型来手动创建权限。


完整代码示例
from django.contrib.auth.models import Group, Permission, ContentType
from django.db import models
from django.db.models import SET_NULL
# 提前导入你的Address模型

class Institute(models.Model):
    CATEGORY=(
        ('play', 'play'),
        ('High school', 'High school'),
        ('College', 'College'),
 
    )
    eiin = models.CharField(max_length=50, blank=True, null= True)  
    name = models.CharField(max_length=100)
    address = models.ForeignKey(Address, on_delete=SET_NULL, blank=True, null=True)
    category = models.CharField(max_length=100, choices=CATEGORY) 

    def save(self, *args, **kwargs):
        # 先判断是否为新建实例、name字段是否修改,避免重复操作
        is_new = self._state.adding
        old_name = None
        if not is_new:
            old_name = Institute.objects.get(pk=self.pk).name
        super().save(*args, **kwargs)
        
        # 动态创建/更新用户组
        group_suffixes = ["_students", "_teachers", "_controller", "_employees", "_guardians"]
        if is_new:
            # 新建实例直接创建对应组
            for suffix in group_suffixes:
                Group.objects.create(name=f"{self.name}{suffix}")
        elif old_name != self.name:
            # name修改时同步更新所有关联组的名称
            for suffix in group_suffixes:
                Group.objects.filter(name=f"{old_name}{suffix}").update(name=f"{self.name}{suffix}")
        
        # 动态创建/更新自定义权限
        # 获取当前模型的ContentType,用于绑定权限归属
        ct = ContentType.objects.get_for_model(Institute)
        # 定义权限规则:(codename后缀, 权限展示名称)
        permission_rules = [
            ("_can_edit_address", "can edit address of institute"),
            ("_can_add_eiin", "can add eiin of institute")
        ]
        for codename_suffix, perm_name in permission_rules:
            full_codename = f"{self.name}{codename_suffix}"
            # 不存在才创建,避免重复生成权限
            perm, _ = Permission.objects.get_or_create(
                codename=full_codename,
                content_type=ct,
                defaults={"name": perm_name}
            )
            # 可按需把权限分配给对应角色组,比如给管理员组分配编辑权限
            controller_group = Group.objects.get(name=f"{self.name}_controller")
            controller_group.permissions.add(perm)
        
        # name修改时同步更新旧权限的codename
        if old_name and old_name != self.name:
            for codename_suffix, _ in permission_rules:
                old_codename = f"{old_name}{codename_suffix}"
                Permission.objects.filter(codename=old_codename, content_type=ct).update(
                    codename=f"{self.name}{codename_suffix}"
                )

    # 删掉原来Meta里的permissions配置即可
    class Meta:
        pass

权限校验方式

后续要判断用户是否持有某个学院的对应权限,直接用以下代码即可:

# 示例:判断当前用户是否可以修改xx学院的地址
user.has_perm(f"{institute_instance.name}_can_edit_address")

补充说明

如果需要删除学院实例时同步清理对应的用户组和权限,可重写delete方法,批量删除关联的Group和Permission对象即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 04:15:03