3 горизонтальные линии, бургер
3 горизонтальные линии, бургер
3 горизонтальные линии, бургер
3 горизонтальные линии, бургер

3 горизонтальные линии, бургер
Удалить все
ЗАГРУЗКА ...

Содержание



    Как легко написать АПИ на Джанго используя Django REST API.

    Часы
    24.02.2025
    /
    Часы
    02.10.2025
    /
    Часы
    7 минут
    Глазик
    4051
    Сердечки
    0
    Соединённые точки
    1
    Соединённые точки
    6
    Соединённые точки
    0

    Вступление

    Доброго времени суток. На примере моего проекта SearchResultParser я покажу как можно сделать API для вашего сайта и то, как этот API можно будет использовать со стороны клиента. Бэкенд я пишу на Django, а за создание и настройку его API будет заниматься Django REST framework.
    О клиентской части сайта (фронтенд). Конкретно эта статья будет описывать работу React фреймворка с Axios библиотекой. Но это, в сущности, неважно. Работа с API всегда представляет собой отправку некоторых запросов на сервер и обработкой обратных ответов. А то чем оно отправляется (Axios) или то, чем оно обрабатывается (React) не столь важно. Но для полноты картины я ещё предоставлю и клиентскую часть.
    Процесс создания Django REST API для сайта можно описать следующими шагами:
    1. Создаём проект и предварительно устанавливаем все необходимые пакеты, настраиваем его
    2. Создаём модели которые, хотим использовать на стороне клиента
    3. Создаём сериализаторы к ним.
    4. Создаём представления(обработчики) для них
    5. Подключаем роутеры и пути
    6. Пишем и настраиваем клиент для работы с API
    По объективным причинам 1 пункт я пропущу, ибо проект SRP уже создан и настроен, можешь посмотреть как его настроить и привести в рабочий вид, а я тем временем опишу дальнейшие шаги.
    Добавлю ещё то, что ты должен будешь установить и подключить следующие python-модули:
    1. django-cors-headers: для активации так называемого Cross-Origin Resource Sharing (CORS) для общения React приложения и Django API.
    2. djangorestframework: это Django приложение, которое позволит нам с лёгкостью построить АПИ для нашего сайта.
    3. django: бэкенд нашего сайта, управление базой данных
    Вот так, подключи ново установленные модули в settings.py:
    INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # Django REST framework 'corsheaders', 'rest_framework', ## 'Backend.apps.BackendConfig', 'Frontend.apps.FrontendConfig', 'Authentication.apps.AuthenticationConfig', # BY ALLAUTH 'allauth', 'allauth.account', 'allauth.headless', 'allauth.mfa', 'allauth.usersessions', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', # REST framework 'corsheaders.middleware.CorsMiddleware', # BY ALLAUTH "allauth.account.middleware.AccountMiddleware", ]
    Так же, прошу заметить я имею отдельное приложение Backend. Там будет весь мой API. Его тоже нужно подключить, ибо там мы и будем всё писать.

    Настраиваем REST API для Django, создаём модели

    Итак, сейчас мой сайт SearchResultPaser имеет систему парсинга данных из поисковых систем. На момент написания данной статьи, только Google. Плюс возможность добавлять новые поисковые системы и удалять старые. Но, данный сайт не ограничивается этим.
    У меня ещё должны быть, так называемые пресеты, то есть, говоря на языке джанго, модель Preset, которая будет доступна каждому зарегистрированному пользователю для сохранения и настройки их любимых поисковых запросов.
    Вот полный код модели, на её примере мы и будем заниматься сереализацией:
    class Preset(models.Model): class Exports(models.TextChoices): AsJson = 'As JSON' AsCsv = 'As CSV' output = models.CharField(max_length=120, choices=Exports, default=Exports.AsExel) name = models.CharField(max_length=120) user = models.ForeignKey(get_user_model(), null=True, on_delete=models.CASCADE) timeCreated = models.DateTimeField(auto_now=True, auto_created=True) title = models.BooleanField(default=False) description = models.BooleanField(default=False) url = models.BooleanField(default=False) isVerbose = models.BooleanField(default=False) queries = models.ManyToManyField(Query) def __str__(self): return self.name
    Как можно видеть, у данной модели есть связь ManyToMany (Одна запись в таблицу Preset может быть связана со множеством записей в БД, модели Query) с моделью Query. Query - это обёртка для хранения запросов пользователей. Хочу обратить внимание, я буду сохранять только те запросы, которые необходимы для персета. В общем-то, ничего особенного в данной модели больше нет. Расмотрим уже модель Query:
    class Query(models.Model): query = models.CharField(max_length=512) searchEngine = models.ForeignKey(SearchEngine, on_delete=models.CASCADE) def __str__(self): return self.query
    Она ещё проще, есть текстовое поле query и связь ForeignKey со следующей моделью SearchEngine(Одна запись в таблицу Query, может иметь связь только с одной записью модели SearchEngine).
    Ну и конечно модель SearchEngine:
    class SearchEngineStatus(models.TextChoices): Ready = 'Ready' InDevelopment = 'In development' NeedsSetup = 'Needs setup' class SearchEngine(models.Model): name = models.CharField(max_length=120) icon = models.ImageField(max_length=120, blank=True, null=True) status = models.CharField(max_length=120, choices=SearchEngineStatus, default=SearchEngineStatus.NeedsSetup) config = models.JSONField(max_length=500, blank=True, null=True, default=dict) def __str__(self): return self.name
    У каждой записи данной модели есть текущее состояние. Ready - значит, пользователь может его выбрать на сайте и получить соответствующий результат парсинга. InDevelopment - значит соответствующий парсер ещё не написан и его нельзя использовать сейчас. И последний статус, NeedsSetup, означает, что пользователь может использовать данный парсер, как и в первом случае, но предварительно требуется настройка в профиле пользователя.
    Так же хочу отметить поле config. Каждая поисковая система уникальна при попытке её парсинга, через официальный API. В любом случае добавлять и удалять записи в таблицу SearchEngine, могу и должен только я.

    Настраиваем REST API для Django, создаём сериализаторы

    Чтобы иметь возможность работать с данными моделями на стороне клиента (через JS), нам потребуются Сереализаторы. Для этого импортируем модуль serializers из rest_framework и пишем, то что хотим сериализовать:
    Да, ещё. У тебя должен быть создан файл Backend/serializers.py. Не забудь создать его, а потом вставить код ниже.
    from rest_framework import serializers from .models import Preset, SearchEngine, Query class PresetSerializer(serializers.ModelSerializer): class Meta: model = Preset fields = ('id', 'output', 'name', 'user', 'title', 'description', 'url', 'isVerbose', 'queries') class QuerySerializer(serializers.ModelSerializer): class Meta: model = Query fields = ('id', 'query', 'searchEngine') class SearchEngineSerializer(serializers.ModelSerializer): class Meta: model = SearchEngine fields = ('id', 'name', 'icon', 'status')
    Ничего особенного в этих сериализаторах нет. Создаём класс посредством наследования. Потом выбираем модель и поля, которые хотим сериализовать. Двигаемся дальше.

    Настраиваем REST API для Django, создаём особые представления

    Теперь, нам бы видеть что мы добавляем, удаляем или изменяем. Нужно создать представления в файле Backend/views.py:
    from rest_framework import viewsets from .serializers import PresetSerializer, QuerySerializer, SearchEngineSerializer from .models import Preset, Query, SearchEngine class PresetModelView(viewsets.ModelViewSet): serializer_class = PresetSerializer queryset = Preset.objects.all() def get_queryset(self): if self.request.user.is_authenticated: return self.queryset.filter(user=self.request.user) return Preset.objects.none() class QueryModelView(viewsets.ModelViewSet): serializer_class = QuerySerializer queryset = Query.objects.all() http_method_names = ('get', 'post') class SearchEngineModelView(viewsets.ModelViewSet): serializer_class = SearchEngineSerializer queryset = SearchEngine.objects.all() http_method_names = ('get')
    Пройдёмся по каждому из них. PresetModelView, его особенность в том что мы фильтруем все наши пресеты в зависимости от пользователя, который хочет их получить. Особенностью SearchEngineModelView, является, то что её можно только просматривать, но не добавлять или удалять записи из БД нельзя.

    Настраиваем REST API для проекта, подключаем представления

    И последний штрих. Чтобы наконец увидеть в действии REST API, нужно подключить созданные ранее классы-представления: QueryModelViews, SearchEngineModelViews и PresetModelView. Для этого в файле Backend/urls.py подключим новый роутер:
    from django.contrib import admin from django.urls import path, include from rest_framework import routers from Backend import views from django.conf.urls.i18n import i18n_patterns router = routers.DefaultRouter() router.register(r'presets', views.PresetModelView, 'preset') router.register(r'queries', views.QueryModelView, 'query') router.register(r'se', views.SearchEngineModelView, 'se') urlpatterns = [ path('admin/', admin.site.urls), path('api/', include(router.urls)), # BY ALLAUTH path('accounts/', include('allauth.urls')), path("_allauth/", include("allauth.headless.urls")), ] urlpatterns += i18n_patterns( path('', include('Frontend.urls')), path('', include('Authentication.urls')), )
    Всё, готово. Давай посмотрим что получилось. Перейди по адресу localhost:8000/api/ , ты увидишь, что-то вроде этого:
    Как видно из картинки мы успешно подключили и настроили наш роутер. Перейдём по любой из представленных ссылок, например localhost:8000/api/se/
    Или например, давай посмотрим страницу пресетов, ради чего собственно это всё и затевалось. Итак, у меня есть две учётные записи dima и some и у каждой свои пресеты. Посмотрим как работает фильтрация по пользователю:
    Пользователь some
    Пользователь dima
    Как видно, у первого пользователя только один пресет с id=3. А у второго 2 пресета с id=1 и 2.

    Дополнительная настройка REST фреймворка

    У тебя наверняка возник вопрос, что всё это красиво, но хочется просто получить JSON файл на стороне клиента и сделать то что должно. У меня так же зудело и я нашёл довольно элегантное решение для данной проблемы.
    Смотри, в режиме разработки нам будут показываться предыдущие страницы на картинках, но если мы поменяем режим (т.е. сделаем debug=False в settings.py) мы будем получать вот такие вот ответы:
    У меня в firefox стоит специальное расширение которое делает вот такую вот красоту. Расширение называется, если что, JSONView и доступно для Chrome тоже.
    Чтобы добиться такого результата, достаточно добавить в конце файла settings.py следующие строчки:
    if not DEBUG: REST_FRAMEWORK = { # Need to be specified explicitly, otherwise for everyone will be available HTML version of REST framework 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', ] }
    Мы просто меняем рендер по умолчанию и получаем то, что получаем ... JSON файл.

    Работа с API со стороны клиента

    Работать с API со стороны клиента, очень просто. Необходимо сделать соответствующий AJAX запрос и обработать ответ. Например, так я получу все доступные записи в SearchEngine модели.
    axios.get("/api/se/", { headers: { "accept": "application/json", 'Content-Type': "application/json", } }) .then( resp => { // Your code }) .catch( error => { // Your error code }
    Для примера, я хочу добавлять разные иконки статусов для каждого из поискового движка. Чтобы получить непосредственные данные из ответа, мы обратимся к специальному объекту data в ответе и после к необходимым нам полям. И в зависимости от статуса движка, мы либо добавим ему обработчик, либо нет.
    axios.get("/api/se/", { headers: { "accept": "application/json", 'Content-Type': "application/json", } }) .then( resp => { const list = resp.data if (engine_list.length > 0){ engine_list = [] } axios.get("/api/seue/", { headers: { "accept": "application/json", 'Content-Type': "application/json", } }) .then( resp2 => { for (let i = 0; i < resp.data.length; i++){ // Find name of engine var name = list[i]['name'] var icon = list[i]['icon'] var name_block = "" var event = "" var isDisabled = true const config = resp2.data[0]['config'] var status = config[i]['engine-status'] switch (status){ case 'Ready': var isDisabled = false var name_block = ( <div className='flex flex-row gap-1 items-center'> <img className='w-4 h-4' src={icon}></img> <div>{name}</div> </div> ) var event = (event)=>{ onAddQuery(event, t) } break case 'In development': var name_block = ( <div className='flex flex-row gap-1 items-center'> <img className='w-4 h-4' src={icon}></img> <div className="text-gray-500">{name}</div> <ReportGmailerrorredIcon sx={{ color: red[500] }} ></ReportGmailerrorredIcon> <div>{status}</div> </div> ) break case 'Needs setup': var name_block = ( <div className='flex flex-row gap-1 items-center'> <img className='w-4 h-4' src={icon}></img> <div className="text-gray-500">{name}</div> <ReportGmailerrorredIcon sx={{ color: yellow[500] }} ></ReportGmailerrorredIcon> <div>{status}</div> </div> ) break } // Push engines to pop up window, for to be selected later engine_list.push( <ListItem> <ListItemButton data-engine_name={name} disabled={isDisabled} onClick={event}> <div className="flex flex-col gap-6"> <div className="flex flex-row gap-2 items-center justify-between" > {name_block} <div id='toRemoveEngineStuff' className='hidden flex flex-row gap-1 items-center w-fit'> <IconButton id='onDeleteQuery' className='w-fit'><DeleteForeverIcon/></IconButton> </div> </div> <Divider id='toRemoveEngineStuff' className="hidden w-full self-center" component='div' variant="middle"/> </div> </ListItemButton> </ListItem> ) } }) .catch( error => { Msg(`${error}`) }) }) .catch( error => { Msg(`${error}`) })
    Да, я понимаю, этот блок кода гораздо сложнее, с вложенными друг в друга запросами. Но этот пример идеально подходит для демонстрации того, как можно получить данные из ответа.
    А вот и ответы с сервера:
    Для localhost:8000/api/se/
    Для localhost:8000/api/seue/
    И то, как это может выглядеть на сайте:

    Заключение

    Вот и закончили мы настройку API нашего сайта при помощи Django REST фреймворка. Конечно, по началу может показаться что всё это как-то запутанно и чересчур сложно, но поверь, когда твой проект станет чуть-чуть сложней, чем одностраничный лендинг, ты сразу вспомнишь про REST фреймворк и про то, что он не такой уж и запутанный ( •̀ ω •́ )y

    Не забудь поделиться, лайкнуть и оставить комментарий)

    Комментарии

    (2)

    captcha
    Отправить
    ЗАГРУЗКА ...
    Часы
    11 июля 2025 г. 21:52
    Человек
    Миша
    Большое спасибо вам за подробный гайд, а подскажите пожалуйста, куда нужно класть файл с JS кодом для взаимодействия этого файла с бэкэндом?
    Все ответы (1)
    Ответить
    ЗАГРУЗКА ...
    Часы
    2 мая 2025 г. 11:05
    Человек
    Ольга
    помогите, пож-та, как посмотреть как будет выглядеть сайт для конечного пользователя??? http://127.0.0.1:8000/api/categories/ - вот например я получаю json данные, но как же посмотреть как будет видеть их конечный пользователь вместе с js статикой и прочей красотой???
    Все ответы (1)
    Ответить
    ЗАГРУЗКА ...

    Другое

    Похожие статьи


    Сделать формы авторизации и регистрации пользователей на Django

    Часы
    16.10.2023
    /
    Часы
    05.10.2025
    Глазик
    641
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Реализовать систему аутентификации пользователей. Для этого создаётся форма регистрации и форма для входа и выхода на сайте timthewebmaster.com.

    Как использовать React с Django API. Django сервер для React сайта, как сделать

    Часы
    24.07.2024
    /
    Часы
    02.10.2025
    Глазик
    671
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В данной статье я опишу процесс соединения React и Django под одним проектом. Мы настроим API для общения обоих между собой, а так же подключим TailwindCSS библиотеку, дабы упростить создание …

    Как (и можно ли) объединить React JS с Django проектом ч. 1

    Часы
    03.08.2024
    /
    Часы
    02.10.2025
    Глазик
    1267
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье ты узнаешь как создать Django приложение и настроить его для работы с React JS чтобы получилось полноценное фулстак приложение. Так же в статье приведено видео-туториал и скачиваемые …

    Как добавить переводы (выбор языка) для твоего телеграм бота telegram/aiogram/python

    Часы
    14.01.2025
    /
    Часы
    02.10.2025
    Глазик
    975
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье я покажу, как сделать так, чтобы английский бот писал на русском, то есть сделаю бота многоязычными на aiogram. И сделаю я это при помощи пакета Babel + …

    Как сделать кнопку загрузки контента используя Django, REST API, HTMx

    Часы
    01.04.2025
    /
    Часы
    01.10.2025
    Глазик
    287
    Сердечки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    Соединённые точки
    0
    В этой статье я опишу способ, как можно реализовать асинхронную загрузку контента(статей) при помощи кнопки "Больше", которая сделана при помощи Django, REST API, HTMx и стилизовано при помощи DaisyUI

    Использованные термины


    Релевантные вопросы