Dans Django, comment vérifier si un utilisateur fait partie d'un certain groupe?

147

J'ai créé un groupe personnalisé sur le site d'administration de Django.

Dans mon code, je veux vérifier si un utilisateur fait partie de ce groupe. Comment je fais ça?

TIMEX
la source

Réponses:

118

Vous pouvez accéder aux groupes simplement via l' groupsattribut sur 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

puis user.groups.all()revient [<Group: Editor>].

Alternativement, et plus directement, vous pouvez vérifier si un utilisateur est dans un groupe en:

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

    ...

Notez qu'il groupnamepeut également s'agir de l'objet Django Group réel.

Miku
la source
112
La vérification réelle seraitif user.groups.filter(name=group_name).count(): # do something
Maccesch
144
ou utilisez .exists () au lieu de .count ()
Lie Ryan
3
La question est d'interroger le modèle User pour les groupes auxquels il appartient, pas de savoir comment l'instancier ... -.-
Jcc.Sanabria
210

Votre objet User est lié à l' objet Group via une relation ManyToMany .

Vous pouvez ainsi appliquer la méthode de filtrage à user.groups .

Donc, pour vérifier si un utilisateur donné est dans un certain groupe ("Membre" pour l'exemple), il suffit de faire ceci:

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

Si vous voulez vérifier si un utilisateur donné appartient à plus d'un groupe donné, utilisez l' opérateur __in comme ceci:

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

Notez que ces fonctions peuvent être utilisées avec le décorateur @user_passes_test pour gérer l'accès à vos vues:

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

J'espère que cette aide

Charlesthk
la source
4
Je ne suis pas sûr du fonctionnement interne de l'accès à la base de données de django, mais cela semble beaucoup plus efficace que certaines des autres suggestions, comme rassembler tous les utilisateurs dans un groupe et faire un python standard user in groups(ou vice versa).
brianmearns
1
N'avez-vous pas besoin d'ajouter .exists()à la fin pour renvoyer un booléen? Sinon, is_member()et is_in_multiple_groups()renverra a QuerySet, ce qui risque de ne pas donner le résultat souhaité.
Michael Bates
4
D'après la documentation de Django, il est en effet plus rapide d'utiliser exist () car il n'évalue pas l'ensemble de requêtes: docs.djangoproject.com/en/dev/ref/models/querysets/#exists
Charlesthk
5
Vous voulez probablement que le super-utilisateur réussisse le test (sans interroger la base de données):def is_member(user): return user.is_superuser or user.groups.filter(...
Dave
is_in_multiple_groupspeut être nommé plus explicitement is_in_some_groupscar il ne nécessite pas que l'utilisateur soit membre de tous les groupes
PeterVermont
15

Si vous avez besoin de la liste des utilisateurs appartenant à un groupe, vous pouvez le faire à la place:

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

puis vérifiez

 if user in users_in_group:
     # do something

pour vérifier si l'utilisateur fait partie du groupe.

Mark Chackerian
la source
5
Cela ne s'adapte pas bien aux sites comptant plus d'un petit nombre d'utilisateurs, car il chargera en mémoire de grands sous-ensembles de la table des utilisateurs à chaque exécution.
bhuber
1
user.groups.filter(name="group name").exists()devrait bien fonctionner. La solution que vous avez écrite utilise deux requêtes et donc pas très optimale.
Noopur Phalak
comme il dit, "si vous avez besoin de la liste des utilisateurs qui sont dans un groupe" ...
Mark Chackerian
15

Si vous n'avez pas besoin de l'instance utilisateur sur le site (comme je l'ai fait), vous pouvez le faire avec

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

Cela produira une seule requête à la base de données et retournera un booléen.

David Kühner
la source
11

Si un utilisateur appartient ou non à un certain groupe, peut être vérifié dans les modèles django en utilisant:

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

CODEkid
la source
1
cela ne fonctionne pas pour moi, semble nécessiter de comparer le groupe avec le nom du groupe
hosein
10

Vous avez juste besoin d'une ligne:

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
la source
4
Code pas très propre cependant, et pas très réutilisable, mais +1 pour le mettre en une seule ligne.
WhyNotHugo
1

Juste au cas où vous voudriez vérifier que le groupe de l'utilisateur appartient à une liste de groupes prédéfinie:

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
la source
1

J'ai une situation similaire, je voulais tester si l'utilisateur est dans un certain groupe. J'ai donc créé un nouveau fichier utils.py dans lequel j'ai mis tous mes petits utilitaires qui m'aident à travers toute l'application. Là, j'ai cette définition:

utils.py

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

Donc, fondamentalement, je teste si l'utilisateur est dans le groupe company_admin et pour plus de clarté, j'ai appelé cette fonction is_company_admin .

Lorsque je veux vérifier si l'utilisateur est dans company_admin, je fais simplement ceci:

views.py

from .utils import *

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

Maintenant, si vous souhaitez tester la même chose dans votre modèle, vous pouvez ajouter is_user_admin dans votre contexte, quelque chose comme ceci:

views.py

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

Vous pouvez maintenant évaluer votre réponse dans un modèle:

users.html

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

Solution simple et propre, basée sur des réponses qui peuvent être trouvées plus tôt dans ce fil, mais faites différemment. J'espère que cela aidera quelqu'un.

Testé dans Django 3.0.4.

Branko Radojevic
la source
Dans votre data = Company.objects.all().filter(id=request.user.company.id), que signifie Entreprise? Est-ce votre modèle?
Hayden le
Oui @hayden, dans ce cas, Company est mon modèle.
Branko Radojevic
0

En une seule ligne:

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

Cela évalue soit Trueou False.

Philipp Zedler
la source
3
Ceci est inefficace, car il va chercher beaucoup plus de données, puis opérer dessus du côté de django. Il vaut mieux l'utiliser .exists()pour laisser la base de données faire le travail.
WhyNotHugo
0

Je l'ai fait de la manière suivante. Cela semble inefficace mais je n'avais pas d'autre moyen dans mon esprit:

@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
la source
0

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

Cette requête vous informera de l'utilisateur: "tom", qu'il appartienne ou non au groupe "admin"

Trung Lê
la source
groups__name avec double souligné
Trung Lê
0

Je l'ai fait comme ça. Pour le groupe nommé 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)

modèle

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