Рубріки: Теория

Django Rest App с аннотированным способом использования типов

Игорь Грегорченко

Существует множество учебников по Django CRUD. Я искал учебник, который использует аннотацию типов Python, но не нашел ни одного, который бы мне понравился, поэтому я изучил его и сделал сам. Как мне кажется, получилось самое понятное руководство по подключению баз данных (БД), ORM, REST API и CRUD для Джанго из всех, что я видел.

Преимущество аннотации типов в том, что она выдает предупреждение о нарушении целостности типа, если вы поместите туда какой-либо несоответствующий тип. Иначе говоря, преимущество в том, что она помогает найти ошибку раньше, хотя при этом нет никакого прироста или потери производительности. У нас есть ссылка на github — вы можете сразу клонировать и запустить проект, который мы будем ковырять в образовательных целях дальше.


Сначала вам нужно установить Python версии 3.5+, он также установит инструмент управления пакетами Python pip. Есть еще один инструмент под названием `pipenv`, который представляет собой комбинацию pip и виртуального окружения, он позволяет легко управлять проектом.

Давайте попробуем, сначала установим его с помощью pip:

pip install pipenv

Он установит pipenv, мы будем использовать его для управления и песочницы нашего python-проекта. Это застрахует от вмешательства со стороны других проектов python на той же хост-машине. Теперь мы установим Python и Django и начнем создавать наш проект.

pipenv --three # Создаем виртуальную среду для этого проекта...
pipenv install django # Добавление django в [пакеты] Pipfile...

Чтобы активировать виртуальную среду этого проекта, выполните следующее:

pipenv shell

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

django-admin startproject InterconnectionContact .

Это создаст проект InterconnectionContact в вашей текущей директории. Не забудьте поставить точку `.` после имени проекта, иначе он создаст одноименные родительский каталог и имя проекта, что приведет к путанице.

Теперь проверьте структуру каталогов. Она будет выглядеть примерно так:

.
├── InterconnectionContact
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
├── Pipfile
└── Pipfile.lock

Теперь проверьте, правильно ли работает ваш проект:

pipenv run ./manage.py runserver

После этого последует такой вывод:

Performing system checks…
System check identified no issues (0 silenced).
You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run ‘python manage.py migrate’ to apply them.
April 02, 2018–11:30:44
Django version 2.0.3, using settings ‘InterconnectionContact.settings’
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

Если все идет правильно, вы увидите что-то вроде этого.

Давайте создадим приложение для этого проекта. Выполните следующую команду:

pipenv run ./manage.py startapp contact

Это создаст приложение contact для проекта ‘InterconnectionContact‘. Давайте проверим структуру каталогов.

.
├── contact
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── db.sqlite3
├── InterconnectionContact
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py
├── Pipfile
└── Pipfile.lock

Это наша начальная структура проекта. Давайте напишем немного кода. На самом деле мы будем писать код в файлах views.py и models.py и создадим другой файл urls.py в каталоге contact, который будет получать входящие запросы из основного файла urls.py проекта.

Давайте проверим код в файле models.py:

"""
models module for organising table and validation
"""
from django.db import models


class Contact(models.Model):
    """
    A class for storing instance contact
    """
    contact_id = models.AutoField(primary_key=True)
    first_name = models.CharField(max_length=130, blank=True, null=True)
    middle_name = models.CharField(max_length=130, blank=True, null=True)
    last_name = models.CharField(max_length=130, blank=True, null=True)
    email = models.EmailField(max_length=110, blank=True, null=True)
    country = models.CharField(max_length=65, blank=True, null=True)
    phone = models.CharField(max_length=19, null=True)
    address = models.CharField(max_length=254, blank=True, null=True)

Теперь переместим проект, который создаст таблицу в базе данных, для простоты мы будем использовать встроенную базу данных sqlite3.

python3.6 manage.py migrate

Создадим файл views.py, в нем мы напишем всю бизнес-логику.

"""
views for organising business logic
"""
from typing import Dict, Any
from django.http import Http404
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from contact.models import Contact
from contact.serializers import ContactSerializer
from django.http import HttpRequest, HttpResponse


