Использование миксинов в работе с представлениями Django

⏱ 30 мин · 🧩 заданий: 6

Миксины

Миксин — небольшой класс, который несёт одну порцию поведения и подмешивается к другим классам. Сам по себе он не используется. Все 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

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Один вариант ответа

Что такое миксин (mixin)?

Задание 2 Написать код

Напишите AuthorRequiredMixin(AccessMixin): в dispatch пропускайте запрос дальше, только если пользователь вошёл и является автором объекта (request.user == self.get_object().author) или суперпользователем (request.user.is_staff). Иначе — return self.handle_no_permission().

Задание 3 Написать код

Подключите миксин к представлению: ArticleUpdateView должен наследовать AuthorRequiredMixin, SuccessMessageMixin, UpdateView (в этом порядке).

Задание 4 Один вариант ответа

Почему миксины пишут левее базового представления (class V(LoginRequiredMixin, UpdateView))?

Задание 5 Написать код

Напишите миксин UserIsNotAuthenticated(UserPassesTestMixin) для страниц входа и регистрации: метод test_func возвращает True, только если пользователь не вошёл (not self.request.user.is_authenticated).

Задание 6 Несколько вариантов

Какие миксины доступа есть в django.contrib.auth.mixins?

Войдите, чтобы отмечать пройденные уроки.