Chciałbym użyć systemu opartego na uprawnieniach, aby ograniczyć pewne działania w mojej aplikacji Django. Te akcje nie muszą być związane z konkretnym modelem (np. Dostęp do sekcji w aplikacji, wyszukiwanie ...), więc nie mogę bezpośrednio korzystać ze standardowej struktury uprawnień , ponieważ Permission
model wymaga odniesienia do zainstalowanego typu zawartości.
Mógłbym napisać własny model uprawnień, ale wtedy musiałbym przepisać wszystkie dodatki zawarte w uprawnieniach Django, takie jak:
- Możliwość nadawania uprawnień użytkownikom i grupom.
permission_required
Dekorator .User.has_perm
i powiązane metody użytkownika.perms
Zmienna szablonu .- ...
Sprawdziłem niektóre aplikacje, takie jak django-authority i django-guardian , ale wydaje się, że zapewniają one uprawnienia jeszcze bardziej powiązane z systemem modelowym, zezwalając na uprawnienia dla poszczególnych obiektów.
Czy istnieje sposób na ponowne użycie tego frameworka bez zdefiniowania żadnego modelu (poza User
i Group
) dla projektu?
źródło
Dla tych z Was, którzy wciąż szukają:
Możesz utworzyć model pomocniczy bez tabeli bazy danych. Ten model może wnieść do twojego projektu wszelkie potrzebne uprawnienia. Nie ma potrzeby zajmowania się ContentType ani jawnego tworzenia obiektów Permission.
from django.db import models class RightsSupport(models.Model): class Meta: managed = False # No database table creation or deletion \ # operations will be performed for this model. default_permissions = () # disable "add", "change", "delete" # and "view" default permissions permissions = ( ('customer_rights', 'Global customer rights'), ('vendor_rights', 'Global vendor rights'), ('any_rights', 'Global any rights'), )
Zaraz potem
manage.py makemigrations
imanage.py migrate
możesz korzystać z tych uprawnień jak z każdego innego.# Decorator @permission_required('app.customer_rights') def my_search_view(request): … # Inside a view def my_search_view(request): request.user.has_perm('app.customer_rights') # In a template # The currently logged-in user’s permissions are stored in the template variable {{ perms }} {% if perms.app.customer_rights %} <p>You can do any customer stuff</p> {% endif %}
źródło
default_permissions = ()
. Zapobiegnie to automatycznemu tworzeniu przez Django domyślnych uprawnień dodawania / zmiany / usuwania / wyświetlania dla tego modelu, które są najprawdopodobniej niepotrzebne, jeśli używasz tego podejścia.Idąc za radą Gonzalo , użyłem modelu proxy i niestandardowego menedżera do obsługi moich „bezmodelowych” uprawnień z fikcyjnym typem zawartości.
from django.db import models from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType class GlobalPermissionManager(models.Manager): def get_query_set(self): return super(GlobalPermissionManager, self).\ get_query_set().filter(content_type__name='global_permission') class GlobalPermission(Permission): """A global permission, not attached to a model""" objects = GlobalPermissionManager() class Meta: proxy = True def save(self, *args, **kwargs): ct, created = ContentType.objects.get_or_create( name="global_permission", app_label=self._meta.app_label ) self.content_type = ct super(GlobalPermission, self).save(*args, **kwargs)
źródło
FieldError: Cannot resolve keyword 'name' into field. Choices are: app_label, id, logentry, model, permission
.Naprawiono odpowiedź Chewiego w Django 1.8, o którą proszono w kilku komentarzach.
W informacjach o wydaniu jest napisane:
Więc jest to „nazwa” w odwołaniu w ContentType, której nie używa w GlobalPermissions.
Kiedy to naprawię, otrzymuję następujące informacje:
from django.db import models from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType class GlobalPermissionManager(models.Manager): def get_queryset(self): return super(GlobalPermissionManager, self).\ get_queryset().filter(content_type__model='global_permission') class GlobalPermission(Permission): """A global permission, not attached to a model""" objects = GlobalPermissionManager() class Meta: proxy = True verbose_name = "global_permission" def save(self, *args, **kwargs): ct, created = ContentType.objects.get_or_create( model=self._meta.verbose_name, app_label=self._meta.app_label, ) self.content_type = ct super(GlobalPermission, self).save(*args)
Klasa GlobalPermissionManager nie uległa zmianie, ale została uwzględniona w celu zapewnienia kompletności.
źródło
To jest alternatywne rozwiązanie. Najpierw zadaj sobie pytanie: dlaczego nie stworzyć manekina, który naprawdę istnieje w DB, ale nigdy nie jest używany, z wyjątkiem posiadania uprawnień? To nie jest miłe, ale myślę, że jest to poprawne i proste rozwiązanie.
from django.db import models class Permissions(models.Model): can_search_blue_flower = 'my_app.can_search_blue_flower' class Meta: permissions = [ ('can_search_blue_flower', 'Allowed to search for the blue flower'), ]
Powyższe rozwiązanie ma tę zaletę, że możesz użyć zmiennej
Permissions.can_search_blue_flower
w swoim kodzie źródłowym zamiast używać literału „my_app.can_search_blue_flower”. Oznacza to mniej literówek i więcej autouzupełniania w IDE.źródło
managed=False
nie pozwala ci używaćPermissions.can_search_blue_flower
z jakiegoś powodu?Możesz użyć
proxy model
do tego z fikcyjnym typem zawartości.from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType class CustomPermission(Permission): class Meta: proxy = True def save(self, *args, **kwargs): ct, created = ContentType.objects.get_or_create( model=self._meta.verbose_name, app_label=self._meta.app_label, ) self.content_type = ct super(CustomPermission, self).save(*args)
Teraz można utworzyć tylko z pozwolenia
name
icodename
z pozwoleniem odCustomPermission
modelu.CustomPermission.objects.create(name='Can do something', codename='can_do_something')
Możesz też wyszukiwać i wyświetlać tylko uprawnienia niestandardowe w swoich szablonach, takich jak ten.
CustomPermission.objects.filter(content_type__model='custom permission')
źródło