Как реализована система разрешений (permissions) в Django?

«Как реализована система разрешений (permissions) в Django?» — вопрос из категории Django, который задают на 10% собеседований Python Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В 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. Она позволяет назначать разрешения не только на тип модели, но и на конкретные экземпляры моделей.