Di Django, bagaimana saya memeriksa apakah pengguna berada dalam grup tertentu?

146

Saya membuat grup khusus di situs admin Django.

Dalam kode saya, saya ingin memeriksa apakah ada pengguna di grup ini. Bagaimana aku melakukan itu?

TIMEX
sumber

Jawaban:

117

Anda dapat mengakses grup hanya melalui groupsatribut aktif 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

lalu user.groups.all()kembali [<Group: Editor>].

Atau, dan lebih langsung, Anda dapat memeriksa apakah pengguna berada dalam grup dengan:

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

    ...

Catatan yang jugagroupname bisa menjadi objek Grup Django yang sebenarnya.

miku
sumber
112
Pengecekan yang sebenarnya adalahif user.groups.filter(name=group_name).count(): # do something
Maccesch
144
atau gunakan .exists () sebagai ganti .count ()
Lie Ryan
3
Pertanyaannya adalah tentang permintaan model Pengguna untuk grup yang dimilikinya, bukan bagaimana membuat instantiate'em ... -.-
Jcc.Sanabria
210

Objek Pengguna Anda ditautkan ke objek Grup melalui ManyToMany hubungan .

Dengan demikian Anda dapat menerapkan metode filter ke user.groups .

Jadi, untuk memeriksa apakah Pengguna yang diberikan berada dalam grup tertentu ("Anggota" sebagai contoh), lakukan saja ini:

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

Jika Anda ingin memeriksa apakah pengguna tertentu memiliki lebih dari satu grup, gunakan operator __in seperti:

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

Perhatikan bahwa fungsi tersebut dapat digunakan dengan dekorator @user_passes_test untuk mengelola akses ke tampilan Anda:

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

Semoga bantuan ini

Charlesthk
sumber
4
Saya tidak yakin tentang cara kerja akses DB Django, tetapi ini tampaknya jauh lebih efisien daripada beberapa saran lainnya, seperti memasukkan semua pengguna dalam grup dan melakukan python standar user in groups(atau sebaliknya).
brianmearns
1
Tidakkah Anda harus menambahkan .exists()sampai akhir untuk mengembalikan boolean? Jika tidak is_member()dan is_in_multiple_groups()akan mengembalikan QuerySet, yang mungkin tidak memberikan hasil yang diinginkan.
Michael Bates
4
Menurut dokumentasi Django, ini memang lebih cepat digunakan ada () karena tidak mengevaluasi queryset: docs.djangoproject.com/en/dev/ref/models/querysets/#exists
Charlesthk
5
Anda mungkin ingin agar pengguna super lulus ujian (tanpa menanyakan basis data):def is_member(user): return user.is_superuser or user.groups.filter(...
Dave
is_in_multiple_groupsdapat secara eksplisit dinamai is_in_some_groupskarena tidak mengharuskan pengguna menjadi anggota dari semua grup
PeterVermont
15

Jika Anda membutuhkan daftar pengguna yang ada dalam grup, Anda dapat melakukan ini sebagai gantinya:

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

lalu periksa

 if user in users_in_group:
     # do something

untuk memeriksa apakah pengguna berada dalam grup.

Mark Chackerian
sumber
5
Ini tidak menskala dengan baik untuk situs dengan jumlah pengguna lebih sedikit, karena ini akan memuat tabel subset pengguna besar ke dalam memori setiap kali dijalankan.
bhuber
1
user.groups.filter(name="group name").exists()harus bekerja dengan baik. Solusi yang Anda tulis menggunakan dua pertanyaan dan karenanya tidak terlalu optimal.
Noopur Phalak
seperti yang tertulis, "jika Anda memerlukan daftar pengguna yang ada dalam grup" ...
Mark Chackerian
15

Jika Anda tidak memerlukan instance pengguna di situs (seperti yang saya lakukan), Anda dapat melakukannya dengan

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

Ini hanya akan menghasilkan satu permintaan ke database dan mengembalikan boolean.

David Kühner
sumber
11

Jika pengguna milik kelompok tertentu atau tidak, dapat diperiksa di templat Django menggunakan:

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

CODEkid
sumber
1
ini tidak bekerja untuk saya, tampaknya memerlukan kelompok pembanding dengan nama grup
hosein
10

Anda hanya perlu satu baris:

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
sumber
4
Bukan kode yang sangat bersih, dan tidak dapat digunakan kembali, tetapi +1 untuk membuatnya menjadi satu baris.
WhyNotHugo
1

Untuk jaga-jaga jika Anda ingin memeriksa grup pengguna milik daftar grup yang telah ditentukan:

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

Saya memiliki situasi yang serupa, saya ingin menguji apakah pengguna berada dalam kelompok tertentu. Jadi, saya telah membuat file utils.py baru di mana saya meletakkan semua utilitas kecil saya yang membantu saya melalui seluruh aplikasi. Di sana, saya punya definisi ini:

utils.py

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

jadi pada dasarnya saya sedang menguji apakah pengguna dalam grup company_admin dan untuk kejelasan saya sudah memanggil fungsi ini is_company_admin .

Ketika saya ingin memeriksa apakah pengguna di company_admin saya hanya melakukan ini:

views.py

from .utils import *

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

Sekarang, jika Anda ingin menguji yang sama dalam template Anda, Anda dapat menambahkan is_user_admin dalam konteks Anda, sesuatu seperti ini:

views.py

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

Sekarang Anda dapat mengevaluasi respons Anda di templat:

users.html

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

Solusi sederhana dan bersih, berdasarkan jawaban yang dapat ditemukan sebelumnya di utas ini, tetapi dilakukan secara berbeda. Semoga ini bisa membantu seseorang.

Diuji dalam Django 3.0.4.

Branko Radojevic
sumber
Di Anda data = Company.objects.all().filter(id=request.user.company.id), apa yang ditandakan Perusahaan? Apakah itu Model Anda?
Hayden
Ya @hayden, dalam hal ini Company adalah model saya.
Branko Radojevic
0

Dalam satu baris:

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

Ini mengevaluasi salah satu Trueatau False.

Philipp Zedler
sumber
3
Ini tidak efisien, karena akan mengambil lebih banyak data, dan kemudian beroperasi di sisi Django. Lebih baik digunakan .exists()untuk membiarkan db melakukan pekerjaan.
WhyNotHugo
0

Saya telah melakukannya dengan cara berikut. Tampaknya tidak efisien tetapi saya tidak memiliki cara lain dalam pikiran saya:

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

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

Kueri itu akan memberi tahu Anda pengguna: "tom" apakah milik grup "admin" atau tidak

Trung Lê
sumber
groups__name dengan garis bawah ganda
Trung Lê
0

Saya melakukannya seperti ini. Untuk grup yang diberi nama 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)

templat

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