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

Cal*_*eng 8 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字段.

方法#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)
Run Code Online (Sandbox Code Playgroud)

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

这意味着每个StudentClass对象,sc_A,sc_B等等,都不可能包含大量基团.

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

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

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

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

或者我最好采用不同的模型设计......

方法#2

# 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)
Run Code Online (Sandbox Code Playgroud)

显然,这种模型设计使我很容易检查用户对象是否属于特定组织.我需要做的就是找出用户john是否属于TeachingTeam的一部分,maths_teachers检查:

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!"
Run Code Online (Sandbox Code Playgroud)

但是这个模型设计意味着当我向一个组添加用户对象时(回想一下我想使用django guardian的组权限功能),我必须确保该save()调用将用户对象添加到"Maths Teachers"组中在django.contrib.auth.models.Group 成我的自定义TeachingTeam类的"数学教师"对象.这并不觉得很干,更不用说我必须以某种方式确保两个模型的保存调用都在一个单独完成transaction.

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

rew*_*ten 7

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

如果属于特定的StudentClass必须暗示某个自动组(除了授予用户的那些),则将groupsm2m 添加到StudentClass模型,并创建新的身份验证后端(扩展默认后端),这提供了一个自定义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和其他相应方法来添加类似的行为.

(为更清晰的序幕编辑)