Django REST Framework: REST API на Python с нуля

  1. Знакомство с REST.
  2. Что такое Django REST Framework?
  3. Установка Django.
    1. Создание виртуальной среды.
    2. Установка зависимостей.
    3. Начало проекта.
    4. Изменение директории.
    5. Запуск сервера.
    6. Создание приложения.
    7. Список приложений в проекте.
    8. Миграции.
    9. Административная панель.
    10. Создание модели.
    11. Не забывайте о миграциях!
    12. Добавление приложения в админ-панель.
  4. Написание Django REST API.
    1. Сериализатор.
    2. Представления.
    3. URL: ссылки на ресурсы.
  5. Выводы.

1. Знакомство с REST

Термин REST API расшифровывается как Representational State Transfer Application Programming Interface. Следовательно, RESTful API  —  это программный интерфейс приложения, соответствующий ограничениям архитектурного стиля REST

REST  —  не протокол и не стандарт. Это, как уже было сказано, архитектурное ограничение. Чтобы API считался RESTful, он должен соответствовать следующим критериям.

  1. Единый интерфейс.
    Единый интерфейс (uniform interface) строится вокруг ресурсов с уникальными идентификаторами и уникальными URL, а каждая страница реализовывает какие-либо из HTTP-методов  —  GET, POST, DELETE или UPDATE  —  все они отвечают за различные манипуляции конкретным ресурсом.
  2. Архитектура “Клиент-Сервер”
    Сервер анализирует запрос клиента и отправляет ему ответ. Получив ответ от сервера, клиент определяет, как именно информация отобразится у конечных пользователей.
  3. Нестационарные запросы
    Нестационарность (stateless) означает, что каждый HTTP-запрос полностью изолирован. Сервер не полагается на информацию из предыдущих запросов  —  клиент отправляет HTTP-запрос, включающий сразу всю необходимую ему информацию. Сервер не хранит контекста между запросами, каждый запрос содержит всю необходимую информацию.

Благодаря вышеперечисленным архитектурным правилам REST API масштабируемый, переносимый и гибкий.


2. Что такое Django REST Framework?

Django  —  масштабируемый полнофункциональный веб-фреймворк, написанный на Python. Django берет на себя все хлопоты, зачастую связанные с веб-разработкой, такие как безопасность и доступ к базам данных.

Существует множество библиотек для Django, расширяющих его функционал. Одна из них, о которой мы поговорим сегодня,  —  это Django REST Framework или DRF, которая позволяет сериализовать данные из Django ORM через REST API

Сериализация  —  это преобразование таблиц из базы данных в формат JSON.

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

Давайте создадим сайт бронирования отелей! Исходный код и справка доступны на GitHub.


3. Установка Django

Прежде чем приступить непосредственно к работе с REST API, сделаем краткий экскурс в Django.

3.1. Создание виртуальной среды

$ virtualenv venv
$ source venv/bin/activate

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

$ pip install djangorestframework
$ pip install django

3.3. Начало проекта

$ django-admin startproject hotel_reservation
$ cd demo/

3.4. Изменение директории

