Создание REST API на Python с помощью Django

Введение Django - это мощная веб-платформа Python, используемая для быстрого создания безопасных масштабируемых веб-приложений с меньшими усилиями. Он стал популярным из-за низкого барьера для входа и сильного сообщества, которое использует и развивает фреймворк. В этом руководстве мы собираемся создать RESTful API с использованием Django без каких-либо внешних библиотек. Мы рассмотрим основы Django и реализуем API на основе JSON для выполнения операций CRUD для приложения корзины покупок. Что такое REST API? ОТДЫХ (Представляет

Вступление

Django - это мощная веб-платформа Python, используемая для быстрого создания безопасных масштабируемых веб-приложений с меньшими усилиями. Он стал популярным из-за низкого барьера для входа и сильного сообщества, которое использует и развивает фреймворк.

В этом руководстве мы собираемся создать RESTful API с использованием Django без каких-либо внешних библиотек . Мы рассмотрим основы Django и реализуем API на основе JSON для выполнения операций CRUD для приложения корзины покупок.

Что такое REST API?

REST (передача репрезентативного состояния)

  • это стандартная архитектура для создания веб-сервисов и взаимодействия с ними. Обычно он требует, чтобы ресурсы в Интернете были представлены в текстовом формате (например, JSON, HTML или XML), и к ним можно получить доступ или изменить их с помощью заранее определенного набора операций. Учитывая, что мы обычно создаем REST API для использования с HTTP вместо других протоколов, эти операции соответствуют HTTP-методам, таким как GET, POST или PUT.

API (интерфейс прикладного программирования) , как следует из названия, представляет собой интерфейс, который определяет взаимодействие между различными программными компонентами. Веб-API определяют, какие запросы могут быть сделаны к компоненту (например, конечной точке для получения списка элементов корзины покупок), как их выполнять (например, запрос GET) и их ожидаемые ответы.

Мы объединяем эти две концепции для создания REST (ful) API , API, который соответствует ограничениям архитектурного стиля REST. Давайте сделаем один, используя Python и Django.

Настройка Django и нашего приложения

Как упоминалось ранее, Django - это веб-платформа, которая способствует быстрой разработке безопасных и масштабируемых веб-сервисов.

Примечание. Мы будем использовать Django версии 3.1, так как это последняя версия на момент написания.

Перед установкой Django, для удобства и во имя изоляции зависимостей, давайте создадим виртуальную среду:

 $ python3 -m venv env 

В некоторых редакторах кода вы обнаружите, что он уже активирован. Если нет, вы можете перейти в каталог сценариев внутри среды и запустить activate .

В Windows:

 $ env\scripts\activate 

На Mac или Linux:

 $ . env/bin/activate 

Теперь давайте продолжим и установим Django через pip :

 $ pip install django 

После установки мы можем создать наш проект. Хотя вы можете сделать это вручную, гораздо удобнее начать со скелетного проекта через сам Django.

Инструмент django-admin позволяет нам создать пустой скелетный проект, над которым мы можем немедленно начать работу. Он поставляется в комплекте с самим Django, поэтому дальнейшая установка не требуется.

Давайте начнем проект с вызова инструмента, а также команды startproject , за которой следует имя проекта:

 $ django-admin startproject shopping_cart 

Это создает простой скелет проекта в рабочем каталоге. Каждый проект Django может содержать несколько приложений, но мы создадим одно. Давайте вызовем manage.py , созданный с помощью команды startproject для запуска приложения:

 $ cd shopping_cart 
 $ python manage.py startapp api_app 

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

 > env 
 > shopping_cart 
 > api_app 
 > migrations 
 __init__.py 
 admin.py 
 apps.py 
 models.py 
 tests.py 
 views.py 
 > shopping_cart 
 __init__.py 
 asgi.py 
 settings.py 
 urls.py 
 wsgi.py 
 manage.py 

shopping_cart верхнего уровня - это корневой каталог Django, имя которого совпадает с именем проекта. Корневой каталог является мостом между фреймворком и самим проектом и содержит несколько классов настройки, таких как manage.py который используется для запуска приложений.

api_app - это приложение, которое мы развиваем, и их может быть много. У каждого есть несколько скриптов по умолчанию, которые мы будем модифицировать, чтобы приспособить к функциональности CRUD.

Низкоуровневая shopping-cart - это каталог проекта , который содержит файлы, связанные с settings.py , такие как settings.py, в которых будут храниться все свойства нашего приложения.

Django - это модель-представление-контроллер (MVC) . Это шаблон проектирования, который разделяет приложение на три компонента: модель, которая определяет данные, которые хранятся и с которыми происходит взаимодействие, представление, которое описывает, как данные представляются пользователю, и контроллер, который действует как посредник между моделью и Посмотреть. Однако интерпретация этого шаблона в Django немного отличается от стандартной интерпретации. Например, в стандартной платформе MVC логика, обрабатывающая HTTP-запросы для управления элементами корзины покупок, будет находиться в контроллере.

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

В каждом проекте Django предустановлено несколько приложений (модулей) Django. Они используются для аутентификации, авторизации, сеансов и т. Д. Чтобы Django знал, что мы также хотели бы включить наше собственное приложение api_app , нам нужно внести его в список INSTALLED_APPS

Перечислим его, перейдя в settings.py и изменив список, включив в него наше собственное приложение:

 ... 
 INSTALLED_APPS = [ 
 'django.contrib.admin', 
 'django.contrib.auth', 
 'django.contrib.contenttypes', 
 'django.contrib.sessions', 
 'django.contrib.messages', 
 'django.contrib.staticfiles', 
 'api_app', 
 ] 

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

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

Определение модели

Давайте начнем с простой базовой модели - CartItem , который представляет элемент, указанный на вымышленном веб-сайте электронной коммерции. Чтобы определить модели, которые может подхватить Django, мы модифицируем файл api_app/models.py

 from django.db import models 
 
 class CartItem(models.Model): 
 product_name = models.CharField(max_length=200) 
 product_price = models.FloatField() 
 product_quantity = models.PositiveIntegerField() 

Здесь мы используем встроенный db , в котором есть пакет models Класс Model представляет собой модель . Он имеет различные поля, такие как CharField , IntegerField и т. Д., Которые используются для определения схемы модели в базе данных. Они отображаются под капотом ORM Django, когда вы хотите сохранить экземпляр модели в базе данных.

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

Если вы хотите работать с нереляционной базой данных, такой как MongoDB, ознакомьтесь с нашим Руководством по использованию Django MongoDB Engine .

Чтобы внести изменения в схемы модели, как мы только что сделали, нам нужно вызвать Django Migrations . Миграции выполнить довольно легко, однако вам придется запускать их каждый раз, когда вы хотите сохранить изменение в схеме.

Для этого мы вызовем файл manage.py makemigrations аргументы makemigrations и migrate

 $ python manage.py makemigrations # Pack model changes into a file 
 $ python manage.py migrate # Apply those changes to the database 

Результатом migrate должно стать что-то вроде этого:

 Operations to perform: 
 Apply all migrations: admin, api_app, auth, contenttypes, sessions 
 Running migrations: 
 Applying contenttypes.0001_initial... OK 
 Applying auth.0001_initial... OK 
 Applying admin.0001_initial... OK 
 Applying admin.0002_logentry_remove_auto_add... OK 
 Applying admin.0003_logentry_add_action_flag_choices... OK 
 Applying api_app.0001_initial... OK 
 Applying contenttypes.0002_remove_content_type_name... OK 
 Applying auth.0002_alter_permission_name_max_length... OK 
 Applying auth.0003_alter_user_email_max_length... OK 
 Applying auth.0004_alter_user_username_opts... OK 
 Applying auth.0005_alter_user_last_login_null... OK 
 Applying auth.0006_require_contenttypes_0002... OK 
 Applying auth.0007_alter_validators_add_error_messages... OK 
 Applying auth.0008_alter_user_username_max_length... OK 
 Applying auth.0009_alter_user_last_name_max_length... OK 
 Applying auth.0010_alter_group_name_max_length... OK 
 Applying auth.0011_update_proxy_permissions... OK 
 Applying auth.0012_alter_user_first_name_max_length... OK 
 Applying sessions.0001_initial... OK 

Если миграция не прошла успешно, просмотрите предыдущие шаги, чтобы убедиться, что вы правильно настроили, прежде чем продолжить.

Сайт администратора Django

При создании приложений Django автоматически создает админ-сайт , предназначенный для использования разработчиком для тестирования и предоставления им доступа к формам, созданным для зарегистрированных моделей. Он предназначен только для использования в качестве удобной панели инструментов во время разработки, а не как фактическая панель управления, которую вы создадите отдельно, если хотите ее иметь.

Модуль admin django.contrib - это пакет, который позволяет нам настраивать сайт администратора .

Чтобы использовать автоматическое создание форм и управление моделями в Django, нам нужно зарегистрировать нашу модель на сайте admin.site .

Заходим в api_app/admin.py и зарегистрируем нашу модель:

 from django.contrib import admin 
 from .models import CartItem 
 
 admin.site.register(CartItem) 

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

 $ python manage.py createsuperuser 

Чтобы создать учетную запись, вам необходимо указать имя пользователя, адрес электронной почты и пароль. Вы можете оставить поле пустым. Пароль не отображается при вводе. Просто введите и нажмите Enter:

 Username (leave blank to use 'xxx'): naazneen 
 Email address: 
 Password: 
 Password (again): 
 Superuser created successfully. 

Наконец, давайте запустим наше приложение, чтобы убедиться, что все работает так, как задумано:

 $ python manage.py runserver 

По умолчанию приложение запускается на нашем localhost 127.0.0.1 (127.0.0.1) на порту 8000 Давайте перейдем в браузер к http://127.0.0.1:8000/admin :

Страница администратора после успешной установкиDjango{.ezlazyload}

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

Создание REST API в Django

Приложение Django полностью настроено - параметры определены, наше приложение подготовлено, модель создана, и мы создали пользователя-администратора, чтобы убедиться, что модель зарегистрирована на панели администратора.

Теперь давайте реализуем функциональность CRUD для нашей модели.

Создание объектов - обработчик запросов POST

POST используются для отправки данных на сервер. Обычно они содержат в своем теле данные, которые предполагается сохранить. При заполнении форм, загрузке изображений или отправке сообщения - POST отправляются с этими данными, которые затем обрабатываются и сохраняются.

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

Чтобы добавить представление, мы api_app_views.py файл api_app_views.py и добавим post() который получает запрос POST Он запишет тело входящего запроса в словарь и создаст CartItem , сохраняя его в базе данных:

 from django.views import View 
 from django.http import JsonResponse 
 import json 
 from .models import CartItem 
 
 class ShoppingCart(View): 
 def post(self, request): 
 
 data = json.loads(request.body.decode("utf-8")) 
 p_name = data.get('product_name') 
 p_price = data.get('product_price') 
 p_quantity = data.get('product_quantity') 
 
 product_data = { 
 'product_name': p_name, 
 'product_price': p_price, 
 'product_quantity': p_quantity, 
 } 
 
 cart_item = CartItem.objects.create(**product_data) 
 
 data = { 
 "message": f"New item added to Cart with id: {cart_item.id}" 
 } 
 return JsonResponse(data, status=201) 

Используя json , мы декодировали и проанализировали тело входящего запроса в объект, с которым мы можем работать, а затем извлекли эти данные в переменные p_name , p_price и p_quantity .

Наконец, мы создали product_data для хранения наших полей и их значений и сохранили CartItem в нашей базе данных с помощью метода create() Model , заполнив его нашими product_data .

Обратите внимание на использование JsonResponse в конце. Мы используем этот класс для преобразования нашего словаря Python в действительный объект JSON, который отправляется по HTTP обратно клиенту. Мы устанавливаем код состояния 201, чтобы обозначить создание ресурса на стороне сервера.

Если мы запустим наше приложение и попытаемся попасть в эту конечную точку, Django отклонит запрос с ошибкой безопасности. По умолчанию Django добавляет уровень защиты от атак с подделкой межсайтовых запросов (CSRF) . На практике этот токен хранится в файлах cookie нашего браузера и отправляется с каждым запросом к серверу. Поскольку этот API будет использоваться без браузера или файлов cookie, запросы никогда не будут содержать токен CSRF. Следовательно, мы должны сообщить Django, что этому методу POST не нужен токен CSRF.

Мы можем добиться этого, добавив декоратор к dispatch нашего класса, который установит для csrf_exempt значение True :

 ... 
 from django.utils.decorators import method_decorator 
 from django.views.decorators.csrf import csrf_exempt 
 
 @method_decorator(csrf_exempt, name='dispatch') 
 class ShoppingCart(View): 
 
 def post(self, request): 
 data = json.loads(request.body.decode("utf-8")) 
 ... 

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

Считается хорошей практикой писать соответствующие URL-адреса в каждом приложении, а затем включать их в файл urls.py проекта, вместо того, чтобы с urls.py

Начнем с изменения urls.py shopping_cart :

 from django.contrib import admin 
 from django.urls import path, include 
 
 urlpatterns = [ 
 path('admin/', admin.site.urls), 
 path('', include('api_app.urls')), 
 ] 

Обязательно импортировать include библиотеку из django.urls , это не импортируется по умолчанию.

Первый аргумент - это строковый путь, а второй - откуда мы получаем URL-адреса. Если наш путь равен '' или пустой, это означает, что URL-адреса нашего API будут корневым путем веб-приложения .

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

 from django.urls import path 
 from .views import ShoppingCart 
 
 urlpatterns = [ 
 path('cart-items/', ShoppingCart.as_view()), 
 ] 

Подобно собственному urls.py , первый аргумент - это подпуть, по которой будут доступны наши представления, а второй аргумент - сами представления.

Наконец, мы можем запустить приложение. Как и раньше, мы будем использовать manage.py и передать аргумент runserver

 $ python manage.py runserver 

Давайте откроем терминал и отправим POST на нашу конечную точку. Здесь вы можете использовать любой инструмент - от более продвинутых инструментов, таких как Postman, до простых инструментов на основе интерфейса командной строки, таких как curl :

 $ curl -X POST -H "Content-Type: application/json" http://127.0.0.1:8000/car 
 t-items/ -d "{\"product_name\":\"name\",\"product_price\":\"41\",\"product_quantity\":\"1\"}" 

Если все работает нормально, вы увидите сообщение:

 { 
 "message": "New item added to Cart with id: 1" 
 } 

Если вы посетите http://127.0.0.1:8000/admin/api_app/cartitem/ , добавленный нами товар также будет в списке.

Получение сущностей - обработчик запроса GET

Давайте создадим обработчик для GET , которые обычно отправляются клиентами, когда они хотят получить некоторую информацию. Поскольку у нас есть CartItem сохраненный в базе данных, имеет смысл, что кто-то захочет получить информацию о нем.

Предполагая, что существует более одного элемента, мы CartItem все записи CartItem и добавим их атрибуты в словарь, который легко преобразуется в ответ JSON для клиента.

Давайте изменим представление ShoppingCart :

 ... 
 @method_decorator(csrf_exempt, name='dispatch') 
 class ShoppingCart(View): 
 
 def post(self, request): 
 ... 
 
 def get(self, request): 
 items_count = CartItem.objects.count() 
 items = CartItem.objects.all() 
 
 items_data = [] 
 for item in items: 
 items_data.append({ 
 'product_name': item.product_name, 
 'product_price': item.product_price, 
 'product_quantity': item.product_quantity, 
 }) 
 
 data = { 
 'items': items_data, 
 'count': items_count, 
 } 
 
 return JsonResponse(data) 

Метод count() подсчитывает количество вхождений в базу данных, а метод all() извлекает их в список сущностей. Здесь мы извлекаем их данные и возвращаем их в виде ответа JSON.

Отправим GET запрос на нашу конечную точку:

 $ curl -X GET http://127.0.0.1:8000/cart-items/ 

Это приводит к ответу JSON клиенту:

 { 
 "items": [ 
 { 
 "product_name": "name", 
 "product_price": 41.0, 
 "product_quantity": 1 
 }, 
 ], 
 "count": 1 
 } 

Обновление объектов - обработчик запросов PATCH

Мы можем сохранять и извлекать данные через наш API, хотя не менее важно иметь возможность обновлять уже сохраненные сущности. Здесь в игру вступают запросы PATCH и PUT

PUT полностью заменяет данный ресурс. В то время как PATCH изменяет часть данного ресурса.

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

post() и get() находятся в одном классе представления ShoppingCart Это потому, что они влияют на более чем один товар в корзине.

PATCH влияет только на один товар в корзине. Итак, мы создадим новый класс, который будет содержать это представление, а также будущий метод delete() Добавим обработчик запроса PATCH api_app/views.py :

 ... 
 @method_decorator(csrf_exempt, name='dispatch') 
 class ShoppingCartUpdate(View): 
 
 def patch(self, request, item_id): 
 data = json.loads(request.body.decode("utf-8")) 
 item = CartItem.objects.get(id=item_id) 
 item.product_quantity = data['product_quantity'] 
 item.save() 
 
 data = { 
 'message': f'Item {item_id} has been updated' 
 } 
 
 return JsonResponse(data) 

Мы получим элемент с заданным идентификатором и изменим его перед повторным сохранением.

Поскольку мы не хотим, чтобы покупатель мог изменять цену или название продукта, мы делаем переменным только количество товара в корзине для покупок. Затем мы вызываем метод save() для обновления уже существующей сущности в базе данных.

Теперь нам нужно зарегистрировать конечную точку для этого, так же, как мы это сделали для cart-items/ endpoint:

api_app/urls.py :

 from django.urls import path 
 from .views import ShoppingCart, ShoppingCartUpdate 
 
 
 urlpatterns = [ 
 path('cart-items/', ShoppingCart.as_view()), 
 path('update-item/<int:item_id>', ShoppingCartUpdate.as_view()), 
 ] 

На этот раз мы полагаемся не только на HTTP-глагол. В прошлый раз отправка запроса POST /cart-items привела к post() , а отправка GET привела к запуску метода get()

Здесь мы добавляем URL-переменную - /<int:item_id> . Это динамический компонент в URL-адресе, который сопоставляется с item_id из представления. На основе предоставленного значения соответствующий элемент извлекается из базы данных.

Отправим запрос PATCH http:127.0.0.1:8000/update-item/1 с соответствующими данными:

 $ curl -X PATCH http://127.0.0.1:8000/update-item/1 -d "{\"product_quantity\":\"3\"}" 

Это приводит к ответу JSON:

 { 
 "message": "Item 1 has been updated" 
 } 

Давайте также проверим это через панель администратора по адресу: http://127.0.0.1:8000/admin/api_app/cartitem/1/change/ .

Удаление объектов - обработчик запроса DELETE

Наконец, последняя часть функциональности CRUD - удаление сущностей.

Чтобы удалить товар из корзины, мы будем использовать тот же ShoppingCartUpdate поскольку он влияет только на один товар. Мы добавим delete() который принимает идентификатор элемента, который мы хотим удалить.

Подобно тому, как мы save() элемент при обновлении его новыми значениями, мы можем использовать delete() для его удаления. Добавим метод delete() в api_app/views.py :

 ... 
 @method_decorator(csrf_exempt, name='dispatch') 
 class ShoppingCartUpdate(View): 
 
 def patch(self, request, item_id): 
 ... 
 
 def delete(self, request, item_id): 
 item = CartItem.objects.get(id=item_id) 
 item.delete() 
 
 data = { 
 'message': f'Item {item_id} has been deleted' 
 } 
 
 return JsonResponse(data) 

А теперь давайте отправим DELETE и предоставим идентификатор элемента, который мы хотим удалить:

 curl -X "DELETE" http://127.0.0.1:8000/update-item/1 

И мы получим такой ответ:

 { 
 "message": "Item 1 has been deleted" 
 } 

Посещение http://127.0.0.1:8000/admin/api_app/cartitem/ подтверждает, что элемента больше нет.

Заключение

В этом кратком руководстве мы рассмотрели, как создать REST API в Python с помощью Django . Мы рассмотрели некоторые основы Django, начали новый проект и приложение в нем, определили необходимые модели и реализовали функциональность CRUD.

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

comments powered by Disqus