Использование миксинов в работе с представлениями Django
Миксины
Миксин — небольшой класс, который несёт одну порцию поведения и подмешивается к другим классам. Сам по себе он не используется. Все CBV Django собраны из миксинов: например, UpdateView = SingleObjectTemplateResponseMixin + BaseUpdateView, а тот — ModelFormMixin + ProcessFormView.
Порядок наследования определяет MRO (Method Resolution Order) — Python ищет метод слева направо:
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
...
print(ArticleUpdateView.__mro__)
# ArticleUpdateView → LoginRequiredMixin → AccessMixin → UpdateView → ...
Поэтому миксины пишут слева: их dispatch() выполнится первым и решит, пускать ли запрос дальше через super().dispatch().
Встроенные миксины доступа
| Миксин | Что проверяет |
|---|---|
LoginRequiredMixin |
Пользователь вошёл |
UserPassesTestMixin |
Ваш метод test_func() вернул True |
PermissionRequiredMixin |
У пользователя есть права permission_required |
AccessMixin |
Базовый: атрибуты login_url, permission_denied_message, raise_exception и метод handle_no_permission() |
handle_no_permission(): анонима отправит на login_url, вошедшему без прав вернёт 403.
class ArticleDeleteView(PermissionRequiredMixin, DeleteView):
permission_required = "blog.delete_article"
Свой миксин: только автор
Закроем дыру из прошлого урока. modules/services/mixins.py:
from django.contrib import messages
from django.contrib.auth.mixins import AccessMixin
from django.shortcuts import redirect
class AuthorRequiredMixin(AccessMixin):
"""Доступ только автору объекта или персоналу."""
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
if request.user == self.get_object().author or request.user.is_staff:
return super().dispatch(request, *args, **kwargs)
messages.info(request, "Изменение и удаление статьи доступно только автору")
return redirect("home")
return self.handle_no_permission()
Тот же результат через UserPassesTestMixin:
class AuthorRequiredMixin(LoginRequiredMixin, UserPassesTestMixin):
def test_func(self):
obj = self.get_object()
return self.request.user == obj.author or self.request.user.is_staff
Подключаем:
from django.contrib.messages.views import SuccessMessageMixin
from modules.services.mixins import AuthorRequiredMixin
class ArticleUpdateView(AuthorRequiredMixin, SuccessMessageMixin, UpdateView):
model = Article
template_name = "blog/articles_update.html"
form_class = ArticleUpdateForm
success_message = "Статья обновлена"
...
Теперь чужую статью не открыть даже по прямой ссылке.
Удаление статьи
С тем же миксином — DeleteView:
from django.urls import reverse_lazy
from django.views.generic import DeleteView
class ArticleDeleteView(AuthorRequiredMixin, DeleteView):
model = Article
success_url = reverse_lazy("home")
context_object_name = "article"
template_name = "blog/articles_delete.html"
path("articles/<str:slug>/delete/", ArticleDeleteView.as_view(), name="articles_delete"),
GET покажет страницу подтверждения, POST удалит статью.
Миксин для гостей
Вошедшему пользователю незачем видеть страницы входа и регистрации:
from django.contrib.auth.mixins import UserPassesTestMixin
from django.shortcuts import redirect
class UserIsNotAuthenticated(UserPassesTestMixin):
def test_func(self):
return not self.request.user.is_authenticated
def handle_no_permission(self):
messages.info(self.request, "Вы уже авторизованы")
return redirect("home")
Его подключим к представлениям регистрации и входа в следующем уроке.
Миксин с общим контекстом
Миксины годятся не только для доступа. Повторяющийся get_context_data с заголовком:
class TitleMixin:
title = None
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = self.title
return context
class ArticleCreateView(TitleMixin, LoginRequiredMixin, CreateView):
title = "Добавление статьи"
Итог
- Миксин — класс с одной порцией поведения; подмешивается слева от базового представления.
- Встроенные:
LoginRequiredMixin,UserPassesTestMixin,PermissionRequiredMixin, базовыйAccessMixin. - Свои миксины:
AuthorRequiredMixinдля редактирования и удаления,UserIsNotAuthenticatedдля гостевых страниц. - Права проверяются во view — скрытая кнопка в шаблоне не защищает.
Практика решено 0 из 6
Что такое миксин (mixin)?
Напишите AuthorRequiredMixin(AccessMixin): в dispatch пропускайте запрос дальше, только если
пользователь вошёл и является автором объекта (request.user == self.get_object().author)
или суперпользователем (request.user.is_staff). Иначе — return self.handle_no_permission().
from django.contrib.auth.mixins import AccessMixin
class AuthorRequiredMixin(AccessMixin):
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated:
if request.user == self.get_object().author or request.user.is_staff:
return super().dispatch(request, *args, **kwargs)
return self.handle_no_permission()
Подключите миксин к представлению: ArticleUpdateView должен наследовать
AuthorRequiredMixin, SuccessMessageMixin, UpdateView (в этом порядке).
class ArticleUpdateView(AuthorRequiredMixin, SuccessMessageMixin, UpdateView):
model = Article
Почему миксины пишут левее базового представления (class V(LoginRequiredMixin, UpdateView))?
Напишите миксин UserIsNotAuthenticated(UserPassesTestMixin) для страниц входа и регистрации:
метод test_func возвращает True, только если пользователь не вошёл
(not self.request.user.is_authenticated).
from django.contrib.auth.mixins import UserPassesTestMixin
class UserIsNotAuthenticated(UserPassesTestMixin):
def test_func(self):
return not self.request.user.is_authenticated
Какие миксины доступа есть в django.contrib.auth.mixins?
Войдите, чтобы отмечать пройденные уроки.