W Django, jak sprawdzić, czy użytkownik jest w określonej grupie?

146

Utworzyłem niestandardową grupę w serwisie administratora Django.

W moim kodzie chcę sprawdzić, czy użytkownik jest w tej grupie. W jaki sposób mogę to zrobić?

TIMEX
źródło

Odpowiedzi:

117

Dostęp do grup można uzyskać po prostu za pomocą groupsatrybutu on 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

potem user.groups.all()wraca [<Group: Editor>].

Alternatywnie, i bardziej bezpośrednio, możesz sprawdzić, czy użytkownik jest w grupie:

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

    ...

Zauważ, że groupnamemoże to być również rzeczywisty obiekt Django Group.

miku
źródło
112
Rzeczywiste sprawdzenie byłobyif user.groups.filter(name=group_name).count(): # do something
Maccesch
144
lub użyj .exists () zamiast .count ()
Lie Ryan
3
Pytanie dotyczy zapytania o model użytkownika dla należących do niego grup, a nie jak ich instancje ... -.-
Jcc.Sanabria
210

Twój obiekt użytkownika jest połączony z obiektem Group za pośrednictwem relacji ManyToMany .

W ten sposób możesz zastosować metodę filtru do user.groups .

Aby więc sprawdzić, czy dany Użytkownik należy do określonej grupy (na przykład „Członek”), wykonaj następujące czynności:

def is_member(user):
    return user.groups.filter(name='Member').exists()

Jeśli chcesz sprawdzić, czy dany użytkownik należy do więcej niż jednej podanej grupy, użyj operatora __in w następujący sposób:

def is_in_multiple_groups(user):
    return user.groups.filter(name__in=['group1', 'group2']).exists()

Pamiętaj, że te funkcje mogą być używane z dekoratorem @user_passes_test do zarządzania dostępem do twoich widoków:

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

Mam nadzieję, że to pomoże

Charlesthk
źródło
4
Nie jestem pewien co do wewnętrznego działania dostępu do bazy danych django, ale wydaje się to o wiele bardziej wydajne niż niektóre inne sugestie, takie jak zebranie wszystkich użytkowników w grupie i wykonanie standardowego Pythona user in groups(lub odwrotnie).
brianmearns
1
Czy nie musisz dodawać .exists()na końcu, aby zwrócić wartość logiczną? W przeciwnym razie is_member()i is_in_multiple_groups()zwróci a QuerySet, co może nie dać pożądanego rezultatu.
Michael Bates,
4
Zgodnie z dokumentacją Django, jest rzeczywiście szybsze w użyciu exist (), ponieważ nie ocenia zestawu zapytań: docs.djangoproject.com/en/dev/ref/models/querysets/#exists
Charlesthk
5
Prawdopodobnie chcesz, aby superużytkownik przeszedł pomyślnie test (bez przeszukiwania bazy danych):def is_member(user): return user.is_superuser or user.groups.filter(...
Dave
is_in_multiple_groupsmożna bardziej jednoznacznie nazwać, is_in_some_groupsponieważ nie wymaga, aby użytkownik był członkiem wszystkich grup
PeterVermont
15

Jeśli potrzebujesz listy użytkowników należących do grupy, możesz to zrobić:

from django.contrib.auth.models import Group
users_in_group = Group.objects.get(name="group name").user_set.all()

a następnie sprawdź

 if user in users_in_group:
     # do something

aby sprawdzić, czy użytkownik jest w grupie.

Mark Chackerian
źródło
5
Nie jest to dobrze skalowalne w przypadku witryn z więcej niż małą liczbą użytkowników, ponieważ przy każdym uruchomieniu będzie ładować tabelę dużych podzbiorów użytkowników do pamięci.
bhuber
1
user.groups.filter(name="group name").exists()powinno działać dobrze. Rozwiązanie, które napisałeś, używa dwóch zapytań i dlatego nie jest zbyt optymalne.
Noopur Phalak
jak mówi, „jeśli potrzebujesz listy użytkowników, którzy są w grupie” ...
Mark Chackerian
15

Jeśli nie potrzebujesz instancji użytkownika na miejscu (tak jak ja), możesz to zrobić za pomocą

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

Spowoduje to wygenerowanie tylko jednego żądania do bazy danych i zwrócenie wartości logicznej.

David Kühner
źródło
11

Jeśli użytkownik należy do określonej grupy lub nie, można to sprawdzić w szablonach django za pomocą:

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

CODEkid
źródło
1
to nie działa dla mnie, wydaje się, że wymaga porównania nazwy grupy z nazwą grupy
wąż
10

Potrzebujesz tylko jednej linii:

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!")
Marcelo Cintra de Melo
źródło
4
Jednak niezbyt czysty kod i niezbyt wielokrotnego użytku, ale +1 za umieszczenie go w jednej linii.
WhyNotHugo
1

Na wszelki wypadek, jeśli chcesz sprawdzić, czy grupa użytkownika należy do predefiniowanej listy grup:

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
James Sapam
źródło
1

Mam podobną sytuację, chciałem sprawdzić, czy użytkownik jest w określonej grupie. Dlatego utworzyłem nowy plik utils.py, w którym umieściłem wszystkie moje małe narzędzia, które pomagają mi w całej aplikacji. Mam taką definicję:

utils.py

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

więc zasadniczo sprawdzam, czy użytkownik jest w grupie company_admin i dla jasności nazwałem tę funkcję is_company_admin .

Kiedy chcę sprawdzić, czy użytkownik jest na koncie company_admin , po prostu robię to:

views.py

from .utils import *

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

Teraz, jeśli chcesz przetestować to samo w swoim szablonie, możesz dodać is_user_admin w swoim kontekście, coś takiego:

views.py

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

Teraz możesz ocenić swoją odpowiedź w szablonie:

users.html

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

Proste i przejrzyste rozwiązanie, oparte na odpowiedziach, które można znaleźć wcześniej w tym wątku, ale zrobiono inaczej. Mam nadzieję, że to komuś pomoże.

Przetestowane w Django 3.0.4.

Branko Radojevic
źródło
W twoim data = Company.objects.all().filter(id=request.user.company.id), co oznacza Firma? Czy to twój model?
Hayden
Tak @hayden, w tym przypadku moim modelem jest firma.
Branko Radojevic
0

W jednej linii:

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

Ocenia się albo Truealbo False.

Philipp Zedler
źródło
3
Jest to nieefektywne, ponieważ będzie pobierać dużo więcej danych, a następnie działać na nich po stronie django. Lepiej jest .exists()pozwolić dbowi wykonać całą pracę.
WhyNotHugo
0

Zrobiłem to w następujący sposób. Wydaje się nieefektywne, ale nie miałem innego wyjścia:

@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')
Mohammad
źródło
0

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

To zapytanie poinformuje użytkownika: "tom", czy należy do grupy "admin", czy nie

Trung Lê
źródło
nazwa_grupy z podwójnym podkreśleniem
Trung Lê
0

Zrobiłem to w ten sposób. Dla grupy o nazwie 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)

szablon

# index.html
{% if is_editor %}
  <h1>Editor tools</h1>
{% endif %}
Harry Moreno
źródło