No Django, como verifico se um usuário está em um determinado grupo?

146

Criei um grupo personalizado no site de administração do Django.

No meu código, quero verificar se um usuário está neste grupo. Como faço isso?

TIMEX
fonte

Respostas:

117

Você pode acessar os grupos simplesmente através do groupsatributo 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

então user.groups.all()retorna [<Group: Editor>].

Como alternativa e mais diretamente, você pode verificar se um usuário está em um grupo:

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

    ...

Note que tambémgroupname pode ser o objeto atual do Django Group.

miku
fonte
112
A verificação real seriaif user.groups.filter(name=group_name).count(): # do something
Maccesch
144
ou usar .exists () em vez de .count ()
Lie Ryan
3
A pergunta é sobre consulta o modelo de usuário para os grupos a que pertence, e não como instantiate'em ... -.-
Jcc.Sanabria
210

Seu objeto Usuário está vinculado ao objeto Grupo por meio de um relacionamento ManyToMany .

Assim, você pode aplicar o método de filtro ao user.groups .

Portanto, para verificar se um determinado usuário está em um determinado grupo ("Membro", por exemplo), faça o seguinte:

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

Se você deseja verificar se um determinado usuário pertence a mais de um grupo, use o operador __in da seguinte forma:

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

Observe que essas funções podem ser usadas com o decorador @user_passes_test para gerenciar o acesso às suas visualizações:

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

Espero que esta ajuda

Charlesthk
fonte
4
Não tenho certeza sobre o funcionamento interno do acesso ao banco de dados do django, mas isso parece muito mais eficiente do que algumas das outras sugestões, como reunir todos os usuários de um grupo e criar um python padrão user in groups(ou vice-versa).
Brianmearns
1
Você não precisa adicionar .exists()no final para retornar um booleano? Caso contrário, is_member()e is_in_multiple_groups()retornará uma QuerySet, o que pode não se obter o resultado desejado.
Michael Bates
4
De acordo com a documentação do Django, é realmente mais rápido para a utilização exista () uma vez que não avaliar os queryset: docs.djangoproject.com/en/dev/ref/models/querysets/#exists
Charlesthk
5
Você provavelmente deseja que o superusuário passe no teste (sem consultar o banco de dados):def is_member(user): return user.is_superuser or user.groups.filter(...
Dave
is_in_multiple_groupspode ser mais explicitamente nomeado is_in_some_groups, uma vez que não requer que o usuário ser um membro de todos os grupos
PeterVermont
15

Se você precisar da lista de usuários que estão em um grupo, faça o seguinte:

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

e depois verifique

 if user in users_in_group:
     # do something

para verificar se o usuário está no grupo.

Mark Chackerian
fonte
5
Isso não é adequado para sites com mais de um pequeno número de usuários, pois carrega grandes tabelas de usuários de subconjuntos na memória toda vez que é executado.
bhuber
1
user.groups.filter(name="group name").exists()deve funcionar bem. A solução que você escreveu usa duas consultas e, portanto, não é a ideal.
Noopur Phalak
como se diz, "se você precisar da lista de usuários que estão em um grupo" ...
Mark Chackerian
15

Se você não precisar da instância do usuário no site (como eu fiz), poderá fazê-lo com

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

Isso produzirá apenas uma solicitação para o banco de dados e retornará um booleano.

David Kühner
fonte
11

Se um usuário pertence a um determinado grupo ou não, pode ser verificado nos modelos do django usando:

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

CODEkid
fonte
1
isso não trabalho para mim, parece que exigem grupo comparar com o nome grupos
Hosein
10

Você só precisa de uma linha:

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
fonte
4
Código não muito limpo e não muito reutilizável, mas +1 por colocá-lo em uma linha.
WhyNotHugo
1

Caso você queira verificar se o grupo de usuários pertence a uma lista de grupos predefinida:

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
fonte
1

Eu tenho situação semelhante, eu queria testar se o usuário está em um determinado grupo. Então, eu criei um novo arquivo utils.py onde coloco todos os meus pequenos utilitários que me ajudam em todo o aplicativo. Lá, eu tenho essa definição:

utils.py

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

basicamente, estou testando se o usuário está no grupo company_admin e, para maior clareza, chamei essa função de is_company_admin .

Quando quero verificar se o usuário está no company_admin , basta fazer isso:

views.py

from .utils import *

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

Agora, se você deseja testar o mesmo no seu modelo, pode adicionar is_user_admin no seu contexto, algo como isto:

views.py

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

Agora você pode avaliar sua resposta em um modelo:

users.html

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

Solução simples e limpa, com base em respostas que podem ser encontradas anteriormente neste tópico, mas feitas de maneira diferente. Espero que ajude alguém.

Testado no Django 3.0.4.

Branko Radojevic
fonte
No seu caso data = Company.objects.all().filter(id=request.user.company.id), o que a Empresa significa? Esse é o seu modelo?
Hayden
Sim @hayden, neste caso a empresa é o meu modelo.
Branko Radojevic
0

Em uma linha:

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

Isso avalia como Trueou False.

Philipp Zedler
fonte
3
Isso é ineficiente, pois ele buscará muito mais dados e depois operará no lado do django. É melhor usar .exists()para deixar o banco de dados fazer o trabalho.
WhyNotHugo
0

Eu fiz da seguinte maneira. Parece ineficiente, mas eu não tinha outra maneira de pensar:

@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
fonte
0

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

Essa consulta informará o usuário: "tom" se pertence ao grupo "admin" ou não

Trung Lê
fonte
groups__name com sublinhado duplo
Trung Lê
0

Eu fiz assim. Para o grupo chamado 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)

modelo

# index.html
{% if is_editor %}
  <h1>Editor tools</h1>
{% endif %}
Harry Moreno
fonte