Приветствую вас!

Сегодня мы погрузимся в процесс создания собственного API на Django с использованием мощного инструмента — Django REST Framework (DRF). Этот фреймворк предоставляет полный набор инструментов для разработки API: маршрутизация, сериализация данных, обработка запросов и формирование ответов. DRF значительно упрощает взаимодействие с клиентами через HTTP, поддерживая такие методы, как GET, POST, PUT и DELETE.

Однако, в отличие от FastAPI, Django REST Framework не включает встроенный инструмент для автодокументирования API. Мы легко решим эту задачу, воспользовавшись расширением drf‑spectacular, которое генерирует спецификации API в формате OpenAPI 3.0. Это позволит интегрировать интерфейсы, такие как Swagger и Redoc, для удобного тестирования и наглядной визуализации документации.

Чем сегодня займемся?

Мы создадим API, который будет обладать следующими возможностями:

  • Регистрация новых пользователей

  • Получение информации о пользователе по его ID

  • Просмотр списка всех пользователей

  • Удаление пользователя по ID

  • Удаление всех пользователей

После этого мы подключим к нашему приложению drf-spectacular, что позволит автоматически генерировать документацию. Я покажу, как буквально за пару минут настроить и Swagger, и Redoc для вашего API. Более того, вы увидите, как легко добавить собственные описания и комментарии в документацию, делая её еще более информативной.

После завершения разработки мы развернем проект на платформе Amvera Cloud, что займет всего несколько минут. Платформа предоставит бесплатный домен и упростит процесс деплоя. Для этого нужно будет создать файл с настройками (я предоставлю код), а затем загрузить его вместе с файлами Django на Amvera через GIT или сайт платформы. Amvera автоматически соберет и запустит приложение на выделенном домене.

Готовы к старту? Приступаем к подготовке!

Подготовка

Для того чтобы вы могли повторить мои шаги, на вашем компьютере должен быть установлен Python. Скачать его можно с официального сайта Python.

Также, для удобства разработки, стоит использовать IDE. В моем случае это будет PyCharm, но вы можете выбрать любой удобный вам инструмент.

Создание проекта для API

Так как мы будем использовать несколько библиотек, создадим файл requirements.txt для управления зависимостями. Вот пример его содержимого:

Django==5.1.1
djangorestframework==3.15.2
drf-spectacular==0.27.2
drf-spectacular-sidecar==2024.7.1
gunicorn==20.1.0

Объяснение библиотек:

  • Django 5.1.1: Основной фреймворк для разработки веб-приложений на Python.

  • djangorestframework 3.15.2: Инструменты для создания REST API в Django.

  • drf-spectacular 0.27.2: Генерация документации для API, созданных с помощью djangorestframework.

  • drf-spectacular-sidecar 2024.7.1: Дополнительные ресурсы для drf-spectacular, такие как Swagger UI.

  • gunicorn 20.1.0: WSGI-сервер для деплоя приложения.

Установка зависимостей

Для установки зависимостей используем команду:

pip install -r requirements.txt

Создание Django-проекта

Создадим новый Django-проект. Я назову его myproject, но имя может быть любым:

django-admin startproject myproject

Затем перейдём в созданную папку проекта:

cd myproject

Сейчас мы находимся в директории с файлом manage.py - это корень проекта. Все новые команды, включая создание приложений, выполнение миграций базы данных и запуск сервера, будем выполнять из этой директории через терминал. Пожалуйста, будьте внимательны!

Теперь создадим приложение, которое будет содержать наш API. Я назову его users, вы можете выбрать любое название:

python manage.py startapp users

После этого, переместите файл requirements.txt в корень проекта (на один уровень с файлом manage.py). Это необходимо для удобства на этапе деплоя.

У вас должна получиться похожая структура проекта.
У вас должна получиться похожая структура проекта.

В дальнейшем я буду называть пакет myproject (папка с файлом init.py) «конфигурационным пакетом», а пакет users – «пакетом API».

Настройка проекта

