django-guardian 如何使对象继承相关对象的权限?

6 投票
2 回答
1684 浏览
提问于 2025-04-18 06:58

我有两个模型:

class ContactGroup(models.Model):
    name = models.CharField(max_length=40)
    class Meta:
        permissions=(('view_group_contacts', 'View contacts from group'))


class Contact(models.Model):
    name = models.CharField(max_length=40)
    group = models.ForeignKey(ContactGroup)
    class Meta:
        permissions=(('view_contact', 'View contact'))        

我该怎么做才能让django guardian在我执行`get_objects_for_user(User, 'appname.view_contact')`时考虑ContactGroup的权限?同时又能保留对单个Contact更改权限的选项?(不是排除,而是当用户没有整个组的权限时,仍然可以给他们查看单个联系人的权限)

2 个回答

2

这个方法看起来很糟糕,它没有考虑到每个对象的变化(如果remove=False,它会把所有的权限重置为ContactGroup的权限)。不过,如果需要的话,可以重新写一下,保留这些变化。我打算把它和“与组同步权限”这个按钮连接起来,这样只有在用户请求的时候才会执行。它的主要优点是可以按照预期与get_objects_for_user一起工作。

def syncPerms(source, remove=False):
if not isinstance(source, ContactGroup):
    return False

contacts= source.client_set.all()
user_perms=get_users_with_perms(source, attach_perms=True)
for contact in contacts:
    for user, perm in user_perms.iteritems():
        if u'view_group_contacts' in perm:
            assign_perm('view_contact', user,client)
        else:
            if remove:
                remove_perm('view_contact', user, client)
2

抱歉,django-guardian 不支持这种行为。至于 has_perm,如果用在查询集上会非常低效,因为我们需要对表中的每一行都执行至少一次查询。

不过,你可以先对 ContactGroup 使用 get_objects_for_user,然后再对 Contact 使用这个方法,并把第二个查询的结果和第一个查询的结果合并起来。大致可以这样做:

contact_groups = get_objects_for_user(user, 'appname.view_group_contacts', ContactGroup)
contacts = get_objects_for_user(user, 'appname.view_contact', Contact)

不过合并这些结果还是有点问题,但总的来说,这是可行的。

撰写回答