在Django中,如何检查用户是否属于某个组?

195

我在Django的管理网站中创建了一个自定义组。

在我的代码中,我想要检查一个用户是否在这个组中。我该怎么做?

13个回答

273

您的User对象通过ManyToMany关系与Group对象相互关联。

因此,您可以将filter方法应用于user.groups

因此,要检查给定的用户是否属于某个组(例如“成员”),请执行以下操作:

def is_member(user):
    return user.groups.filter(name='Member').exists()
如果您想检查给定用户是否属于多个给定组,请使用__in运算符,例如:
def is_in_multiple_groups(user):
    return user.groups.filter(name__in=['group1', 'group2']).exists()
请注意,这些函数可以与@user_passes_test装饰器一起使用来管理对视图的访问权限:
from django.contrib.auth.decorators import login_required, user_passes_test

@login_required
@user_passes_test(is_member) # or @user_passes_test(is_in_multiple_groups)
def myview(request):
    # Do your processing

对于基于类的视图,您可以使用UserPassesTestMixintest_func方法:

from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin

class MyView(LoginRequiredMixin, UserPassesTestMixin, View):

    login_url = '/login/'
    redirect_field_name = 'redirect_to'

    def test_func(self):
        return is_member(self.request.user)

希望这有所帮助


4
我对Django的数据库访问机制不是很清楚,但这种方法似乎比其他一些建议更高效,比如获取组中的所有用户并执行标准的Python user in groups(或反过来)。 - brianmearns
1
你不需要在结尾添加.exists()来返回一个布尔值吗?否则,is_member()is_in_multiple_groups()将返回一个QuerySet,这可能无法得到所需的结果。 - Michael Bates
4
根据 Django 文档,使用 exists() 更快,因为它不评估 queryset:https://docs.djangoproject.com/en/dev/ref/models/querysets/#exists - Charlesthk
7
您可能希望超级用户通过测试(而无需查询数据库):def is_member(user): return user.is_superuser or user.groups.filter(...) - Dave
1
@DavidRhoden 你可以在你的应用程序中创建一个名为functions.py的页面,并将其添加到其中,然后在views.py或任何你要使用它的Python文件中,如果它在该应用程序中,则只需从顶部导入它,如此from .functions import is_member。如果你从另一个应用程序导入它,则是from {thatAppName}.functions import is_member,其中{thatAppName}是你的应用程序名称,例如如果你将其命名为app1,则是from app1.functions import is_member - AnonymousUser
显示剩余7条评论

144
你可以通过User上的groups属性轻松访问组。
from django.contrib.auth.models import User, Group

group = Group(name = "Editor")
group.save()                    # save this new group for this example
user = User.objects.get(pk = 1) # assuming, there is one initial user 
user.groups.add(group)          # user is now in the "Editor" group

那么user.groups.all()将返回[<Group: Editor>]

或者,更直接地,您可以通过以下方式检查用户是否在组中:

if django_user.groups.filter(name = groupname).exists():

    ...

请注意,groupname也可以是实际的Django组对象。


116
实际检查会是 if user.groups.filter(name=group_name).count(): # do something - Maccesch
149
使用.exists()代替.count()。 - Lie Ryan
3
这个问题是关于查询用户模型所属的组,而不是如何实例化它们的... -.- - Jcc.Sanabria

20

如果你不需要在站点上使用用户实例(就像我一样),你可以这样做:

User.objects.filter(pk=userId, groups__name='Editor').exists()
这将仅产生一个数据库请求并返回布尔值。

16
如果您需要获取某个用户组中的用户列表,可以使用以下方法:
from django.contrib.auth.models import Group
users_in_group = Group.objects.get(name="group name").user_set.all()

然后检查

 if user in users_in_group:
     # do something

检查用户是否在组中。


更新 2023

回顾这个解决方案十年后,我非常确定我不想再像这样获取整个用户列表。在大规模情况下,这将是一个问题。你只想在非常特定的用例中获取用户列表,并确保用户列表将保持较小,或者仅在使用Django shell时使用。


