В уроке 6 по созданию API на Django REST Framework, мы рассмотрим миксины DRF, они необходимы для создания гибкости в представлениях Django.
В прошлом уроке мы рассмотрели расширенные CRUD запросы: Django REST Framework создание API: Урок 5, расширенные CRUD запросы на основе классов
А теперь приступим к написанию универсального представления с помощью миксирования:
modules/blog/views/articles.py
from rest_framework import generics
class ArticleMixinView(generics.GenericAPIView):
pass
Если мы рассмотрим класс GenericAPIView, то увидим следующие параметры:
queryset
- набор запросов, из которого мы будем возвращать данные для просмотра.serializer_class
- класс сериализатора, который мы будем использовать для проверки и десериализации входных данных.lookup_field
- поле, по которому мы будем находить один экземпляр модели.lookup_url_kwarg
- аргумент ключевого слова URL, который следует использовать для поиска объекта, использует тот же, что lookup_field.pagination_class
- класс разбивки результатов на страницы, рассмотрим в последующих уроках.filter_backends
- список классов фильтров сервера, для фильтрации набора запросов.
Есть также и базовые методы:
get_queryset()
get_object()
get_serializer_class()
filter_queryset()
Микширование:
Добавим ListModelMixin
для метода get()
, данный метод позволяет нам получить список, например статей, поэтому заполним также и параметры
modules/blog/views/articles.py
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics, mixins
class ArticleMixinView(generics.GenericAPIView, mixins.ListModelMixin):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get(self, request, *args, **kwargs):
# HTTP -> GET метод
# self.list из ListModelMixin
return self.list(request, *args, **kwargs)
Пояснение:
self.list
мы берем для списка получаемых экземпляров, получаемых из queryset с помощью:ListModelMixin
Давайте попробуем испытать данное представление.
Необязательно для тех, кто делает все в файле views.py.
Добавлю импорты в __init__.py:
from modules.blog.views.articles import ArticleMixinView
__all__ = '__all__'
И добавлю обработку нашего представления в urls.py:
modules/blog/urls.py
from django.urls import path
from modules.blog import views
urlpatterns = [
path('articles/', views.ArticleMixinView.as_view(), name='api_articles_list'),
]
Попробуем отправить GET и POST запрос на получение списка статей по ссылке: http://127.0.0.1:8000/api/articles/


С помощью микширования мы можем поменять, чтобы POST запрос работал и получал список:
class ArticleMixinView(generics.GenericAPIView, mixins.ListModelMixin):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def post(self, request, *args, **kwargs):
# HTTP -> POST метод
# self.list из ListModelMixin
return self.list(request, *args, **kwargs)
И проверяем:

Как видите, мы получили список с помощью POST запроса. Но в этот раз у нас не работает GET запрос. Давайте пойдем дальше и дополним метод get()
:
modules/blog/views/articles.py
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics, mixins
class ArticleMixinView(generics.GenericAPIView, mixins.ListModelMixin, mixins.RetrieveModelMixin):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'slug'
def get(self, request, *args, **kwargs):
# HTTP -> GET метод
print(args, kwargs)
# Если мы передали slug в url, то получаем его из параметров
slug = kwargs.get('slug')
# И если slug существует, возвращаем один экземпляр
if slug is not None:
# self.retrieve из RetrieveModelMixin
return self.retrieve(request, *args, **kwargs)
# self.list из ListModelMixin
return self.list(request, *args, **kwargs)
Пояснение:
self.retrieve
мы берем для единичного экземпляра, который хотим получить с помощью заданного slug, все это работает с миксином:RetrieveModelMixin
- Выводимые данные в процессе отработки представления
print(args, kwargs)
:>>> () {'slug': 'test-article-4'}
Добавим обработку представления в urls.py:
modules/blog/urls.py
from django.urls import path
from modules.blog import views
urlpatterns = [
path('articles/', views.ArticleMixinView.as_view(), name='api_articles_list'),
path('articles/<str:slug>/', views.ArticleMixinView.as_view(), name='api_articles_detail')
]
Проверим GET запрос отправив его на страницу, например: http://127.0.0.1:8000/api/articles/test-article-4/

