6

używam django-guardian aby zarządzać za zgodą obiektu.Przedmioty z uprawnieniami przypisanymi przez Django opiekuna niewidoczne admin

dla danego użytkownika Wyrażam zgodę wszystkie pozwolenia na jednym obiekcie:

joe = User.objects.get(username="joe") 

mytask = Task.objects.get(pk=1) 

assign('add_task', joe, mytask) 
assign('change_task', joe, mytask) 
assign('delete_task', joe, mytask) 

a ja się, zgodnie z oczekiwaniami:

In [57]: joe.has_perm("add_task", mytask) 
Out[57]: True 

In [58]: joe.has_perm("change_task", mytask) 
Out[58]: True 

In [59]: joe.has_perm("delete_task", mytask) 
Out[59]: True 

W admin.py ja również TaskAdmin dziedziczą GuardedModelAdmin zamiast z admin.ModelAdmin

Teraz, gdy łączę się z moją stroną z joe, na komputerze dostaję:

You don't have permission to edit anything 

Am I nie powinien być w stanie edytować mytask obiekt?

Czy muszę ustawić niektóre uprawnienia przy użyciu wbudowanego systemu uprawnień opartego na modelu?

Czy brakuje mi czegoś?

EDIT

Próbowałem dodać opcję user_can_access_owned_objects_only, która ma do czynienia z mojego problemu, ale ja nadal nie widzę w moim administratora ...

class TaskAdmin(GuardedModelAdmin): 

    user_can_access_owned_objects_only = True 

    pass 

admin.site.register(Task, TaskAdmin) 

Thank Ci

Odpowiedz

3

w celu tylko zobaczyć instancje należące do bieżącego użytkownika, daję mu wszystkie uprawnienia

add_task=Permission.objects.get(codename="add_task") 
change_task=Permission.objects.get(codename="change_task") 
delete_task=Permission.objects.get(codename="delete_task") 

joe.user_permissions.add(add_task) 
joe.user_permissions.add(change_task) 
joe.user_permissions.add(delete_task) 

następnie ustawić pozwolenie na kilku przypadkach stosując guardian.shortcuts.assign i filtrować queryset w admin:

class TaskAdmin(admin.ModelAdmin): 

    def queryset(self, request): 
      if request.user.is_superuser: 
       return super(TaskAdmin, self).queryset(request) 
      return get_objects_for_user(user=request.user, perms=['add_task', 'change_task', 'delete_task'], klass=Task) 

to daleko od doskonałości, ale nie mogę znaleźć żadnego innego rozwiązania .

2

Django Admin, zwłaszcza, że ​​ma do czynienia w/change zgody, jest nieco gruboziarnisty. Metoda wewnętrzna obejmuje sprawdzanie uprawnień, których faktycznie brakuje.

Po drugie, GuardedModelAdmin przynosi sprawdzanie własności (poprzez user_can_access_owned_objects_only) i formularze do zarządzania uprawnieniami na poziomie wiersza. Nie zapewnia żadnych innych uprawnień dostępu do poziomu dla administratora Django.

Dla typowego wiersz poziom uprawnień sceny w Django Admin, chciałbym zaproponować kod, tutaj wprowadziliśmy opcjonalny „view” gość:

class ExtendedGuardedModelAdmin(GuardedModelAdmin): 
    def queryset(self, request): 
     qs = super(ExtendedGuardedModelAdmin, self).queryset(request) 
     # Check global permission 
     if super(ExtendedGuardedModelAdmin, self).has_change_permission(request) \ 
      or (not self.list_editable and self.has_view_permission(request)): 
       return qs 
     # No global, filter by row-level permissions. also use view permission if the changelist is not editable 
     if self.list_editable: 
      return get_objects_for_user(request.user, [self.opts.get_change_permission()], qs) 
     else: 
      return get_objects_for_user(request.user, [self.opts.get_change_permission(), self.get_view_permission(
)], qs, any_perm=True) 

    def has_change_permission(self, request, obj=None): 
     if super(ExtendedGuardedModelAdmin, self).has_change_permission(request, obj): 
      return True 
     if obj is None: 
      # Here check global 'view' permission or if there is any changeable items 
      return self.has_view_permission(request) or self.queryset(request).exists() 
     else: 
      # Row-level checking 
      return request.user.has_perm(self.opts.get_change_permission(), obj) 

    def get_view_permission(self): 
     return 'view_%s' % self.opts.object_name.lower() 

    def has_view_permission(self, request, obj=None): 
     return request.user.has_perm(self.opts.app_label + '.' + self.get_view_permission(), obj) 

    def has_delete_permission(self, request, obj=None): 
     return super(ExtendedGuardedModelAdmin, self).has_delete_permission(request, obj) \ 
       or (obj is not None and request.user.has_perm(self.opts.get_delete_permission(), obj)) 

W ten sposób można osiągnąć bardziej elastyczną kontrolę uprawnień, łatwość uprawnienia są teraz globalne, łatwość obj-uprawnienia są na poziomie wiersza oparta:

  • joe.user_permissions.add(add_task)
    Joe mógł dodać nowe zadania (nie ma row-level 'dodać' pozwolenie)
  • joe.user_permissions.add(change_task)
    Joe może zmienić wszystkie zadania
  • joe.user_permissions.add(delete_task)
    Joe mógł usunąć wszystkie zadania
  • assign(Task._meta.get_change_permission(), joe, obj)
    Joe może zmienić OBJ zadań, patrz listy zmian zawierający obj a także inne zadania wymienne .
  • assign(Task._meta.get_delete_permission(), joe, obj)
    Joe mógł usunąć zadanie obj
  • assign('view_task', joe, obj)
    [Opcjonalnie] Joe mógł oglądać Zadaniem obj (warto sprawdzić to pozwolenie na dostosowanej stronie widoku Admin)
  • joe.user_permissions.add(Permission.objects.get(codename='view_task', ...))
    [opcjonalnie] joe może wyświetlać wszystkie zadania w liście zmian, o ile lista zmian nie jest edytowalna inline. Jest to przydatne, jeśli joe może odbierać przedmioty z pola raw_id_fields bez posiadania uprawnień do zmiany.
  • ...

Można zignorować 'view' pozwolenie bezpiecznie jeśli jest bezużyteczny dla Ciebie.

Obecnie django.contrib.admin.util.get_deleted_objects nie czci OBJ podczas sprawdzania zezwolenia, jeśli trzeba sprawdzić pozwolenie na poziomie wierszy podczas usuwania, załatać get_deleted_objects modyfikując linię if not user.has_perm(p): do if not user.has_perm(p, obj):. Bilety względne są 13539 & 16862

+0

Należy zdać „prośbę” a nie „” w request.user self.has_view_permission – Don

+0

@Don Tak, dzięki za wskazanie, że =) – okm

+0

może być wersjonowania zmian związanych problem, ale działa w Obiekt "Opcje" nie ma atrybutu "get_change_permission" – Mutant