7
对于用户量较大的网站而言,这种方法无法良好扩展,因为每次运行它都会将用户表的大量子集加载到内存中。 - bhuber
1
user.groups.filter(name="group name").exists() 应该能正常工作。您编写的解决方案使用了两个查询,因此不太优化。 - Noopur Phalak
如果你需要获取某个用户组中的用户列表... - Mark Chackerian
确实,减少数据库查询以检查一组给定用户的关系是一个不错的解决方案。 - Trigremm
回顾这个解决方案十年后,我非常确定我永远不想像这样获取整个用户列表。这是一种在规模上会崩溃的东西——你只想在非常特定的用例中使用,在那里有保证用户列表将保持较小。 - Mark Chackerian

11
如果要检查用户是否属于特定组,可以在Django模板中使用以下代码:

{% if group in request.user.groups.all %} "某些操作" {% endif %}

该代码会检查当前登录用户是否属于指定的用户组,如果是,则执行一些操作。

2
这对我不起作用,似乎需要将比较组与组名进行比较。 - hosein

10

你只需要一行代码:

from django.contrib.auth.decorators import user_passes_test  

@user_passes_test(lambda u: u.groups.filter(name='companyGroup').exists())
def you_view():
    return HttpResponse("Since you're logged in, you can see this text!")

6
虽然代码不是很干净,也不太可重用,但因将其压缩成一行而获得+1的点赞。 - WhyNotHugo

8

使用如下代码:

{% for group in request.user.groups.all %}
    {% if group.name == 'GroupName' %}
    {% endif %}
{% endfor %}

我一直在寻找这个。谢谢。 - Robin

4

我有类似的情况,我想测试用户是否在某个群组中。因此,我创建了一个名为utils.py的新文件,其中我放置了所有帮助我完成整个应用程序的小工具。在那里,我有以下定义:

utils.py

def is_company_admin(user):
    return user.groups.filter(name='company_admin').exists()

基本上,我正在测试用户是否在组company_admin中,并为了清晰起见,我将此函数称为is_company_admin

当我想要检查用户是否在company_admin中时,只需要这样做:

views.py

from .utils import *

if is_company_admin(request.user):
        data = Company.objects.all().filter(id=request.user.company.id)

现在,如果您想在模板中进行测试,可以将is_user_admin添加到您的上下文中,类似于以下内容:

views.py

return render(request, 'admin/users.html', {'data': data, 'is_company_admin': is_company_admin(request.user)})

现在你可以在模板中评估你的响应:

users.html

{% if is_company_admin %}
     ... do something ...
{% endif %}

这是一个简单清晰的解决方案,基于之前在讨论串中找到的答案,但是采用了不同的方法。希望能对某些人有所帮助。

在 Django 3.0.4 中进行过测试。


在你的 data = Company.objects.all().filter(id=request.user.company.id) 中,Company代表什么?那是你的模型吗? - Hayden
是的,@hayden,在这种情况下,Company 是我的模型。 - Branko Radojevic

1

如果您想检查用户组是否属于预定义的组列表:

def is_allowed(user):
    allowed_group = set(['admin', 'lead', 'manager'])
    usr = User.objects.get(username=user)
    groups = [ x.name for x in usr.groups.all()]
    if allowed_group.intersection(set(groups)):
       return True
    return False

2
[你可以使用 { x.name for x in usr.groups.all() }](http://docs.python.org/2/tutorial/datastructures.html#sets) - Kos

0
我是用以下的方式完成的。看起来效率不高,但我脑海中没有其他方法:
@login_required
def list_track(request):

usergroup = request.user.groups.values_list('name', flat=True).first()
if usergroup in 'appAdmin':
    tracks = QuestionTrack.objects.order_by('pk')
    return render(request, 'cmit/appadmin/list_track.html', {'tracks': tracks})

else:
    return HttpResponseRedirect('/cmit/loggedin')

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