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

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


Python и 1000 программ



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

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

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

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

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



Перевод статьи

Report Page