Перейти к основному содержимому

Первая программа на Django REST Framework

Разработчику

Play ITЗагрузка интерактивного демо…


Первая программа на Django REST Framework

От HTML к JSON

Первая программа на Django заканчивается HTML-страницей в браузере и админкой /admin. В реальных проектах тот же бэкенд часто отдаёт JSON — текстовый формат, который удобно читать JavaScript, мобильным приложениям и другим сервисам.

Пример JSON-ответа:

[
{"id": 1, "text": "Купить молоко", "created_at": "2026-05-26T10:00:00Z"}
]

Django REST Framework (DRF) — надстройка над Django, которая превращает модели БД в такой API с минимумом кода.

Если проект ещё не на Django и нужен только API — смотрите FastAPI. DRF выигрывает, когда уже есть Django — ORM, auth, админка, одна кодовая база.


REST без DRF

Для узкого API достаточно ядра Django: JsonResponse, django.core.serializers или ручной dict. Пример списка:

from django.http import JsonResponse
from django.views.decorators.http import require_GET
from .models import Note

@require_GET
def note_list_api(request):
data = [
{'id': n.id, 'text': n.text, 'created_at': n.created_at.isoformat()}
for n in Note.objects.all()[:50]
]
return JsonResponse(data, safe=False)

Минусы по сравнению с DRF — нет browsable API, валидации тела запроса "из коробки", единообразной пагинации и прав. DRF окупается, когда эндпоинтов много. Подробнее — Справочник по Django.


Словарь DRF

ТерминПростыми словами
APIНабор URL, по которым клиент получает и меняет данные
СериализаторКласс: "какие поля модели уйти в JSON" + проверка входа
ViewSetОдин класс с методами list, create, retrieve, update, destroy
RouterАвтоматически создаёт URL вроде /api/notes/ и /api/notes/1/
Browsable APIHTML-страница DRF для ручной отладки POST/GET в браузере
QuerySet"Запрос к БД", который Django выполнит позже: Note.objects.all()

Что получится

Метод HTTPURLДействие
GET/api/notes/Список заметок
POST/api/notes/Создать: тело {"text": "..."}
GET/api/notes/1/Одна заметка с id=1
PUT/PATCH/api/notes/1/Изменить (ModelViewSet умеет)
DELETE/api/notes/1/Удалить

Слэш в конце URL (/notes/) — важная деталь Django: без него часто будет редирект 301.


Подготовка проекта

Продолжите проект из Первая программа на Django или создайте новый:

python -m venv venv
# Windows — venv\Scripts\activate
# macOS/Linux — source venv/bin/activate

pip install django djangorestframework
django-admin startproject notes_project
cd notes_project
python manage.py startapp notes

Разбор: команды готовят окружение, устанавливают DRF и создают структуру проекта с приложением notes.

startproject — каркас с settings.py и urls.py. startapp notes — приложение с models.py, куда кладут модель "Заметка".


Регистрация в settings.py

INSTALLED_APPS = [
# ...
'rest_framework',
'notes',
]

Разбор: 'rest_framework' подключает инструменты DRF, а 'notes' регистрирует ваше приложение в жизненном цикле Django.

Django подхватывает только приложения из этого списка. Без 'rest_framework' импорты from rest_framework import ... упадут с ModuleNotFoundError.


Модель — что хранится в БД

notes/models.py:

from django.db import models

class Note(models.Model):
text = models.CharField(max_length=500)
created_at = models.DateTimeField(auto_now_add=True)

def __str__(self):
return self.text[:50]

Разбор — Note описывает таблицу заметок, auto_now_add ставит время создания автоматически, __str__ делает объект читаемым в админке.

ПолеСмысл
CharField(max_length=500)Строка до 500 символов
DateTimeField(auto_now_add=True)Время создания ставится один раз при INSERT
__str__Как запись выглядит в админке

Создание таблиц в БД:

python manage.py makemigrations # файл миграции в git
python manage.py migrate # применить к SQLite/PostgreSQL

Миграция — версионированное изменение схемы. Вы изменили модель — снова makemigrations + migrate.


Сериализатор — мост модель ↔ JSON

notes/serializers.py:

from rest_framework import serializers
from .models import Note

class NoteSerializer(serializers.ModelSerializer):
class Meta:
model = Note
fields = ['id', 'text', 'created_at']
read_only_fields = ['id', 'created_at']

Разбор: сериализатор превращает модель в JSON и обратно, а read_only_fields не даёт клиенту подменять серверные поля.

Разбор:

  • ModelSerializer — DRF сам построит поля по модели Note.
  • fields — белый список: в JSON попадут только эти ключи.
  • read_only_fields — клиент при POST не может подставить свой id или created_at; сервер выставит сам.

При POST с пустым text DRF вернёт 400 с описанием полей — отдельный if not text в каждом view писать не нужно.

Пример ошибки:

{"text": ["This field may not be blank."]}

ViewSet — вся CRUD-логика в одном классе

notes/views.py:

from rest_framework import viewsets
from .models import Note
from .serializers import NoteSerializer