$ mv hotel_reservation/manage.py .
$ mv hotel_reservation/hotel_reservation/* hotel_reservation/
$ rm -r hotel_reservation/hotel_reservation/

3.5. Запуск сервера

$ python manage.py runserver

Теперь перейдите по адресу http://127.0.0.1:8000/ в браузере. Если все прошло успешно, то вы увидите следующую страницу:

3.6. Создание приложения

Приложения в Django  —  это независимые многократно используемые компоненты. Создадим приложение hotel_app.

$ django-admin startapp hotel_app

3.7. Список приложений в проекте

Чтобы подключить к проекту hotel_reservation приложения hotel_app и rest_framework, необходимо отредактировать файл results/settings.py, указав эти приложения в списке INSTALLED_APPS:

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'hotel_app'
'rest_framework'

]

3.8. Миграции

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

$ python manage.py migrate

3.9. Административная панель

Django поставляется со встроенной панелью администратора, что позволяет создать суперпользователя с помощью одной команды. Заполните форму  —  появится учетная запись администратора:

$ python manage.py createsuperuser

Для доступа к админ-панели перейдите по ссылке: http://127.0.0.1:8000/admin.

Снова выполните миграции, авторизуйтесь.

3.10. Создание модели

Django ORM абстрагирует базу данных, позволяя легко запрашивать данные и манипулировать ими через объектно-ориентированное отображение, называемое моделью. Django ORM заставляет писать код согласно паттерну MVC (Model View Controller), который станет интуитивно понятным для вас после прохождения кривой обучения.

hotel_app/models.py:

from datetime import timedelta, datetime
from django.db import models
from datetime import datetime

class Guest(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField(default=20)
phone = models.CharField(max_length=20)
email = models.CharField(max_length=30)

def __str__(self) -> str:
return self.name


class Hotel(models.Model):
name = models.CharField(max_length=20)
location = models.CharField(max_length=50)
phone = models.CharField(max_length=20)
email = models.CharField(max_length=30)

def __str__(self) -> str:
return self.name


class Room(models.Model):
room_no = models.IntegerField(default=101)
price = models.FloatField(default=1000.0)
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE)
is_booked = models.BooleanField(default=False)

def __str__(self) -> str:
return str(self.room_no)

def hotel_name(self) -> str:
return self.hotel


class Booking(models.Model):
guest = models.ForeignKey(Guest, on_delete=models.CASCADE)
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
num_of_guest = models.IntegerField(default=1)
checkin_date = models.DateField(default=datetime.now)
checkout_date = models.DateField(default=datetime.now)
is_checkout = models.BooleanField(default=False)

def __str__(self) -> str:
return self.guest.name

def hotel_name(self) -> str:
return self.hotel.hotel

def charge(self) -> float:
return self.is_checkout* \
(self.checkout_date - self.checkin_date + timedelta(1)).days* \
self.room.price

Мы создали модель, хранящую имя студента и его оценки. Метод __str__ определяет имя объекта, отображаемое в браузере. Если пропустить определение данного метода, то вы увидите в панели администратора объект под названием <ClassName>.

3.11. Не забывайте о миграциях!

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

$ python manage.py makemigrations
$ python manage.py migrateviews.

3.12. Добавление приложения в админ-панель

Во встроенное приложение административной панели можно добавить созданную ранее пользовательскую модель.

hotel_app/admin.py:

from django.contrib import admin
from .models import Guest, Hotel, Room , Bookingadmin.site.register(Guest)
admin.site.register(Hotel)
admin.site.register(Room)
admin.site.register(Booking)

Теперь мы завершили ту общую часть разработки веб-приложения, которая относится к фреймворку Django. Настало время приступить к проектированию REST API. 


4. Написание Django REST API

Структура директорий проекта:

$ tree -I 'venv'
.
├── db.sqlite3
├── hotel_app
│ ├── __init__.py
│ ├── __pycache__
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
| ├── serializer.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── hotel_reservation
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── manage.py

Добавим в проект файлы urls.py и serializers.py. Вот новый список файлов.

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

Сериализация  —  процесс перевода структуры данных в последовательность байтов. Она используется для передачи объектов по сети и для сохранения их в файлы (Википедия).

hotel_app/serializers.py:

from rest_framework import fields, serializers
from .models import Guest, Hotel, Room , Booking


class GuestSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Guest
fields = ("name", "age", "phone", "email")


class HotelSerializer(serializers.ModelSerializer):
class Meta:
model = Hotel
fields = ("name", "location", "phone", "email")


class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = ("room_no", "price", "hotel", "is_booked")


class BookingSerializer(serializers.ModelSerializer):
guest = GuestSerializer
hotel = HotelSerializer
room = RoomSerializer
class Meta:
model = Booking
fields =("guest", "hotel", "room", "checkin_date", "checkout_date", "charge",)

Сериализаторы определяют, как именно и какие данные отобразит представление API. При запросе по REST API к экземпляру модели Hotel мы получим список следующих полей, взятых из самой модели при помощи сериализатора:

{
“name” : “”,
“location” : “”,
“phone” : “”,
“email” : ””,
}

4.2. Представления

Файл представления определяет то, как сериализованные объекты отображаются пользователю.

from rest_framework import  status
from rest_framework.response import Response
from rest_framework.decorators import api_view

from .models import Guest, Hotel, Room, Booking 
from .serializer import GuestSerializer, HotelSerializer,  RoomSerializer, BookingSerializer 

from collections import namedtuple


nt = namedtuple("object", ["model", "serializers"])
pattern = {
    "guest"  : nt(Guest, GuestSerializer),
    "hotel"  : nt(Hotel, HotelSerializer),
    "room"   : nt(Room, RoomSerializer),
    "booking": nt(Booking, BookingSerializer),
}

@api_view(["GET", "POST"])
def ListView(request, api_name):
    object =  pattern.get(api_name, None)
    if object == None:
        return Response(
            data   = "Invalid URL",
            status = status.HTTP_404_NOT_FOUND,
        )
    if request.method == "GET":
        object_list = object.model.objects.all()
        serializers  = object.serializers(object_list, many=True)
        return Response(serializers.data)

    if request.method == "POST":
        data = request.data
        serializers = object.serializers(data=data)
        
        if not serializers.is_valid():
            return Response(
                data   = serializers.error,
                status = status.HTTP_404_NOT_FOUND
            )
        serializers.save()
        return Response(
                data   = serializers.error,
                status = status.HTTP_201_CREATED
        )

Вышеописанное представление возвращает результат для URL-параметра api_name при его соответствии одному из следующих значений: guest, hotel, room или booking. В противном случае представление отправляет клиенту сообщение Invalid URL.

4.3. URL: ссылки на ресурсы

hotel_app/urls.py:

from django.urls import re_path
from .views import ListViewurlpatterns = [
re_path(r"^(?P<api_name>[a-z]+)", ListView, name='hotel-objects'),
]

hotel_reservation/urls.py:

from django.contrib import admin
from django.urls import path, includeurlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘hotel-app’, include(‘hotel_app.urls’))
]

Таким образом определяется базовый URL-путь для API: http://127.0.0.1:8000/hotel-app/.

Перейдя по данной ссылке, вы получите доступ ко всем ранее определенным “разделам” REST API проекта:

При попытке запросить какое-либо иное API браузер получит от сервера сообщение об ошибке, так как в приложении бронирования отеля существуют только эти четыре вида API.

Пример:


5. Выводы

Мы успешно реализовали пользовательский интерфейс отправки запросов HTTP-методами GET и POST. API готов, к нему можно получить доступ по соответствующей ссылке. Весь исходный код руководства доступен на GitHub.


Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Umangshrestha: Create a REST API with Django

Предыдущая статьяВсе о ключевых словах static и final
Следующая статьяКак оформить поле ввода: советы и техники