使用Django和django-guardian对象权限每个对象的组

13

我目前正在创建一个结构,其中有员工属于一家公司。在这个公司中,我需要能够创建几个组。如果您愿意,可以分配更少的权限给较低的等级,更多的权限给较高的等级。

我想采用对象级权限,并发现django-guardian项目正好提供了我所需的功能。它与本机用户和组对象一起使用,因此我现在正在尝试找到一种实现本机组对象在公司对象中的方法。

我面临的问题是组中的名称是唯一的。因此,如果两个公司添加相同的组,将会出现错误。

我找到了一种可行的实现方式,但对我来说似乎有些“hacky”。在我的公司中,我声明了一个引用Group的group变量:

class Company(models.Model):
    ...
    groups = models.ManyToManyField(Group, through='CompanyRole')

CompanyRole基本上包含组名和公司与组的引用。

class CompanyRole(models.Model):
    group = models.ForeignKey(Group)
    company = models.ForeignKey(Company)
    real_name = models.CharField(max_length=60, verbose_name=_('Real name'))

    objects = CompanyGroupManager()

我创建了一个自定义管理器,其中包含一个方便的方法来添加一个新的“公司组”

class CompanyGroupManager(models.Manager):
    def create_group(self, company, group_name):
        un_group_name = str(company.id) + '#' + group_name
        group = Group.objects.create(name=un_group_name)
        company_group = self.model(
            real_name=group_name, 
            company=company, 
            group=group
        )

        company_group.save(using=self._db)
        return company_group

这里是我不太舒服的部分。为了解决Group模型中唯一名称的问题,我使用了公司id、一个哈希标志和实际的组名的组合,以避免冲突。

现在我的问题是:在我的情况下有更好的方法吗?我有所遗漏,还是这是实现我所需的好方法?


你能否在公司模型中使用硬编码的自定义权限而不是组? - Fiver
基本上我想做的是,在公司中,您应该能够创建部门并为其分配全局权限和对象权限。假设您有一个名为初级程序员的部门,我希望能够在某些项目上给予他们完全的权限,但在全局范围内仅给予他们对其他创建的项目非常少的权限。现在这是可能的,但我的解决方案似乎相当笨拙。您所说的硬编码自定义权限是什么意思? - Jeffrey Vandenborne
1
嗨杰弗里,我的意思是使用“权限”元属性来定义您自己的权限,以便您可以进行检查。您提到了几个其他模型,如项目和部门,在您发布的代码中不存在,因此我对您的模型结构有些不清楚。但是,我认为我知道您想要实现什么。我会提供一个我过去使用过的设置答案。您能否提供一份您想为用户拥有哪些许可/角色的示例列表? - Fiver
1个回答

3

很遗憾,无法绕过唯一要求,因为该字段用作id:

https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.Field.unique

您有以下选项:

1)模拟模型。

您可以创建一个没有唯一要求的新组模型。缺点在于,您需要在所有位置使用它,因此如果需要更新第三方应用程序,则可能不值得一试。

2)使名称唯一。(就像您所做的那样)

确保记录您的约定,以便所有未来的开发人员都知道他们正在查看什么。例如,“公司名称”#“组名称”可能比id更直观。如果哈希可能出现在两者中的任何一个中,则使用更确定的分隔符(“__”是在django中连接相关概念的相对常见的方法,我可能会选择这个)。

我建议您添加以下内容,以便轻松访问名称。

def get_name(self):
    # Explain how you get the group name from your uniqueified name
    return self.name.split('#')[1] 

Group.add_to_class('get_name', get_name)

当你在应用程序中访问你的群组名称时,只需要执行以下操作:
my_group.get_name()

您可能还希望在重写save()方法时将生成唯一名称的步骤放入其中。这样可以更好地区分模型和视图...


这正是我最终也采取的方法。 :) 但是,我发现这种方法的缺点是:例如,您有一个模型:MyModel。 具有权限:view_mymodel,change_mymodel,add_mymodel,delete_mymodel。 对于查看、更改和删除权限,您可以将这些权限添加到对象中并检查权限(user.has_perm('view_mymodel',obj))。但是对于添加操作,您无法使用user.has_perm('add_mymodel')。 如果用户在一个组织中具有添加权限并且在另一个组织中用户没有该权限的组,则怎么办? - gabn88

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接