Теперь нам нужно внести изменения в файл settings.py, который находится в конфигурационном пакете myproject. Мы зарегистрируем следующие приложения:

  • users — основное приложение для API.

  • rest_framework — для работы с Django REST Framework.

  • drf_spectacular — для автоматической генерации документации OpenAPI.

Регистрация приложений

Найдите в файле settings.py раздел INSTALLED_APPS и добавьте туда наши приложения:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',        # Подключение Django REST Framework
    'users',                 # Приложение для работы с пользователями
    'drf_spectacular',       # Генератор документации OpenAPI
]

Настройки для DRF и drf-spectacular

Добавим настройки для библиотеки drf-spectacular, которая будет управлять схемами API и документацией.

# Настройки для Django REST Framework
REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',  # Схема для автоматической генерации API-документации
}

# Настройки для drf-spectacular
SPECTACULAR_SETTINGS = {
    'TITLE': 'User Management API',                               # Название API
    'DESCRIPTION': 'API для регистрации, получения и удаления пользователей.',  # Описание API
    'VERSION': '1.0.0',                                           # Версия API
    'SERVE_INCLUDE_SCHEMA': False,                                # Отключение схемы в ответах API
}

Мы завершили настройку конфигурации проекта. На следующем этапе можно приступить к созданию моделей базы данных для работы с пользователями.

Подготовка базы данных

На данном этапе мы создаем модель пользователя, которая описывает, как данные о пользователях будут храниться в базе данных. Также мы выполняем миграции, чтобы Django создал таблицы в базе данных на основе описанных моделей. Давайте рассмотрим все шаги подробнее.

Шаг 1: Описание модели пользователя

Файл users/models.py — это место, где мы описываем структуру таблицы базы данных для пользователей с помощью модели. В Django каждая модель автоматически связывается с таблицей в базе данных.

from django.db import models


class User(models.Model):
    first_name = models.CharField(max_length=100)  # Имя пользователя
    last_name = models.CharField(max_length=100)   # Фамилия пользователя
    email = models.EmailField(unique=True)         # Уникальный email пользователя
    age = models.IntegerField()                    # Возраст
    job = models.CharField(max_length=100)         # Профессия

    def __str__(self):
        return f'{self.first_name} {self.last_name}'  # Строковое представление объекта

Шаг 2: Создание миграций

Когда модель описана, нужно создать миграции — это команды, которые переводят описанную модель в SQL-запросы для создания таблиц в базе данных. Выполняем команду:

python manage.py makemigrations

Эта команда сканирует все модели в проекте, которые были изменены, и создает миграцию, то есть файл с инструкциями для изменения базы данных (в нашем случае — для создания новой таблицы для модели User).

Шаг 3: Применение миграций

После того как миграции созданы, их нужно применить, чтобы физически создать таблицы в базе данных. Для этого выполняем команду:

python manage.py migrate

Эта команда берет созданные миграции и выполняет их, создавая необходимые таблицы и поля в базе данных на основе нашей модели User.

При первой миграции, дополнительно, будут созданы системные таблицы Django
При первой миграции, дополнительно, будут созданы системные таблицы Django

Так как мы не указывали в настройках описание базы данных — применились стандартные настройки, а именно работа с базой данных SQLite. В чем можно убедиться, заглянув в созданный файл базы данных.

Для просмотра использую Pycharm, но вы можете поставить, например, DB Browser for SQLite
Для просмотра использую Pycharm, но вы можете поставить, например, DB Browser for SQLite

Таким образом, на этом этапе мы описали модель пользователя, сгенерировали SQL-инструкции для создания таблицы, а затем применили их, чтобы подготовить базу данных для работы. Теперь наша база данных готова для хранения информации о пользователях!

Настройка маршрутов

Для настройки маршрутов (или конечных точек) для нашего API или документации, необходимо внести изменения в файл urls.py конфигурационного пакета.

Маршруты представляют собой пути, по которым клиентские запросы направляются к соответствующим обработчикам на сервере. Они позволяют организовать взаимодействие между клиентом и сервером, обеспечивая доступ к различным ресурсам и функциям API.

Кроме того, для удобства, мы создадим файл urls.py и в пакете нашего API, чтобы избежать избыточности.

