Ответ
В Django реализована мощная встроенная система разрешений (permissions), которая тесно интегрирована с моделями, пользователями и группами. Она позволяет контролировать доступ к объектам и действиям в приложении.
Почему это важно? Система разрешений обеспечивает гранулярный контроль доступа, повышая безопасность приложения и позволяя гибко управлять тем, какие пользователи или группы могут выполнять определенные операции (например, создавать, изменять, удалять или просматривать данные).
Ключевые аспекты:
- Автоматические разрешения: Для каждой модели Django автоматически создает четыре базовых разрешения:
add_<model_name>,change_<model_name>,delete_<model_name>, иview_<model_name>. -
Кастомные разрешения: Дополнительные, специфичные для приложения разрешения можно определить в классе
Metaмодели с помощью атрибутаpermissions.from django.db import models class Task(models.Model): name = models.CharField(max_length=255) is_closed = models.BooleanField(default=False) class Meta: permissions = [ ("can_close_task", "Can close task"), # (codename, human-readable name) ("can_assign_task", "Can assign task to users"), ] verbose_name = "Задача" verbose_name_plural = "Задачи" - Проверка разрешений:
- На уровне пользователя/группы: Используется метод
user.has_perm('app_label.permission_codename'). - В представлениях (views): С помощью декораторов (
@permission_required,@user_passes_test) или миксинов (PermissionRequiredMixin) для классов-представлений. - В шаблонах: Через тег
{% if perms.app_label.permission_codename %}.
- На уровне пользователя/группы: Используется метод
Пример проверки в коде:
from django.contrib.auth.decorators import permission_required
from django.shortcuts import render, get_object_or_404
from .models import Task
@permission_required('myapp.can_close_task', raise_exception=True)
def close_task_view(request, task_id):
task = get_object_or_404(Task, id=task_id)
if not task.is_closed:
task.is_closed = True
task.save()
return render(request, 'task_closed.html', {'task': task})
return render(request, 'task_already_closed.html', {'task': task})
# Или прямая проверка
def some_other_view(request):
if request.user.has_perm('myapp.can_assign_task'):
# Логика для назначения задачи
pass
# ...
Дополнительные возможности:
Для более детального контроля доступа на уровне отдельных объектов (object-level permissions) часто используются сторонние библиотеки, такие как django-guardian. Она позволяет назначать разрешения не только на тип модели, но и на конкретные экземпляры моделей.
Ответ 18+ 🔞
А, ну так, про джанговские разрешения, да? Система, блядь, мощная, как трактор в деревне — если правильно рулить, то всё пашет, а если нет — то сам себя ебнешь в сраку.
Зачем это вообще нужно, спросишь? А чтобы не было, как в том анекдоте: «все могут, а я что, хуже?». Нет, сука, не все. Одному — смотреть, другому — менять, третьему — удалять, а четвёртому вообще нихуя нельзя. Безопасность, понимаешь? Чтобы какой-нибудь Васян из бухгалтерии не взял и не удалил все заказы за 2023 год, потому что «ну я же просто кнопку нажал».
Что там у них есть, эти разрешения:
-
Автоматом прикрученные: Джанга, она умная, блядь. Создал модель — она тебе сразу четыре разрешения на блюдечке: добавить, изменить, удалить и посмотреть. Всё, сиди и распределяй.
-
Свои, кастомные: А если тебе мало? Если тебе нужно, чтобы только избранные могли, например, задачу закрывать или другому юзеру впендюрить? Без проблем, ёпта! Пишешь в модели и всё.
from django.db import models class Task(models.Model): name = models.CharField(max_length=255) is_closed = models.BooleanField(default=False) class Meta: permissions = [ ("can_close_task", "Can close task"), # (кодовое имя, понятное имя для админа) ("can_assign_task", "Can assign task to users"), ] verbose_name = "Задача" verbose_name_plural = "Задачи"Вот, добавил два своих. Теперь можно давать право не просто «менять задачу», а конкретно «закрывать» её. Точечно, блядь!
-
А как проверять-то?
- Спросить у юзера напрямую:
user.has_perm('myapp.can_close_task')— вернётTrueилиFalse. Проще пареной репы. - Вьюхи обернуть: Чтоб не писать в каждой функции проверку, есть декораторы. Навесил
@permission_required— и если у юзера нет нужного пермишена, ему либо отказ, либо, еслиraise_exception=True, вообще ошибку 403 в ебало. - В шаблонах спрятать: Хочешь кнопку «Закрыть задачу» показывать только тем, кто может?
{% if perms.myapp.can_close_task %}— и готово, хитрая жопа.
- Спросить у юзера напрямую:
Вот тебе пример, чтоб вообще всё стало ясно, как божий день:
from django.contrib.auth.decorators import permission_required
from django.shortcuts import render, get_object_or_404
from .models import Task
@permission_required('myapp.can_close_task', raise_exception=True)
def close_task_view(request, task_id):
task = get_object_or_404(Task, id=task_id)
if not task.is_closed:
task.is_closed = True
task.save()
return render(request, 'task_closed.html', {'task': task})
return render(request, 'task_already_closed.html', {'task': task})
# Или вот так, по-простому, в другой вьюхе
def some_other_view(request):
if request.user.has_perm('myapp.can_assign_task'):
# Ну тут логика, чтоб задачу на другого перекинуть
pass
# ...
А что если мало?
А если тебе мало этих общих разрешений на всю модель? Если нужно, чтобы Петя мог редактировать только СВОИ статьи, а чужие — нихуя? Вот тут встроенная система уже пасует, ей на всё похуй. Для такого есть, блядь, отдельные библиотеки, типа django-guardian. Эта штука позволяет привязывать права к КОНКРЕТНОМУ объекту в базе. То есть дать право «менять» не всем статьям, а только статье с id=42. Вот это уже уровень, ёпта! Но это уже совсем другая история, про которую, если захочешь, в другой раз расскажу. А пока — разберись с базовыми, чтоб не было мудацких дыр в доступе.