class NoteViewSet(viewsets.ModelViewSet):
queryset = Note.objects.all().order_by('-created_at')
serializer_class = NoteSerializer

Разбор — ModelViewSet даёт готовый CRUD, queryset определяет набор и сортировку данных, serializer_class задаёт формат входа и выхода.

АтрибутСмысл
querysetОткуда брать объекты для list/retrieve/update/delete
order_by('-created_at')Сначала новые заметки
ModelViewSetВключает list, create, retrieve, update, partial_update, destroy

Раньше в "голом" Django писали отдельную функцию на каждое действие. ViewSet группирует их по ресурсу Note.


Router — автоматические URL

notes_project/urls.py:

from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from notes.views import NoteViewSet

router = DefaultRouter()
router.register('notes', NoteViewSet, basename='note')

urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
]

Разбор: DefaultRouter автоматически создаёт URL для списка и элемента ресурса, а префикс api/ отделяет API от остальных маршрутов.

router.register('notes', ...) создаёт маршруты:

  • GET/POST/api/notes/
  • GET/PUT/PATCH/DELETE/api/notes/<pk>/

basename='note' — имя для reverse в тестах (reverse('note-list')).


Запуск и проверка

python manage.py runserver

В браузере (Browsable API)

Откройте http://127.0.0.1:8000/api/notes/ — форма DRF: можно отправить POST с полем text без Postman.


curl — как это видит скрипт

Список:

curl http://127.0.0.1:8000/api/notes/

Создание:

curl -X POST http://127.0.0.1:8000/api/notes/ \
-H "Content-Type: application/json" \
-d "{\"text\": \"Первая заметка через DRF\"}"

Разбор — -X POST выбирает метод создания, Content-Type указывает JSON-формат, -d передаёт тело запроса.

Часть командыСмысл
-X POSTМетод HTTP
Content-Type: application/jsonТело — JSON
-d "{...}"Тело запроса

Ответ при успехе — 201 Created и JSON с id, text, created_at.


Разрешения (важно для production)

По умолчанию настройки DRF могут требовать авторизацию. Для локальной отладки иногда явно разрешают всем:

REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
],
}

Разбор: глобальная настройка разрешений открывает доступ без авторизации; в боевом API её обычно меняют на IsAuthenticated.

Для боевого API замените на IsAuthenticated и подключите сессии Django, токены или JWT (djangorestframework-simplejwt). Иначе любой в интернете сможет читать и удалять ваши данные.


Как DRF связан с обычным Django

СлойОбычный Django (3011)DRF
Данныеmodels.ModelТа же модель
ОтветHTML-шаблонJSON через сериализатор
Вход формыrequest.POSTJSON в request.data
URLpath('...', view)Router + ViewSet

Фронт на React делает fetch('/api/notes/') и рисует список без серверного HTML.


Частые ошибки

СимптомПричинаРешение
404 на /api/notesНет завершающего /Запрос на /api/notes/
Пустой список после POSTPOST на неверный URL или 400Смотреть тело ответа и статус
ModuleNotFoundError: rest_frameworkНе в INSTALLED_APPSДобавить приложение
403 ForbiddenСтрогие permissionsAllowAny локально или login

Что попробовать дальше

  1. SearchFilterGET /api/notes/?search=молоко.
  2. PageNumberPagination — постраничный список в REST_FRAMEWORK.
  3. Сравнить тот же сценарий "заметки" с Flask и FastAPI.
  4. Тесты API — pytest + APIClient из DRF.

Связанные материалы


Основа по протоколу

Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.


Три слоя DRF

  1. Модель — что хранится в БД.
  2. Сериализатор — форма данных в JSON.
  3. ViewSet и Router — URL и HTTP-методы.

Правка структуры — в модели, формата ответа — в сериализаторе, доступа — во view и permissions.


Минимальные улучшения для реального проекта

Сразу после первого рабочего эндпойнта стоит добавить три практики:

  • Фильтрация и поиск для списков (?search= и фильтры по полям).
  • Пагинация для длинных списков, чтобы не отдавать тысячи записей одним ответом.
  • Явные коды ошибок с понятными сообщениями для клиента.

Базовая настройка в settings.py:

REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
}

Так API быстрее масштабируется и остаётся удобным для фронтенда и мобильных клиентов.


Типичный путь развития API

После CRUD-основы проект обычно растёт в таком порядке:

  1. Авторизация (SessionAuth, токены или JWT).
  2. Права (IsAuthenticated, объектные permissions).
  3. Версионирование API (/api/v1/...).
  4. Автотесты контрактов и бизнес-правил.
  5. Документация OpenAPI/Swagger.

Полезно сравнивать этот путь с альтернативами:


В подборках

Статья входит в тематические подборки и блок "С чего начать?" на главной. Соседние шаги того же маршрута:

Первые шаги (маршрут подборки) — Первая программа на Django, Первая программа на Tkinter, Первая программа на Next.js, Первая программа на PyQt6, Первая программа на Ext JS, Первая программа на Flask.