Як у Django можна перевірити, чи є користувач у певній групі?


146

Я створив власну групу на сайті адміністратора Django.

У своєму коді я хочу перевірити, чи є користувач у цій групі. Як це зробити?

Відповіді:


117

Ви можете отримати доступ до груп просто через groupsатрибут на User.

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>].

Крім того, і більш прямо, ви можете перевірити, чи є користувач aa в групі, виконавши:

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

    ...

Зауважте, що такожgroupname може бути власне об’єкт групи Django.


112
Фактична перевірка була бif user.groups.filter(name=group_name).count(): # do something
Maccesch

144
або використовувати .exists () замість .count ()
Lie Ryan

3
Питання полягає в запиті моделі користувача для груп, до яких вона належить, а не про те, як інстанціювати ... -.-
Jcc.Sanabria

210

Ваш об'єкт " Користувач" пов'язаний з об'єктом групи через відносини ManyToMany .

Таким чином, ви можете застосувати метод фільтра до 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

Сподіваюся, що це допоможе


4
Я не впевнений у внутрішній роботі доступу до БД django, але це здається набагато ефективнішим, ніж деякі інші пропозиції, наприклад, залучення всіх користувачів до групи та виконання стандартного пітона user in groups(або навпаки).
brianmearns

1
Чи не потрібно додати .exists()до кінця, щоб повернути булеве значення? В іншому випадку is_member()і is_in_multiple_groups()повернеться a QuerySet, що може не дати бажаного результату.
Майкл Бейтс

4
Згідно з документацією Django, використання дійсно швидше, оскільки воно не оцінює набір запитів: docs.djangoproject.com/en/dev/ref/models/querysets/#exists
Charlesthk

5
Ви, мабуть, хочете, щоб суперпользователь пройшов тест (без запитів у базі даних):def is_member(user): return user.is_superuser or user.groups.filter(...
Дейв,

is_in_multiple_groupsможна чіткіше назвати, is_in_some_groupsоскільки це не вимагає, щоб користувач був членом усіх груп
PeterVermont

15

Якщо вам потрібен список користувачів, які перебувають у групі, ви можете зробити це замість цього:

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

щоб перевірити, чи є користувач у групі.


5
Це не відповідає масштабам для сайтів з більш ніж невеликою кількістю користувачів, оскільки він буде завантажувати в пам'ять великі підмножини користувачів під час кожного запуску.
бхубер

1
user.groups.filter(name="group name").exists()повинен добре працювати. Написане вами рішення використовує два запити, тому не дуже оптимальне.
Ноопур Фалак

як говориться, "якщо вам потрібен список користувачів, які входять до групи" ...
Марк Чакерян

15

Якщо вам не потрібен екземпляр користувача на сайті (як я це робив), ви можете це зробити

User.objects.filter(pk=userId, groups__name='Editor').exists()

Це створить лише один запит до бази даних і поверне булеве значення.


11

Якщо користувач належить до певної групи чи ні, його можна перевірити в шаблонах django, використовуючи:

{% if group in request.user.groups.all %} "some action" {% endif %}


1
це не працює для мене, схоже, що потрібно порівнювати групу з назвою груп
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!")

4
Хоча не дуже чистий код і не дуже багаторазовий, але +1 для отримання його в один рядок.
WhyNotHugo

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


1

У мене схожа ситуація, я хотів перевірити, чи є користувач у певній групі. Отже, я створив новий файл 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), що означає компанія? Це ваша модель?
Хайден

Так @hayden, в цьому випадку компанія - моя модель.
Бранко Радоевич

0

В одному рядку:

'Groupname' in user.groups.values_list('name', flat=True)

Це оцінюється на Trueабо False.


3
Це неефективно, оскільки воно отримає набагато більше даних, а потім оперує ним на стороні джанго. Краще використовувати, .exists()щоб дозволити db виконувати роботу.
WhyNotHugo

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')

0

User.objects.filter(username='tom', groups__name='admin').exists()

Цей запит повідомить користувача: "tom", належать вони до групи "admin" чи ні


groups__name з подвійним підкресленням
Trung Lê

0

Я зробив це так. Для групи з назвою Editor.

# views.py
def index(request):
    current_user_groups = request.user.groups.values_list("name", flat=True)
    context = {
        "is_editor": "Editor" in current_user_groups,
    }
    return render(request, "index.html", context)

шаблон

# index.html
{% if is_editor %}
  <h1>Editor tools</h1>
{% endif %}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.