В уроке 4 по созданию API на Django REST Framework, мы рассмотрим создание запросов (добавления, получения, изменения, удаления) для нашей модели Статьи на основе классов.
В прошлом уроке мы рассмотрели два запроса основанных на функциях: запрос GET и POST: Django REST Framework создание API: Урок: 3, сериализация данных на основе функций
Перейдем к созданию запросов, создавать мы все также будет во views/articles.py
Запрос на получение статей (ListAPIView
):
modules/blog/views/articles.py
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics
class ArticleListAPIView(generics.ListAPIView):
"""
Контроллер для просмотра списка статей (Только GET)
"""
queryset = Article.objects.all()
serializer_class = ArticleSerializer
Пояснение:
queryset
- передаем список статей (Article.objects.all()
)serializer_class
- передаем наш сериалайзер, что создали в третьем уроке для модели статьи.- Также есть дополнительные методы, о них можете почитать в официальной документации: Generic views - Django REST framework
Необязательно для тех, кто делает все в файле views.py. Добавлю импорты в __init__.py:
modules/blog/views/__init__.py
from modules.blog.views.articles import ArticleListAPIView
__all__ = '__all__'
Добавлю обработку нашего контроллера в urls.py
modules/blog/urls.py
from django.urls import path
from modules.blog import views
urlpatterns = [
path('articles/', views.ArticleListAPIView.as_view(), name='api_articles_list'),
]
Проверю запрос на получение списка статей, отправив запрос на страницу: http://127.0.0.1:8000/api/articles/


Запрос на добавление статьи (CreateAPIView
):
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics
from django.template.defaultfilters import slugify
class ArticleCreateAPIView(generics.CreateAPIView):
"""
Контроллер для добавления статьи (Только POST)
"""
serializer_class = ArticleSerializer
def perform_create(self, serializer):
"""
Метод создания статьи в БД
"""
# Если не задан слаг, генерируем его из заголовка
slug = serializer.validated_data.get('slug')
if slug is None:
slug = slugify(serializer.validated_data.get('title'))
serializer.save(slug=slug)
print(serializer.validated_data)
return super().perform_create(serializer)
Пояснение:
serializer_class
- передаем наш сериалайзер, что создали в третьем уроке для модели статьи.perform_create
- метод, в котором мы можем задавать различные параметры для создаваемого объекта, аналогично методу сохранения в CreateView с формами.- В примере
perform_create
показан метод генерацииslug
при его отсутствии с помощью слагификации заголовка. - Информация из
print(serializer.validated_data)
:OrderedDict([('title', 'My test Article'), ('short_description', 'Тестовая статья, отправленная через CreateAPIView'), ('full_description', 'Тестовая статья, отправленная через CreateAPIView'), ('category', <Category: Python>)])
Добавлю импорты в __init__.py
from modules.blog.views.articles import ArticleListAPIView, ArticleCreateAPIView
__all__ = '__all__'
Добавлю обработку нашего контроллера в urls.py
modules/blog/urls.py
from django.urls import path
from modules.blog import views
urlpatterns = [
path('articles/', views.ArticleListAPIView.as_view(), name='api_articles_list'),
path('articles/create/', views.ArticleCreateAPIView.as_view(), name='api_articles_create'),
]
Проверю POST запрос на создание статьи, отправив запрос на страницу: http://127.0.0.1:8000/api/articles/create/

Все отлично, отправил главную информацию в виде заголовка, описаний и категории, остальное автоматически отработало в сериализаторе и в нашей модели.
Запрос на получение одного экземпляра статьи (RetrieveAPIView
):
modules/blog/views/articles.py
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics
class ArticleRetrieveAPIView(generics.RetrieveAPIView):
"""
Контроллер для просмотра статьи (Только GET)
"""
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'slug'
Пояснение:
queryset
- передаем список статей (Article.objects.all()
)serializer_class
- передаем наш сериалайзер, что создали в третьем уроке для модели статьи.lookup_field
- поле, по которому будет получаться статья. Я передаюslug
.
Добавлю импорты в __init__.py:
modules/blog/views/__init__.py
from modules.blog.views.articles import ArticleListAPIView, ArticleCreateAPIView, ArticleRetrieveAPIView
__all__ = '__all__'
Добавлю обработку нашего контроллера в urls.py
modules/blog/urls.py
from django.urls import path
from modules.blog import views
urlpatterns = [
path('articles/', views.ArticleListAPIView.as_view(), name='api_articles_list'),
path('articles/create/', views.ArticleCreateAPIView.as_view(), name='api_articles_create'),
path('articles/<str:slug>/', views.ArticleRetrieveAPIView.as_view(), name='api_articles_detail'),
]
Проверю GET запрос на получение одной статьи, отправив запрос на страницу со статьей созданной при запросе CreateAPIView
: http://127.0.0.1:8000/api/articles/my-test-article/