Файл myproject/urls.py

Этот файл можно полностью очистить от текущего содержимого и оставить только следующее:

from django.urls import path, include
from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView


urlpatterns = [
    path('api/', include('users.urls')),
    # Генерация OpenAPI схемы
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    # Swagger UI
    path('api/docs/swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    # Redoc
    path('api/docs/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

Этим кодом мы подключаем маршрут для отображения документации и привязываем файл users/urls.py, который нам еще предстоит создать.

Создание файла users/urls.py

Создаем файл users/urls.py и заполняем его следующим образом:

from django.urls import path
from .views import UserRegistration, UserDetail, UserList, UserDelete, UserDeleteAll


urlpatterns = [
    path('register/', UserRegistration.as_view(), name='user-register'),
    path('user/<int:user_id>/', UserDetail.as_view(), name='user-detail'),
    path('users/', UserList.as_view(), name='user-list'),
    path('delete/<int:user_id>/', UserDelete.as_view(), name='user-delete'),
    path('delete-all/', UserDeleteAll.as_view(), name='user-delete-all'),
]

В данном случае мы импортируем несколько классов, которые скоро опишем в файле users/views.py. Пока предлагаю закомментировать все методы, кроме register и убрать лишние импорты.

from django.urls import path
# from .views import UserRegistration, UserDetail, UserList, UserDelete, UserDeleteAll
from .views import UserRegistration


urlpatterns = [
    path('register/', UserRegistration.as_view(), name='user-register'),
    # path('user/<int:user_id>/', UserDetail.as_view(), name='user-detail'),
    # path('users/', UserList.as_view(), name='user-list'),
    # path('delete/<int:user_id>/', UserDelete.as_view(), name='user-delete'),
    # path('delete-all/', UserDeleteAll.as_view(), name='user-delete-all'),
]

API метод для регистрации пользователей

Теперь начнем создавать методы нашего API. Первым таким методом будет метод для регистрации пользователей в нашей базе данных. Прежде чем мы перейдем к его написанию, я хочу рассказать про общие принципы создания API через Django REST Framework (DRF).

Классовые представления

Мы будем использовать классовые представления (Class-Based Views), которые позволяют организовать код более структурированно и повторно использовать его. Классовые представления предоставляют методы для обработки различных HTTP-запросов (GET, POST, PUT, DELETE), что делает их гибкими и удобными для создания API.

Сериализация

Написание API тесно связано с сериализацией. Сериализация (Serialization) используется для преобразования сложных типов данных, таких как модели Django, в JSON или другие форматы, которые могут быть легко переданы через API. Сериализаторы также помогают валидации входных данных, что обеспечивает их корректность и безопасность. Сегодня мы разберемся с этим на конкретных примерах.

Теперь давайте напишем метод регистрации пользователей на простом примере (пока без автодокументации).

Сериализатор

Для этого, в пакете API, создадим файл serializers.py и внутри него пропишем простой серилизатор для модели User

from rest_framework import serializers
from .models import User


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'first_name', 'last_name', 'email', 'age', 'job']

Этот сериализатор преобразует данные модели User в формат JSON и обратно. Он также выполняет валидацию данных, что гарантирует их корректность перед сохранением в базу данных.

Представление

В файле users/views.py создадим классовое представление для регистрации пользователей:

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import UserSerializer


class UserRegistration(APIView):
    def post(self, request):
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            return Response({"status": "User created", "id": user.id}, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Объяснение кода

  • Импорт необходимых модулей: Вы импортировали модули для работы с сериализаторами, статусами HTTP-ответов и представлениями.

  • Создание класса UserRegistration: Этот класс наследуется от APIView, что позволяет вам обрабатывать HTTP-запросы.

  • Метод post: Этот метод обрабатывает POST-запросы. Он принимает данные из запроса, передает их в сериализатор и проверяет их валидность.

  • Валидация данных: Если данные валидны, они сохраняются в базе данных, и возвращается успешный ответ с кодом 201 (Created). Если данные не валидны, возвращается ответ с ошибками и кодом 400 (Bad Request).

Почему именно такая запись?

Я выбрал APIView для наглядности, чтобы показать основные принципы работы с сериализаторами и обработкой POST-запросов. Однако, в Django REST Framework существуют более специализированные классы, такие как CreateAPIView, которые автоматически обрабатывают POST-запросы и упрощают код. Например, класс UserRegistration можно было бы упростить следующим образом:

from rest_framework import generics
from .serializers import UserSerializer


class UserRegistration(generics.CreateAPIView):
    serializer_class = UserSerializer

Для всех последующих методов я буду использовать именно APIView, так как он позволяет наглядно демонстрировать, что происходит с данными на каждом этапе.

Тестируем API

Сейчас мы протестируем процесс регистрации пользователя через наш API. Для этого необходимо запустить сервер Django. Выполнить это можно следующей командой:

python manage.py runserver
После запуска вы должны увидеть похожий результат.
После запуска вы должны увидеть похожий результат.

Пока у нас нет полноценной документации для нашего API. Точнее, она есть, но сейчас она совсем не информативна, что можно увидеть, зайдя на Swagger-документацию.

Мы скоро это исправим, а пока для тестов я создам временный файл в корне проекта PyCharm и назову его register_api.py. В этом файле я буду использовать синхронный модуль requests, чтобы не усложнять, так как код временный.

Установим модуль requests:

pip install requests

Создадим файл register_api.py с таким содержимым:

from requests import post


url = "http://127.0.0.1:8000/api/register/"
data = {
    "first_name": "John",
    "last_name": "Doe",
    "email": "john.doe@example.com",
    "age": 30,
    "job": "Developer"
}


response = post(url, data=data)


if response.status_code == 201:
    print("User created successfully:", response.json())
else:
    print("Error:", response.json())

Да, вот такой простой код

Ссылка для POST-запроса получилась такой, потому что в файле urls.py в конфигурационном пакете мы указали:

path('api/', include('users.urls'))

Тем самым установив маршрут api/ для всех методов. А путь register/ мы получили из-за этой записи:

path('register/', UserRegistration.as_view(), name='user-register')

Далее мы сформировали словарь с данными для регистрации, что аналогично JSON на фронтенде. ID не передавали, так как Django присвоит его автоматически при создании записи.

После этого выполняем запрос и выводим ответ в консоль. Проверим:

Запись действительно появилась в базе данных. Но согласитесь, хотелось бы пользоваться API более удобно, не так ли? Добавим теперь пару строк для корректного документирования API.

Улучшаем серилизатор

Вариант серилизатора, который мы описали слишком простой и в реальной практике, конечно, он описывается несколько сложнее. Я предлагаю добавить в него валидацию полей. К примеру, минимальный возраст сделаем 16, а максимальный 99. Кроме того, давайте пропишем значение «Безработный(ая)» по умолчанию.

Описание теперь можете выглядеть так:

class UserSerializer(serializers.ModelSerializer):
    # Добавляем поле с валидацией и значением по умолчанию
    age = serializers.IntegerField(min_value=16, max_value=99)
    job = serializers.CharField(required=False, default="Безработный(ая)")

    class Meta:
        model = User
        fields = ['id', 'first_name', 'last_name', 'email', 'age', 'job']

    # Валидация на уровне всех полей, если нужна более комплексная проверка
    def validate(self, data):
        if data['age'] < 16 or data['age'] > 99:
            raise ValidationError("Возраст должен быть между 16 и 99.")
        return data

    # Метод для кастомного сохранения данных с дефолтными значениями
    def create(self, validated_data):
        # Устанавливаем значение по умолчанию для поля "job", если оно не передано
        if 'job' not in validated_data or not validated_data['job'].strip():
            validated_data['job'] = "Безработный(ая)"
        return super().create(validated_data)

Этот улучшенный сериализатор теперь включает валидацию возраста и значение по умолчанию для поля “job”.

Для тех кто знаком с FastApi сейчас обнаружил многое от Pydantic.  Кстати, в моем профиле на Хабре вы найдете больше десяти крупных и подробных публикаций, посвященных теме разработки собственного API с использованием FastAPI.

Улучшаем метод регистрации пользователя

Изначально метод регистрации пользователей выглядел так:

class UserRegistration(APIView):
    def post(self, request):
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            return Response({"status": "User created", "id": user.id}, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Этот код выполняет свою задачу, но он не содержит документации, что затрудняет его использование и понимание.

Сейчас мы добавили документацию с помощью библиотеки drf-spectacular, чтобы сделать API более понятным и удобным для использования. Вот как теперь выглядит метод:

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiResponse
from .serializers import UserSerializer


class UserRegistration(APIView):
    @extend_schema(
        summary="Регистрация пользователя",
        description="Создаёт нового пользователя с уникальным email, именем, фамилией, возрастом и профессией. "
                    "Возраст должен быть в пределах от 16 до 99 лет. Если профессия не указана, подставляется значение "
                    "'Безработный(ая)'.",
        request=UserSerializer,
        responses={
            201: OpenApiResponse(response=UserSerializer, description="Пользователь успешно создан"),
            400: OpenApiResponse(description="Ошибки валидации")
        }
    )
    def post(self, request):
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
            user = serializer.save()
            return Response({"status": "User created", "id": user.id}, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Что мы сделали и зачем

Из изменений вы можете заметить, что появился декоратор extend_schema, который мы навесиили на наш обработчик POST запроса. Вот короткое описание параметров, которые мы ввели:

  • summary: Краткое описание метода.

  • description: Подробное описание метода, включая требования к полям и значения по умолчанию.

  • request: Указание на сериализатор, который используется для обработки входящих данных.

  • responses: Описание возможных ответов, включая коды статусов и сериализаторы для успешных и ошибочных ответов.

Эти изменения делают наш API более профессиональным и удобным для разработчиков, что способствует более быстрому и эффективному взаимодействию с ним.

Обновим страницу со SWAGGER докуметацией.

Тут мы можем заметить, что получилось максимально подробное и доступное описание метода для регистрации пользователя. Точно такое-же, как мы получили бы через FastApi, при корректном написании кода и правильной схемой Pydantic.

Выполню запрос

Все отработало корректно и мы получили результат с созданным ID пользователя.

Теперь опишем остальные методы.

Метод для получения списка всех пользователей

class UserList(APIView):
    @extend_schema(
        summary="Получение информации обо всех пользователях",
        description="Возвращает список всех зарегистрированных пользователей.",
        responses={
            200: OpenApiResponse(response=UserSerializer(many=True), description="Список всех пользователей")
        }
    )
    def get(self, request):
        users = User.objects.all()
        serializer = UserSerializer(users, many=True)
        return Response(serializer.data)

В данном примере мы написали обработчик для GET-метода. Если кратко, то мы:

  1. Определили декоратор extend_schema для описания нашего метода, указав краткое описание, подробное описание и возможные ответы.

  2. Получили всех пользователей из базы данных с помощью User.objects.all().

  3. Сериализовали данные пользователей с помощью UserSerializer, передав параметр many=True для обработки списка объектов.

  4. Вернули сериализованные данные в ответе с помощью Response(serializer.data).

Этот обработчик позволяет получить список всех зарегистрированных пользователей в удобном формате.

Выполним импорт и регистрацию маршрута для данного метода:

path('users/', UserList.as_view(), name='user-list')

Проверим

Выполним запрос

Данные получены!
Данные получены!

Метод для получения пользователя по его ID

Напишем метод для получения информации про одного пользователя по его ID.

class UserDetail(APIView):
    @extend_schema(
        summary="Получение информации о пользователе",
        description="Возвращает информацию о пользователе по его ID.",
        responses={
            200: OpenApiResponse(response=UserSerializer, description="Информация о пользователе"),
            404: OpenApiResponse(description="Пользователь не найден")
        }
    )
    def get(self, request, user_id):
        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExist:
            return Response({"error": "User not found"}, status=status.HTTP_404_NOT_FOUND)
        serializer = UserSerializer(user)
        return Response(serializer.data)

Этот метод обрабатывает GET-запрос для получения информации о пользователе по его ID. Если пользователь с указанным ID существует, метод возвращает его данные в формате JSON. Если пользователь не найден, возвращается сообщение об ошибке с кодом статуса 404.

Тут обратите внимание на то, что метод get у нас принимает дополнительный параметр — user_id – это обязательно необходимо указать в маршруте при регистрации:

path('user/<int:user_id>/', UserDetail.as_view(), name='user-detail')

Пробуем

Выполним запрос

Данные получены!
Данные получены!

Метод для удаления пользователя по его ID

class UserDelete(APIView):
    @extend_schema(
        summary="Удаление пользователя",
        description="Удаляет пользователя по его ID. Если пользователь не найден, возвращает ошибку.",
        responses={
            200: OpenApiResponse(description="Пользователь успешно удалён"),
            404: OpenApiResponse(description="Пользователь не найден"),
            400: OpenApiResponse(description="ID пользователя не предоставлен")
        }
    )
    def delete(self, request, user_id):
        if user_id:
            try:
                user = User.objects.get(id=user_id)
                user.delete()
                return Response({"status": "User deleted"}, status=status.HTTP_200_OK)
            except User.DoesNotExist:
                return Response({"error": "User not found"}, status=status.HTTP_404_NOT_FOUND)
        return Response({"error": "User ID not provided"}, status=status.HTTP_400_BAD_REQUEST)

Тут мы использовали уже delet метод. Для удаления мы сначала получаем пользователя по его ID и, если пользователь найден, выполняем его удаление с базы данных. Иначе возвращаем сообщение с исключением.

Описание значений в декораторе похое на то, которое мы делали при описании метода для регистрации пользователя.

Регистрируем маршрут

path('delete/<int:user_id>/', UserDelete.as_view(), name='user-delete')

Проверяем

Выполним запрос

Пользователь удален
Пользователь удален

Метод для удаления всех пользователей

class UserDeleteAll(APIView):
    @extend_schema(
        summary="Удаление всех пользователей",
        description="Удаляет всех пользователей из базы данных.",
        responses={
            200: OpenApiResponse(description="Все пользователи успешно удалены")
        }
    )
    def delete(self, request):
        User.objects.all().delete()
        return Response({"status": "All users deleted"}, status=status.HTTP_200_OK)

Регистрируем маршрут

path('delete-all/', UserDeleteAll.as_view(), name='user-delete-all')

Проверяем

Все пользователи удалены
Все пользователи удалены

Методы по изменению данных о пользователе рекомендую написать самостоятельно. Это позволит лучше усвоить полученную тут информацию.

Внимательный читатель спросит, а что там по Redoc и я скажу вам что все готово! Для того чтоб в этом убедиться достаточно перейти по адресу: http://127.0.0.1:8000/api/docs/redoc/ и вот что мы видим:

Наш API получился действительно впечатляющим, и это вызывает желание поделиться им с миром. Давайте воплотим эту идею в жизнь, запустив наш проект на платформе Amvera Cloud.

Подготовка к деплою

Несмотря на общую простоту, нам необходимо будет выполнить небольшую подготовку приложения, прежде чем мы сможем его запустить удаленно на Amvera Cloud.

В корне проекта, на уровне с manage.py, базой данных и requiremnts.txt создадим файл amvera.yml. Файл можно сгенерировать и на сайте, но я решил это сделать за вас.

Настройки, которые будут содержаться в этом файле, помогут платформе Amvera собрать ваше приложение, а затем выполнить его запуск. Полный код настроек:

---
meta:
  environment: python
  toolchain:
    name: pip
    version: 3.12
build:
  requirementsPath: requirements.txt
run:
  persistenceMount: /data
  containerPort: 5000
  command: gunicorn myproject.wsgi:application  --bind 0.0.0.0:5000

Эти настройки в файле amvera.yml выполняют несколько важных функций для вашего проекта:

  1. meta:

    • environment: Указывает, что проект использует Python.

    • toolchain: Определяет, что для управления зависимостями используется pip версии 3.12.

  2. build:

    • requirementsPath: Указывает путь к файлу requirements.txt, который содержит список всех зависимостей проекта.

  3. run:

    • persistenceMount: Указывает, что директория /data будет монтироваться для сохранения данных.

    • containerPort: Определяет, что контейнер будет слушать на порту 5000.

    • command: Указывает команду для запуска приложения с использованием gunicorn, который будет слушать на всех интерфейсах (0.0.0.0) на порту 5000.

Эти настройки помогают автоматизировать развертывание и запуск вашего проекта на платформе Amvera Cloud.

command: gunicorn myproject.wsgi:application  --bind 0.0.0.0:5000

Проверьте, чтоб вместо myproject было указано корректное имя вашего конфигурационного пакета.

Переведём проект из режима разработки. Для этого, в файле settings.py, конфигурационного пакета заменим DEBUG = True на DEBUG = False.

Настроим разрешения доступа к сайту. Так как проект учебный, разрешим доступ со всех адресов:

 ALLOWED_HOSTS = ['*']

 На этом процесс подготовки полностью окончен.

Деплой проекта

Так как мы уже подготовили все файлы и каждый из нас любит делать быстро и без лишних движений — для загрузки файлов проекта мы воспользуемся внутренним терминалом, тем более файл настроек уже готов.

Приступим.

  • Регистрируемся в Amvera Cloud если регистрации не было (за регистрацию вам дадут 111 рублей на баланс)

  • Переходим в раздел проектов

  • Кликаем на «Создать проект». После необходимо дать ему название, выбрать тариф и кликнуть на «Далее».

  • На открывшемся экране жмем на «Через интерфейс» и загружаем содержимое проекта. Нас интересуют следующие файлы:

+ файл amvera.yml, который тоже должен был попасть в красный квадрат
+ файл amvera.yml, который тоже должен был попасть в красный квадрат
  • После загрузки файлов жмем на «Далее» и на «Завершить». После заходим в проект.

  • Активируем бесплатное доменное имя. Для этого переходим в «Настройки» и там активируем домен.

После загрузки файлов начнется автоматическая сборка проекта и, если все файлы были доставлены и они корректно заполнены, то уже через 2-3 минуты ваше API Django будет доступно по выделенному под ваш проект доменному имени.

Заключение

Друзья, надеюсь, что эта статья помогла вам увидеть, насколько легко и увлекательно можно создавать полноценные API на Django. Мы рассмотрели основные шаги, от разработки до автодокументации с помощью drf-spectacular, и убедились, что этот процесс не так сложен, как может показаться на первый взгляд.

Если вы хотите углубиться в эту тему, не стесняйтесь обращаться к официальной документации и экспериментировать с собственными API-методами. Пусть это руководство станет для вас отправной точкой в создании мощных и многофункциональных API на Django.

Для тех, кто хочет получить полный код проекта и эксклюзивный контент, который я не публикую на Хабре, приглашаю вас в мой бесплатный телеграм-канал «Легкий путь в Python». Там вы найдете еще больше полезных материалов и сможете задать свои вопросы.

Спасибо за внимание и до скорых встреч!

Комментарии (14)


  1. UncleJonathan
    14.09.2024 08:39

    Если кто-то планирует задействовать DRF для долгоживущего и очень highload проекта (десятки тысяч rps), то я бы обязательно упомянул два основных недостатка, на мой взгляд.

    Первый недостаток. Отсутствие встроенного генератора документации. Все эти нашлёпки, ставящиеся сбоку, периодически валятся с непонятными симптомами, как только API чуточку усложняется. Конкретные примеры сейчас не приведу. Но это постоянный источник небольшой, но заметной боли (если говорить про годы поддержки и развития API).

    Второй недостаток. Когда всё начинает тормозить (понимаю, что 99% проектов с этим не столкнётся), и начинаешь исследовать тормоза в профайлере и дебаггере, то там творится какая-то дичь. Данные десятки, если не сотни, раз преобразовываются из одного типа в другой, json'ы сериализуются, десереализуются, и сериализуются снова, всё это передается через лабиринт вызовов вверх и вниз по стеку. Когда начинает играть роль каждая микросекунда, выясняется, что этот монстр жуёт жвачку из данных, как корова, очень долго, и ускорить этот процесс без переписывания без DRF, никак нельзя.


    1. yakvenalex Автор
      14.09.2024 08:39

      А альтернативы какие?


      1. kompilainenn2
        14.09.2024 08:39

        Яндекс думает, что самописное все на плюсах. Как показывает их опыт - это вполне себе вариант


      1. UncleJonathan
        14.09.2024 08:39

        Честно говоря, сам ещё не определился. В конкретных ручках, где важны сотни и десятки миллисекунд, делаю по самому простому brute force варианту: заменяю всю машинерию DRF на закат солнца вручную: ручная десериализация и сериализация.

        Если можно легкой кровью вынести часть ручек в отдельный микросервис, выносится в микросервис на FastAPI или Go.

        Но повторюсь: большинство с этим не столкнётся. Однако, если вдруг сталкиваешься, то положение плачевное. DRF - всё-таки наверное одна из самых тяжёлых реализаций REST. Хотя бенчмарки не проводил, но по результатам профилирования возникали мысли, что оно всё переусложнено на порядок, а то и два.


    1. whoisking
      14.09.2024 08:39

      Первый недостаток хорошо закрывается drf-specracular


      1. UncleJonathan
        14.09.2024 08:39

        Проблема всех этих проектов, что они - сторонние. Их авторы не всегда успевают или хотят синхронизироваться с версиями DRF, или иногда вообще забрасывают свои творения на полдороге (как было с drf-yasg, или чем-то похожим, копаться и вспоминать сейчас некогда).


        1. whoisking
          14.09.2024 08:39
          +1

          Я бы с таким настроением предложил вообще код перестать писать) Ну, или писать абсолютно всё самому (тут просто пожелаю удачи).

          Во-первых, у вас всегда будет что-то стороннее. Во-вторых, стороннее - необязательно плохое и не всегда умирает. Сам drf тоже, по сути, сторонний для джанги, но в целом всё даже ок (ну, кроме отсутствия поддержки асинка).

          В третьих, не стороннее не даёт вам никаких гарантий. В дрф же есть встроенная генерация опенапи, но кто-то ей пользуется?)


          1. yakvenalex Автор
            14.09.2024 08:39
            +1

            Максимально согласен. Весь Python основан на всем стороннем) И так мы можем прийти что и Django с нуля писать нужно)


  1. Andrew4fr
    14.09.2024 08:39

    Полноценное API 

    создадим API, которое будет

    Так пишет Опытный python разработчик с многолетним стажем.
    Печаль


    1. yakvenalex Автор
      14.09.2024 08:39

      Слово “API” (Application Programming Interface) в русском языке обычно используется как среднего рода. Например, можно сказать “это API”, “новое API” или “полноценное API”. Однако, если быть точным, “интерфейс” — это слово мужского рода. Но я предпочитаю использовать тот вариант, который чаще встречается в реальной жизни.

      Теперь хотелось бы понять, как эта ошибка указывает на мою неопытность?

      Что касается кода моего полноценного API, есть ли там какие-то ошибки? Или вы не работаете с кодом?


      1. Andrew4fr
        14.09.2024 08:39

        лучше писать и говорить правильно, чем неправильно


        1. yakvenalex Автор
          14.09.2024 08:39
          +1

          Как использование слова “оно” в отношении API указывает на мою неопытность как программиста? Я и в повседневной жизни так говорю. Мы с вами не работаем вместе, вы меня не знаете, но решаете, что можно делать выводы о моем опыте. Ваш комментарий сначала показался мне написанным подростком, а теперь оказывается, что вам за 50. Как это вообще возможно? Если я ошибся, скажите об этом. API - мужской род, исправьте. Зачем упоминать мой статус и опыт здесь?


          1. Andrew4fr
            14.09.2024 08:39

            Много шума из ничего

            API - мужской род, исправьте


            1. yakvenalex Автор
              14.09.2024 08:39

              Так пишет Опытный python разработчик с многолетним стажем. Печаль

              На вопрос по поводу опыта вы так и не ответите?