В предыдущих уроках мы научились регистрировать пользователей, авторизовывать их, работать с профилем и ограничивать доступ по признаку «авторизован / не авторизован». Однако в реальных проектах этого недостаточно.
В проекте cinemahub у нас могут быть разные типы пользователей:
- обычные пользователи, которые только смотрят каталог фильмов;
- модераторы, которые могут добавлять и редактировать фильмы;
- администраторы, которые управляют всеми сущностями проекта.
Для решения этой задачи в Django существует мощный и гибкий механизм разрешений (permissions) и групп (groups).
Цель этого урока — научиться:
- понимать, как Django работает с разрешениями;
- ограничивать доступ к представлениям;
- проверять разрешения в шаблонах;
- использовать группы для управления доступом;
- работать с разрешениями программно;
- диагностировать типичные ошибки.
Откроем админ-панель проекта:
http://127.0.0.1:8000/admin/
Перейдём в раздел Users → Users и откроем любого пользователя на редактирование.
Мы увидим два важных поля:
- Groups — группы, к которым принадлежит пользователь
- User permissions — индивидуальные разрешения пользователя
Важно понимать: Django всегда проверяет разрешения пользователя, объединяя:
- личные разрешения пользователя;
- разрешения всех групп, в которые он входит.
Для каждой модели Django автоматически создаёт четыре базовых разрешения:
| Разрешение | Назначение |
|---|---|
add |
Добавление записей |
change |
Изменение записей |
delete |
Удаление записей |
view |
Просмотр записей |
Модель Movie находится в приложении movies, поэтому Django создаёт следующие разрешения:
movies.add_moviemovies.change_moviemovies.delete_moviemovies.view_movie
Общий формат имени разрешения:
<app_label>.<action>_<modelname>
Предположим, в проекте есть представление для добавления фильма.
Файл: movies/views.py
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import CreateView
from .models import Movie
class MovieCreateView(PermissionRequiredMixin, CreateView):
model = Movie
fields = ['title', 'description', 'year', 'category', 'is_published']
template_name = 'movies/movie_form.html'
success_url = '/'
permission_required = 'movies.add_movie'-
Django проверяет наличие разрешения
movies.add_movie -
Если разрешение есть — страница открывается
-
Если нет:
- авторизованный пользователь получает 403 Forbidden
- неавторизованный пользователь будет перенаправлен на страницу входа
- Зайдите под пользователем без разрешения
- Перейдите на страницу добавления фильма
- Вы увидите ошибку 403
Теперь:
- Зайдите в админку
- Назначьте пользователю разрешение
add movie - Обновите страницу
Страница станет доступной.
Если используется представление-функция, применяется декоратор @permission_required.
Файл: movies/views.py
from django.contrib.auth.decorators import permission_required
from django.http import HttpResponse
@permission_required('movies.view_movie', raise_exception=True)
def movie_contacts(request):
return HttpResponse("Контакты кинопортала Cinemahub")- если
True→ ошибка 403 - если
False(по умолчанию) → редирект на страницу логина
Django автоматически передаёт объект perms во все шаблоны.
{% if perms.movies.change_movie %}
<a href="{% url 'movies:movie_edit' movie.pk %}">
Редактировать фильм
</a>
{% endif %}Если у пользователя нет разрешения — ссылка просто не будет отображаться.
Это особенно важно:
- для UX
- для безопасности
- для предотвращения ошибок доступа
Когда пользователей становится много, назначать разрешения вручную неудобно. В этом случае используются группы.
| Группа | Назначение |
|---|---|
moderator |
Управление фильмами |
editor |
Редактирование описаний |
admin |
Полный доступ |
-
Админка → Groups
-
Создать группу
moderator -
Назначить ей:
add_moviechange_movieview_movie
Теперь достаточно добавить пользователя в группу — и он автоматически получит все права.
Откроем shell:
python manage.py shellfrom django.contrib.auth.models import Group
from django.contrib.auth import get_user_model
User = get_user_model()
user = User.objects.get(username='user1')
group = Group.objects.get(name='moderator')
user.groups.add(group)user.has_perm('movies.add_movie') # True
user.has_perm('movies.delete_movie') # Falseuser.user_permissions.add(permission)
user.user_permissions.remove(permission)
user.user_permissions.clear()Добавление по объекту:
from django.contrib.auth.models import Permission
perm = Permission.objects.get(codename='change_movie')
user.user_permissions.add(perm)Иногда стандартных разрешений недостаточно.
Файл: movies/models.py
class Movie(models.Model):
...
class Meta:
permissions = [
("can_publish_movie", "Can publish movie"),
]После makemigrations и migrate разрешение появится в админке.
Проверка:
user.has_perm('movies.can_publish_movie')users/models.py— связи пользователя с группами и правамиmovies/models.py— кастомные разрешенияmovies/views.py—PermissionRequiredMixinmovies/templates/—permsadmin.py— назначение правmanage.py shell— отладка
- пользователь не перелогинился
- кэш сессии не обновился
- не выполнены
makemigrations/migrate - ошибка в
Meta.permissions
- отсутствует
raise_exception=True - неверное имя разрешения
Ограничьте доступ к редактированию фильма так, чтобы только пользователи с разрешением change_movie могли открывать страницу. Использовать PermissionRequiredMixin с movies.change_movie.
Создайте группу editor, которая может только редактировать и просматривать фильмы.Назначить change_movie и view_movie, добавить пользователя в группу.
Скройте кнопку удаления фильма, если у пользователя нет соответствующего разрешения. Использовать perms.movies.delete_movie в шаблоне.
- Какие стандартные разрешения создаёт Django?
- Чем отличаются группы от индивидуальных разрешений?
- Как проверить разрешение пользователя в коде?
- Как ограничить доступ к CBV?
- Что делает
raise_exception=True? - Где хранятся кастомные разрешения?
- Почему пользователь может не получить доступ сразу?
- Как проверить разрешения в шаблоне?