Отлично, все работает. Также у нас остается возможность по этому же представлению обратиться к списку статей.
Давайте дополним наше представление возможностью добавлять статьи:
modules/blog/views/articles.py
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics, mixins
class ArticleMixinView(generics.GenericAPIView, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'slug'
def get(self, request, *args, **kwargs):
# HTTP -> GET метод
print(args, kwargs)
# Если мы передали slug в url, то получаем его из параметров
slug = kwargs.get('slug')
# И если slug существует, возвращаем один экземпляр
if slug is not None:
# self.retrieve из RetrieveModelMixin
return self.retrieve(request, *args, **kwargs)
# self.list из ListModelMixin
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
# HTTP -> POST метод
# self.create из CreateModelMixin
return self.create(request, *args, **kwargs)
Пояснение:
self.create
мы берем для создания экземпляра с помощью:CreateModelMixin
- Также нам доступен метод вызываем при добавлении экземпляра с помощью
CreateModelMixin
:perform_create(self, serializer)
Попробуем отправить POST запрос с данными новой статьи по ссылке: http://127.0.0.1:8000/api/articles/
Отправляемые JSON данные:
{
"title": "Тестовая статья номер 5",
"slug": "test-article-5",
"short_description": "Краткое описание статьи 5",
"full_description": "Полное описание статьи 5",
"category": 1
}
Смотрим результат:

Как видите, статью мы добавили. Пойдем дальше и добавим больше методов в наше универсальное представление:
Добавим возможность обновления статьи:
modules/blog/views/articles.py
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics, mixins
class ArticleMixinView(generics.GenericAPIView, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'slug'
def get(self, request, *args, **kwargs):
# HTTP -> GET метод
print(args, kwargs)
# Если мы передали slug в url, то получаем его из параметров
slug = kwargs.get('slug')
# И если slug существует, возвращаем один экземпляр
if slug is not None:
# self.retrieve из RetrieveModelMixin
return self.retrieve(request, *args, **kwargs)
# self.list из ListModelMixin
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
# HTTP -> POST метод
# self.create из CreateModelMixin
return self.create(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
# HTTP -> PUT метод
# self.update из UpdateModelMixin
return self.update(request, *args, **kwargs)
def patch(self, request, *args, **kwargs):
# HTTP -> PATCH метод
# self.partial_update из UpdateModelMixin
return self.partial_update(request, *args, **kwargs)
Пояснение:
self.update
иself.partial_update
мы берем для обновления экземпляра с помощью:UpdateModelMixin
- Также нам доступен метод вызываем при обновления экземпляра с помощью
UpdateModelMixin
:perform_update(self, serializer)
Попробуем обновить статью, отправив запрос PUT на страницу: http://127.0.0.1:8000/api/articles/test-article-5/

Отлично, и как завершающий этот урок, мы добавим миксин для удаления экземпляра:
modules/blog/views/articles.py
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics, mixins
class ArticleMixinView(
generics.GenericAPIView,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
mixins.CreateModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'slug'
def get(self, request, *args, **kwargs):
# HTTP -> GET метод
print(args, kwargs)
# Если мы передали slug в url, то получаем его из параметров
slug = kwargs.get('slug')
# И если slug существует, возвращаем один экземпляр
if slug is not None:
# self.retrieve из RetrieveModelMixin
return self.retrieve(request, *args, **kwargs)
# self.list из ListModelMixin
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
# HTTP -> POST метод
# self.create из CreateModelMixin
return self.create(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
# HTTP -> PUT метод
# self.update из UpdateModelMixin
return self.update(request, *args, **kwargs)
def patch(self, request, *args, **kwargs):
# HTTP -> PATCH метод
# self.partial_update из UpdateModelMixin
return self.partial_update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
# HTTP -> DELETE метод
# self.delete из DestroyModelMixin
return self.destroy(request, *args, **kwargs)
Пояснение:
self.
destroy
мы берем для удаления экземпляра с помощью:DestroyModelMixin
- Также нам доступен метод вызываем при удалении экземпляра с помощью
DestroyModelMixin
:perform_destroy(self, instance)
Попробуем удалить статью, отправив запрос DELETE на страницу: http://127.0.0.1:8000/api/articles/test-article-5/

Отлично, как видите, статья была удалена. Все это с помощью одного представления созданного с помощью миксинов, а также обращения с различными запросами: GET, POST, PUT, DELETE