Рубрики
Без рубрики

Создайте правильный API REST с Django, DRF, JWT и OpenAPI

Резюме этого поста. В этом посте я представлю следующие концепции, не стесняйтесь пропустить … Tagged с Django, Python, Openapi.

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

  1. Создать проект Django с Django Rest Framework
  2. Добавить спецификации OpenAPI для генерации документации по динамической API
  3. Используйте JWT (JSON Web Token) для аутентификации и авторизации

Шаг № 1 – Создайте новый проект

Начните новый проект (либо с Pycharm -> Новый проект Django или django -admin startproject restapi_article ). Я не буду покрывать основы, потому что вы всегда можете пойти в Джанго Учебник и учиться на официальной документации (которую я нахожу лучшим на момент написания этой статьи).

Как только у нас будет настроен проект Django, нам нужно установить библиотеки Python ниже (для лучшего опыта вы должны использовать Виртуальная среда ):

  • Джанго
  • djangorestframework
  • DRF-YASG
  • djangorestframework-simplejwt

Всегда хорошо соответствовать стандартам, поэтому мы должны создать Требования.txt Файл со всеми библиотеками. Вы можете создать его, используя эту команду в папке Project Root PIP FREEZE> Требования.txt Анкет Файл должен выглядеть так:

asgiref==3.2.10
certifi==2020.6.20
chardet==3.0.4
coreapi==2.3.3
coreschema==0.0.4
Django==3.1.1
djangorestframework==3.11.1
djangorestframework-simplejwt==4.4.0
drf-yasg==1.17.1
idna==2.10
inflection==0.5.1
itypes==1.2.0
Jinja2==2.11.2
MarkupSafe==1.1.1
packaging==20.4
PyJWT==1.7.1
pyparsing==2.4.7
pytz==2020.1
requests==2.24.0
ruamel.yaml==0.16.12
ruamel.yaml.clib==0.2.2
six==1.15.0
sqlparse==0.3.1
uritemplate==3.0.1
urllib3==1.25.10

Далее создайте приложение с командой Python3 Manage.py StartApp Restapi

Ваша структура файла после создания должна выглядеть так:

. 
├── restapi
│   ├── migrations
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── restapi_article
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── venv
├── db.sqlite3
├── manage.py
└── requirements.txt

И добавить в наш restapi_article \ settings.py Эти три приложения

INSTALLED_APPS = [
    ...
    'rest_framework',
    'drf_yasg',
    'restapi',
]

Редактировать urls.py Чтобы использовать root restapi.urls в качестве основных URL -адресов приложения API, мы будем иметь Localhost: 8000/Admin Играть с административной панелью Джанго и /api/v1 Конечная точка в качестве префикса для всех URL -адресов (это действительно хороший способ версировать ваш API, как это может легко измениться в будущем)

from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include('restapi.urls')),
]

Шаг 2 – Создайте модели данных

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

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

Todo (Future): Создайте модель событий, где вы можете попросить некоторых людей присоединиться к вам в питье. Ему придется объединить несколько профилей/пользователей с одной датой

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

models.py

from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver


class Day(models.Model):
    day = models.DateField()


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(max_length=500, blank=True)
    location = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)
    days = models.ManyToManyField(Day, through='DrinkingDay')


class DrinkingDay(models.Model):
    profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
    day = models.ForeignKey(Day, on_delete=models.CASCADE)
    note = models.TextField(max_length=1000, blank=True)

# Use signals so our Profile model will be automatically created
# or updated when we create or update User instance
# https://docs.djangoproject.com/en/3.1/topics/signals/
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)


@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
    instance.profile.save()

Теперь давайте создадим и применяем миграции для БД, а затем создадим суперпользователь, чтобы иметь возможность войти в нашу панель администратора. Вам нужно запустить эти три команды один за другим (вы можете изменить электронную почту и имя пользователя), конечно)

python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser --email admin@example.com --username admin

Шаг 3 – Создать сериализаторы

Теперь нам нужно добавить сериализаторы Анкет Serializer в ярлыке – это способ создать JSON из объекта. Давайте начнем писать сериализаторы для модели пользователей и профиля (нам нужно сделать их обоих, так как это не будет работать без пользователя):

serializers.py

from django.contrib.auth.models import User
from rest_framework import serializers

from restapi.models import Profile


class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ['url', 'username', 'email', 'groups']


class ProfileSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Profile
        fields = ['user', 'bio', 'location', 'birth_date', 'days']

Шаг 4 – Создать виды

Теперь, когда у нас есть сериализаторы, мы можем создавать представления в Джанго. Итак, на каждом URL мы увидим, что хотим. Давайте сделаем это для USerview и ProfileView (хотя здесь мы могли бы опустить представление пользователя, поскольку это не требуется.

Изменение views.py (в папке API REST):

from django.contrib.auth.models import User
from rest_framework import viewsets

from restapi.models import Profile
from restapi.serializers import ProfileSerializer, UserSerializer


class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.all().order_by('-date_joined')
    serializer_class = UserSerializer


class ProfileViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows profiles to be viewed or edited.
    """
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer

Шаг 5 – Зарегистрируйте маршрутизатор для просмотров

DRF позволяет нам использовать что -то, что называется маршрутизаторы Анкет Это будет обрабатывать автоматическую маршрутизацию URL для Django для нас.

Изменение urls.py (в папке Restapi):

from django.urls import path, include
from rest_framework import routers

from restapi import views

router = routers.DefaultRouter()
router.register(r'profile', views.ProfileViewSet)
router.register(r'user', views.UserViewSet)

urlpatterns = [
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('', include(router.urls)),
]

Теперь мы можем запустить наше приложение с Python Manage.py Runserver и пойти в http://127.0.0.1:8000/api/v1/ Чтобы увидеть, что наше приложение работает:)

Если вы создали суперпользователь, это должно автоматически создать для него профиль, поэтому переход к http://127.0.0.1:8000/api/v1/profile/1/ должен позволить вам обновить профиль суперпользователя.

Шаг 6 – Добавить документацию Swagger

Все уже хорошо, чтобы идти, нам просто нужно создать URL для демонстрации документации Swagger. Кроме того, это хорошая практика для создания Schema_View, чтобы описать наш API для других разработчиков.

Обновление urls.py (в папке Restapi):

from django.urls import path, include, re_path
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
from rest_framework import routers, permissions

from restapi import views

router = routers.DefaultRouter()
router.register(r'profile', views.ProfileViewSet)
router.register(r'user', views.UserViewSet)

schema_view = get_schema_view(
   openapi.Info(
      title="Drinking Day API",
      default_version='v1',
      description="This API allows us to keep a diary of our daily drinking",
      terms_of_service="https://www.scvconsultants.com",
      contact=openapi.Contact(email="michal@scvconsultants.com"),
      license=openapi.License(name="MIT License"),
   ),
   public=True,
   permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    path('', include(router.urls)),
    re_path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
    path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
]

Теперь мы должны быть в состоянии увидеть Swagger UI по адресу: http://127.0.0.1:8000/api/v1/swagger/ и .json + .yaml схема по ссылкам ниже: http://127.0.0.1:8000/api/v1/swagger.json http://127.0.0.1:8000/api/v1/swagger.yaml

Шаг 7 – Добавьте токены JWT, чтобы ограничить доступ к модели профиля.

Во -первых, нам нужно обновить настройки.py Чтобы добавить классы jwt auth. Я также добавляю страницу, так как это отличная практика для использования размера страницы по умолчанию для коллекций (нам не нужно отправлять все сразу, верно?).

# REST FRAMEWORK config
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 25,
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}

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

Давайте добавим его в urls.py

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    ...
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    ...
]

Теперь вы можете перейти к: http://127.0.0.1:8000/api/v1/token/ и отправьте свои учетные данные суперпользователя в качестве поста, и вы должны получить красивый рабочий токен, который вы можете расшифровать и проверить здесь и он должен декодировать на user_id, который соответствует вашим учетным данным (вероятно, будет, вероятно, 1).

Добавить теперь разрешения к нашим взглядам действительно прост, первый импорт в views.py

from rest_framework import permissions

А затем в нашем конкретном представлении (давайте используем ProfileViewSet для этого) добавить:

class ProfileViewSet(viewsets.ModelViewSet, mixins.UpdateModelMixin):
    ...
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

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

Далее:

  • Создание CI/CD с использованием GitHub и Хероку Анкет
  • Докеризация
  • Интеграционные тесты для API с Pytest

Оригинал: “https://dev.to/misiekofski/create-proper-rest-api-with-django-drf-jwt-and-openapi-chp”