Отлично, все работает. Теперь перейдем к запросу для изменения статьи.
Запрос на редактирование статьи (UpdateAPIView
):
modules/blog/views/articles.py
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics
class ArticleUpdateAPIView(generics.UpdateAPIView):
"""
Контроллер для редактирования статьи (Только PUT)
"""
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'slug'
def perform_update(self, serializer):
"""
Метод обновления статьи в БД
"""
instance = serializer.save()
print(instance)
return super().perform_update(serializer)
Пояснение:
queryset
- передаем список статей (Article.objects.all()
)serializer_class
- передаем наш сериалайзер, что создали в третьем уроке для модели статьи.lookup_field
- поле, по которому будет получаться статья. Я передаюslug
.perform_update
- метод, в котором мы можем управлять параметрами объекта.
Добавлю импорты в __init__.py:
modules/blog/views/__init__.py
from modules.blog.views.articles import ArticleListAPIView, ArticleCreateAPIView, ArticleRetrieveAPIView, ArticleUpdateAPIView
__all__ = '__all__'
Добавлю обработку нашего контроллера в urls.py
modules/blog/urls.py
from django.urls import path
from modules.blog import views
urlpatterns = [
path('articles/', views.ArticleListAPIView.as_view(), name='api_articles_list'),
path('articles/create/', views.ArticleCreateAPIView.as_view(), name='api_articles_create'),
path('articles/<str:slug>/', views.ArticleRetrieveAPIView.as_view(), name='api_articles_detail'),
path('articles/<str:slug>/update/', views.ArticleUpdateAPIView.as_view(), name='api_articles_detail'),
]
Проверю PUT запрос на редактирование одной статьи, отправив запрос на страницу со статьей созданной при запросе CreateAPIView
: http://127.0.0.1:8000/api/articles/my-test-article/update/


На втором скриншоте как Вы видите, недоступен GET запрос, но это мы исправим уже в другом уроке, где рассмотрим другие смешанные виды контроллеров на основе классов.
И перейдем к запросу на удаление статьи (DestroyAPIView
)
modules/blog/views/articles.py
from modules.blog.models import Article
from modules.blog.serializers import ArticleSerializer
from rest_framework import generics
class ArticleDestroyAPIView(generics.DestroyAPIView):
"""
Контроллер для удаления статьи (Только DELETE)
"""
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'slug'
Пояснение:
queryset
- передаем список статей (Article.objects.all()
)serializer_class
- передаем наш сериалайзер, что создали в третьем уроке для модели статьи.lookup_field
- поле, по которому будет получаться статья. Я передаюslug
.
Добавлю импорты в __init__.py:
modules/blog/views/__init__.py
from modules.blog.views.articles import ArticleListAPIView, ArticleCreateAPIView, ArticleRetrieveAPIView, ArticleUpdateAPIView, ArticleDestroyAPIView
__all__ = '__all__'
Добавлю обработку нашего контроллера в urls.py
modules/blog/urls.py
from django.urls import path
from modules.blog import views
urlpatterns = [
path('articles/', views.ArticleListAPIView.as_view(), name='api_articles_list'),
path('articles/create/', views.ArticleCreateAPIView.as_view(), name='api_articles_create'),
path('articles/<str:slug>/', views.ArticleRetrieveAPIView.as_view(), name='api_articles_detail'),
path('articles/<str:slug>/update/', views.ArticleUpdateAPIView.as_view(), name='api_articles_detail'),
path('articles/<str:slug>/delete/', views.ArticleDestroyAPIView.as_view(), name='api_articles_delete'),
]
Проверю DELETE запрос на удаление одной статьи, отправив запрос на страницу со статьей созданной при запросе CreateAPIView
: http://127.0.0.1:8000/api/articles/my-test-article/delete/

И как видите, на скриншоте выше, статья удалилась со статусом 204.
Проверим весь список:

Отлично. Мы рассмотрели основные CRUD запросы в DRF, но это ещё не все. В следующем уроке мы рассмотрим более интересные контроллеры, которые позволят одновременно как получать что-то, так и сразу редактировать при отправке разных запросов.