Я хотел бы использовать систему на основе разрешений, чтобы ограничить определенные действия в моем приложении Django. Эти действия не обязательно должны быть связаны с конкретной моделью (например, доступ к разделам в приложении, поиск ...), поэтому я не могу использовать структуру разрешений акций напрямую, потому что Permission
модель требует ссылки на установленный тип контента.
Я мог бы написать свою собственную модель разрешений, но тогда мне пришлось бы переписать все полезности, включенные в разрешения Django, такие как:
- Возможность назначать права пользователям и группам.
permission_required
Декоратор .User.has_perm
и связанные пользовательские методы.perms
Шаблон переменной .- ...
Я проверил некоторые приложения, такие как django-Authority и django-guardian , но они, похоже, предоставляют разрешения, даже более связанные с системой модели, разрешая разрешения для каждого объекта.
Есть ли способ повторно использовать эту структуру без определения какой-либо модели (кроме User
и Group
) для проекта?
источник
Для тех из вас, кто все еще ищет:
Вы можете создать вспомогательную модель без таблицы базы данных. Эта модель может дать вашему проекту любое необходимое разрешение. Нет необходимости иметь дело с ContentType или явно создавать объекты разрешений.
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'), )
Сразу же после
manage.py makemigrations
иmanage.py migrate
вы можете использовать эти права , как и любой другой.# 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 %}
источник
default_permissions = ()
. Это предотвратит автоматическое создание Django разрешений на добавление / изменение / удаление / просмотр по умолчанию для этой модели, которые, скорее всего, не нужны, если вы используете этот подход.Следуя совету Гонсало , я использовал прокси-модель и настраиваемый менеджер для обработки моих «немодельных» разрешений с фиктивным типом контента.
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)
источник
FieldError: Cannot resolve keyword 'name' into field. Choices are: app_label, id, logentry, model, permission
.Исправление для ответа Чуи в Django 1.8, о котором просили в нескольких комментариях.
В примечаниях к выпуску говорится:
Таким образом, это «имя» в ссылке в ContentType, которое используется не в GlobalPermissions.
Когда исправляю, получаю следующее:
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)
Класс GlobalPermissionManager не изменился, но включен для полноты картины.
источник
Это альтернативное решение. Сначала спросите себя: почему бы не создать фиктивную модель, которая действительно существует в БД, но никогда не используется, за исключением удержания разрешений? Это неприятно, но я думаю, что это правильное и простое решение.
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'), ]
Вышеупомянутое решение имеет то преимущество, что вы можете использовать переменную
Permissions.can_search_blue_flower
в исходном коде вместо буквальной строки «my_app.can_search_blue_flower». Это означает меньше опечаток и больше автозаполнения в IDE.источник
managed=False
не позволяет использоватьPermissions.can_search_blue_flower
по какой-то причине?Вы можете использовать
proxy model
для этого фиктивный тип контента.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)
Теперь вы можете создать разрешение только с
name
иcodename
разрешения отCustomPermission
модели.CustomPermission.objects.create(name='Can do something', codename='can_do_something')
И вы можете запрашивать и отображать только настраиваемые разрешения в своих шаблонах, как это.
CustomPermission.objects.filter(content_type__model='custom permission')
источник