django守护者,权限和扩展django auth组到'组织'模型

时间:2012-04-23 03:40:01

标签: django django-models rbac

django guardian https://github.com/lukaszb/django-guardian是一个写得很好的对象级权限应用程序;我已经阅读并在各种django项目中使用了相当多的其他django对象级权限应用程序。

在我最近的一个项目中,我决定使用django监护人,但我有一个模型设计问题,涉及两种可能方法的优缺点及其对sql查询的各自影响性能: -

  1. 使用django.contrib.auth.models.Group并将其扩展到我的自定义组织应用的模型;或

  2. 改为使用django.contrib.auth.models.User并为我的组织应用中的每种组织类型创建一个m2m字段。

  3. 方法#1

    # Organisation app's models.py
    
    from django.contrib.auth.models import Group
    
    class StudentClass(models.Model):
        name = models.CharField('Class Name', max_length=255)
        groups = models.ManyToManyField(Group, blank=True)
        size = models.IntegerField('Class Size', blank=True)
    
    class SpecialInterestGroup(models.Model):
        name = models.CharField('Interest Group Name', max_length=255)
        groups = models.ManyToManyField(Group, blank=True)
        description = models.TextField('What our group does!', blank=True)
    
    class TeachingTeam(models.Model):
        name = models.CharField('Teacher Team Name', max_length=255)
        groups = models.ManyToManyField(Group, blank=True)
        specialization = models.TextField('Specialty subject matter', blank=True)
    

    在这种方法中,当用户第一次被添加到组(django组)时,如果该组对象尚未属于该类,则创建组对象并将其分配给这3个类中的一个。它被添加到。

    这意味着每个StudentClass对象sc_Asc_B等可能包含很多组。

    这意味着,为了确定特定用户(比如myuser)是否属于某个特定组织,我必须通过{{1来查询该用户所属的所有组。然后通过groups_myuser_belongto = myuser.groups查询与我感兴趣的组织相关联的所有组,因为我现在有2个需要比较的列表,我可以groups_studentclass = sc_A.groups.all()返回一个新集合,其中可能包含一个或多个相交的组。如果有1个或多个组,则set(groups_myuser_belongto) && set(groups_studentclass)确实是myuser的成员。

    因此,这个模型设计意味着我必须经历很多麻烦(和额外的查询)才能找出用户是否属于某个组织。

    我将m2m用于组的原因是为了使用django guardian提供的组级权限功能。

    这样的模型设计是否实用?

    或者我最好选择不同的模型设计......

    方法#2

    sc_A

    显然,这种模型设计使我很容易检查用户对象是否属于某个特定组织。我需要做的就是找出用户# Organisation app's models.py from django.contrib.auth.models import User class StudentClass(models.Model): name = models.CharField('Class Name', max_length=255) users = models.ManyToManyField(User, blank=True) size = models.IntegerField('Class Size', blank=True) class SpecialInterestGroup(models.Model): name = models.CharField('Interest Group Name', max_length=255) users = models.ManyToManyField(User, blank=True) description = models.TextField('What our group does!', blank=True) class TeachingTeam(models.Model): name = models.CharField('Teacher Team Name', max_length=255) users = models.ManyToManyField(User, blank=True) specialization = models.TextField('Specialty subject matter', blank=True) 是否属于TeachingTeam john的一部分是检查:

    maths_teachers

    但是这个模型设计暗示的是当我将一个用户对象添加到一个组时(回想一下我想使用django guardian的组权限功能),我必须确保{{ 1}}调用将用户对象添加到user = User.objects.get(username='john') maths_teachers = TeachingTeam.objects.get(name='Maths teachers') if user in maths_teachers.users.all(): print "Yes, this user is in the Maths teachers organization!" AND 中的“数学教师”组中,并添加到我的自定义save()班级的“数学教师”对象中。这并不觉得很干,更不用说我必须以某种方式确保两个模型中的保存调用都在一个django.contrib.auth.models.Group中完成。

    根据这个用例/要求,有没有更好的方法来设计我的模型 - 使用django组并提供一种方法来“扩展”django的本机组功能(几乎就像我们使用“用户配置文件”扩展django的用户模型一样应用程序“)?

2 个答案:

答案 0 :(得分:7)

我对此的看法(长期开发django应用程序)是你应该坚持自然的方法(所以StudentClass有用户而不是群组)。这里“自然”意味着它对应于所涉及对象的实际语义。

如果属于特定的StudentClass必须暗示某个自动组(除了授予用户的那些),请向StudentClass模型添加groups m2m,并创建新的身份验证后端(扩展默认后端) ,它提供自定义get_all_permissions(self, user_obj, obj=None)方法。它将被https://github.com/django/django/blob/master/django/contrib/auth/models.py#L201

所吸引

在此方法中查询与用户所属的任何组织关联的任何组。而且您不需要执行1 + N个查询,正确使用ORM将同时导航到两个*到多个。

https://github.com/django/django/blob/master/django/contrib/auth/backends.py#L37中的当前ModelBackend方法查询get_group_permissions(user_obj)并将它们添加到用户分配的权限中。您可以通过添加(缓存)get_student_class_permission和其他相应的方法来添加类似的行为。

(为更清晰的序幕编辑)

答案 1 :(得分:0)

Obs:还有另一种方法是使用generic relationships,在这种方法中,你可以让User模型实例通过contenttypes框架指向它的资源。有nice question here on SE解释这种方法。

关于绩效:有一些线索表明,使用JOIN的单个选择比许多简单选择(123)便宜。在这种情况下,选择2会更好。

关于可用性:第一种方法难以解释,难以理解。恕我直言不。 2.或尝试一般关系。