Разобравшись с теорией разработки API переходим к практике. Сначала освежим в памяти создание API с нуля с учетом тестирования, организации безопасности и мониторинга, а в будущих модулях разберемся с версионированием.
В занятии используем django-rest-framework, как более популярный API пакет. django-ninja рассмотрим в другом занятии
Львиная доля API в продуктах это или перекладывание JSON из одного формата в другой или выполнение какого-то действия над данными. DRF (django-rest-framework) хорошо справляется с такими задачами, позволяет за минимальное время создать API на основе существующей модели. В этом материале рассмотрим как это происходит, а в следующих "накрутим сверху" тестирование, доступ к данным и мониторинг.
Модели
Хорошо начинать описание API в коде с тестов (согласно Test Driven Development (TDD)), однако, чаще начинается с описания моделей: основных и вспомогательных данных, взаимосвязи между моделями.
Представим, что делаем небольшой магазин, где есть товары по категориям, можно купить товар со склада, оставить отзыв. В первом приближении модели можно сделать такие:
# models.py
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MinValueValidator, MaxValueValidator
class TimeModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class ContentModel(models.Model):
is_active = models.BooleanField(default=True)
slug = models.SlugField(unique=True)
title = models.CharField(max_length=100, unique=True)
description = models.TextField(blank=True)
class Meta:
abstract = True
def __str__(self):
return self.title
class Category(TimeModel, ContentModel):
"""Категория товара"""
pass
class Tag(TimeModel, ContentModel):
"""Характеристика товара"""
color = models.CharField(max_length=7, default='#000000') # HEX color
class Product(TimeModel, ContentModel):
"""Описание товара"""
PRIORITY_CHOICES = [
('low', 'Низкий'),
('medium', 'Средний'),
('high', 'Высокий'),
]
price = models.DecimalField(max_digits=10, decimal_places=2)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
tags = models.ManyToManyField('Tag', blank=True, related_name='products')
stock_quantity = models.PositiveIntegerField(default=0)
class Review(TimeModel):
"""Отзыв на товар"""
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='reviews')
user = models.ForeignKey(User, on_delete=models.CASCADE)
rating = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
content = models.TextField()
class Meta:
unique_together = ['product', 'user'] # Один отзыв от пользователя на продукт
Абстрактные модели позволяют систематизировать поведение различных моделей