class ContactView(APIView):
    """
    Get or post a contact instance.
    """
    def get(self, request: HttpRequest) -> Response:
        """
        :param request:
        :return:
        """
        contact = Contact.objects.all()
        serializer = ContactSerializer(contact, many=True)
        return Response(serializer.data)

    def post(self, request: HttpRequest) -> Response:
        """
        :param request:
        :return:
        """
        serializer = ContactSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response({"serializer.data": 200, "status": status.HTTP_201_CREATED})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class ContactDetail(APIView):
    """
     Update or delete a contact instance.
    """
    def get_object(self, contact_id: int) -> Response:
        """
        :param id:
        :return:
        """
        try:
            return Contact.objects.get(contact_id=contact_id)
        except Contact.DoesNotExist:
            raise Http404
            
    def get(self, request: HttpRequest, contact_id: int, format=None) -> Response:
        """
        :param id:
        :return:
        """
        contact = self.get_object(contact_id)
        serializer = ContactSerializer(contact)
        return Response(serializer.data)
            
    def put(self, request: HttpRequest, contact_id: int) -> Response:
        """
        :param request:
        :param id:
        :return:
        """
        contact = self.get_object(contact_id)
        serializer = ContactSerializer(contact, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request: HttpRequest, contact_id: int) -> Response:
        """
        :param request:
        :param id:
        :return:
        """
        contact = self.get_object(contact_id)
        contact.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

В этом файле views.py мы применим все CRUD-операции, используя два url’a.

Когда пользователь отправит запрос через файл urls.py, он найдет и выполнит соответствующий метод в классе в файле views.py. Вот наш файл urls.py:

from django.conf.urls import url
from django.urls import path
from contact.views import ContactView, ContactDetail

urlpatterns = [
    path('api/v1/contact/', ContactView.as_view()),
    path('api/v1/contact/<int:contact_id>', ContactDetail.as_view()),
]

Для десериализации сериализации модели существует файл serializers.py. Он используется для преобразования объекта Python в json или наоборот.

from contact.models import Contact
from rest_framework import serializers


class ContactSerializer(serializers.ModelSerializer):
    """Serializes an Address object"""

    class Meta:
        model = Contact
        fields = ("contact_id", "first_name", "last_name", "middle_name", "email", "country", "phone", "address")

И, наконец, есть корневой файл url.py в InterconnectionProject/urls.py.

Все входящие запросы сначала попадают сюда и перенаправляются в файл app contact/urls.py.

from django.conf.urls import url
from django.urls import include, path
urlpatterns = [
    path('', include('contact.urls')),
]

Это все, что у нас есть для вас на данный момент. Если вы хотите запустить этот проект, клонируйте его из репозитория github и следуйте инструкциям, приведенным в файле README.md

Останні статті

Обучение Power BI – какие онлайн курсы аналитики выбрать

Сегодня мы поговорим о том, как выбрать лучшие курсы Power BI в Украине, особенно для…

13.01.2024

Work.ua назвал самые конкурентные вакансии в IТ за 2023 год

В 2023 году во всех крупнейших регионах конкуренция за вакансию выросла на 5–12%. Не исключением…

08.12.2023

Украинская IT-рекрутерка создала бесплатный трекер поиска работы

Unicorn Hunter/Talent Manager Лина Калиш создала бесплатный трекер поиска работы в Notion, систематизирующий все этапы…

07.12.2023

Mate academy отправит работников в 10-дневный оплачиваемый отпуск

Edtech-стартап Mate academy принял решение отправить своих работников в десятидневный отпуск – с 25 декабря…

07.12.2023

Переписки, фото, история браузера: киевский программист зарабатывал на шпионаже

Служба безопасности Украины задержала в Киеве 46-летнего программиста, который за деньги устанавливал шпионские программы и…

07.12.2023

Как вырасти до сеньйора? Девелопер создал популярную подборку на Github

IT-специалист Джордан Катлер создал и выложил на Github подборку разнообразных ресурсов, которые помогут достичь уровня…

07.12.2023