Django 5: асинхронный бекенд и эффектный фронтенд с минимальными затратами времени

от автора

Приветствую, друзья!

Уже давно у меня возникала мысль подробно, как в случае с FastAPI и Aiogram 3, разобрать «суровый» Django 5. Однако, из-за большого дефицита свободного времени и масштабности Django, руки до этого не доходили. Сегодня, как вы уже поняли, момент настал.

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

Из-за слабого отклика на некоторые предыдущие темы, такие как SQLAlchemy 2, Playwright и Docker, я их забросил. Посмотрим, как пойдет дело с Django 5.

План на сегодня

Обозначим задачу. К концу этой статьи мы не просто напишем наш первый проект на Django 5, но и развернем его на реальном хостинге, тем самым преодолевая основной страх разработчиков Django.

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

Для деплоя я буду использовать сервис Amvera Cloud. Основная причина — простота деплоя. Нам достаточно будет:

  1. Зарегистрироваться в Amvera Cloud.

  2. Создать проект.

  3. Одним кликом активировать домен.

  4. Сгенерировать файл настроек прямо на их сайте.

  5. Через стандартные GIT-команды загрузить файлы Django-проекта на хостинг Amvera Cloud.

  6. Весь процесс деплоя займет не больше 5 минут, так что обязательно дочитайте статью до конца.

О самом проекте

Сегодня мы создадим простой сайт, который будет демонстрировать гороскоп на завтра для любого знака зодиака. Чтобы было интереснее, гороскоп будем асинхронно парсить в момент обращения к знаку зодиака (об этом подробнее далее).

Фронтенд, а именно два шаблона, мы попросим сгенерировать одну нейросеть, обзор которой я уже делал неоднократно в своем Хабре — websim.ai.

В процессе написания кода мы затронем следующие темы: маршрутизация, работа со статическими файлами, асинхронное использование Django 5, работа с базой данных SQLite через встроенное ORM и многое другое.

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

Дисклеймер

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

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

Немного теории

Django — это высокоуровневый веб-фреймворк на Python, предназначенный для быстрого и удобного создания веб-приложений. Он следует принципу «Don’t Repeat Yourself» (DRY), что позволяет уменьшить количество повторяющегося кода.

Django предоставляет множество инструментов и библиотек «из коробки», таких как админ-панель, система маршрутизации, ORM для работы с базой данных, аутентификация и многое другое (большую часть этих инструментов мы рассмотрим сегодня).

Мы будем работать с 5-й версией Django. Как и в предыдущих версиях, основное внимание уделяется улучшению производительности и удобству разработки. То, что нас будет интересовать сегодня — это продвинутая асинхронность, которой мы и воспользуемся.

Больше теоретической информации вы найдете в интернете, а мы приступим к написанию кода.

Начинаем писать код

Для начала создадим новый проект под наше будущее приложение. Я, как обычно, буду работать в PyCharm.

В проекте будут использованы некоторые «нестандартные» для Django библиотеки. Для удобства установим их через файл requirements.txt. Вот его пример:

beautifulsoup4==4.12.3 bs4==0.0.2 django==5.1 fake-useragent==1.5.1 httpx==0.27.2 gunicorn==20.1.0 whitenoise==6.7.0

Библиотеки gunicorn и whitenoise нам понадобятся только на этапе деплоя. Поэтому их можно добавить в файл requirements.txt уже на стадии подготовки проекта к развертыванию.

Django — основной фреймворк, на котором мы будем писать код, а библиотеки bs4, fake-useragent и httpx понадобятся для парсинга гороскопа.

Установим библиотеки:

pip install -r requirements.txt

Теперь приступим к созданию проекта Django (не путать с приложением). Для этого воспользуемся командой:

django-admin startproject project_name

Я назову проект zodiac:

django-admin startproject zodiac

В результате у нас появится папка с именем zodiac и одноименный конфигурационный пакет zodiac. Давайте сразу переместим файл requirements.txt в корневую директорию проекта (папка zodiac). Это облегчит процесс деплоя в будущем, так как все нужные файлы будут находиться в одном месте.

Теперь создадим наше первое и единственное приложение.

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

Для создания приложения:

  • Переходим в папку проекта

cd zodiac
  • Выполняем команду (имя приложения может быть любым)

python manage.py startapp zodiac_app

Теперь нам необходимо зарегистрировать созданное приложение. Для этого в конфигурационном пакете (zodiac в моем случае) необходимо найти файл settings.py.

Там находим список INSTALLED_APPS и добавляем в него имя приложения:

INSTALLED_APPS = [     …,     'zodiac_app', ]

Теперь нам необходимо подготовить маршруты для созданного приложения. Маршрутов у нас будет всего 2:

  1. Главная страница

  2. Страница с гороскопом (будет динамически подставляться путь)

Для этого в пакете созданного приложения (zodiac_app) создадим файл urls.py и заполним его следующим образом:

from django.urls import path from . import views   urlpatterns = [     path('', views.index, name='home'), ]

Тут нужно немного разобраться.

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

Опишем это представление в файле views.py:

from django.shortcuts import render   def index(request):     return render(request,                    template_name='index.html',                    context={'title': 'Космический гороскоп - все знаки зодиака'})

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

Параметр context может принимать словарь с данными. В него мы пока просто передадим название страницы (это нужно будет для тестов).

Создадим максимально простой HTML.

Для хранения html шаблонов (напомню, у нас их всего 2 будет) необходимо создать папку templates в корне приложения (у меня это zodiac_app) и во внутрь положим файл index.html.

<!doctype html> <html lang="en"> <head>     <meta charset="UTF-8">     <meta name="viewport"           content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">     <meta http-equiv="X-UA-Compatible" content="ie=edge">     <title>{{ title }}</title> </head> <body> <h1>{{ title }}</h1> </body> </html>

Стандартный HTML. В него, чтоб проверить что переменные контекста корректно передаются я передал переменную title (для этого используются двойные фигурные скобки).

Теперь, перед первым запуском нашего приложения, нам необходимо будет включить страницы приложения. Для этого в конфиг-пакете (у меня это zodiac) находим файл urls.py и добавляем там следующее.

from django.urls import path, include   urlpatterns = [     path('', include('zodiac_app.urls')) ]

Админку можно убрать, так как ее мы не будем использовать в данном проекте.

Благодаря такой записи мы включили маршруты из нашего приложения zodiac_app.

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

python manage.py runserver PORT

У меня свободен порт 5000, а значит команда запуска будет выглядеть так:

python manage.py runserver 5000

Перейдем на сервер

Посмотрим на исходный код страницы (CTRL + U)

Видим, что наш шаблон отработал корректно. Продолжим.

Теперь немного отойдем от самого Django и выполним небольшую подготовку, а именно, напишем парсер гороскопа.

Для написания создадим файл utils.py в пакете приложения (zodiac_app).

Логика парсера

Данные мы будем брать с сайта https://horo.mail.ru/prediction. Там, если переходить на страницу с гороскопом, то, по умолчанию, открывается страница следующей конструкции: https://horo.mail.ru/prediction/HOROSCOP_NAME_EN/today/. К этому мы и подстроим свой парсер.

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

Полный код парсера

import httpx from bs4 import BeautifulSoup from fake_useragent import UserAgent   async def fetch_horoscope(zodiac_en="cancer"):     # Создаем фейковый User-Agent     ua = UserAgent()     headers = {         'accept': '*/*',         'accept-language': 'ru,en;q=0.9',         'cache-control': 'no-cache',         'pragma': 'no-cache',         'priority': 'u=0, i',         'referer': 'https://horo.mail.ru/prediction/',         'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "YaBrowser";v="24.7", "Yowser";v="2.5"',         'sec-ch-ua-mobile': '?0',         'sec-ch-ua-platform': '"Windows"',         'sec-fetch-dest': 'document',         'sec-fetch-mode': 'navigate',         'sec-fetch-site': 'same-origin',         'sec-fetch-user': '?1',         'upgrade-insecure-requests': '1',         'user-agent': ua.random,  # Используем фейковый User-Agent     }      # Асинхронный HTTP-запрос     async with httpx.AsyncClient() as client:         response = await client.get(f'https://horo.mail.ru/prediction/{zodiac_en}/today/', headers=headers)      # Парсинг ответа с помощью BeautifulSoup     soup = BeautifulSoup(response.text, 'html.parser')     main_content = soup.find('main', itemprop='articleBody')      # Извлечение текста из найденного элемента, с разделением на строки     text_lines = main_content.get_text(separator="\n", strip=True).splitlines()      # Формирование новых <p> для каждой строки текста     paragraphs = ''.join([f'<p>{line}</p>' for line in text_lines])     return paragraphs 

Для того чтоб сильно на этом не заострять внимание оставил комментарии в коде.

На что стоит обратить внимание — это подставка фейкового User Agent в заголовки. Далее все просто:

  • подставили название на английском гороскопа

  • отправили запрос на получение данных

  • через bs4 вытянули из полученных данных описание гороскопа

  • очистили от лишних классов и вернули html

Проверим код на знаке «Весы»

print(asyncio.run(fetch_horoscope(zodiac_en="aries")))
 Получаем нужный результат. Отлично!

Получаем нужный результат. Отлично!

Теперь нам нужно подготовить красивые HTML шаблоны для нашего сайта. Воспользуемся нейросетью websim.ai

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

Страница гороскопа на русском языке. На ней размещена иконка гороскопа (фото), под ней — название на русском и дата рождения, соответствующая этому знаку. Также есть кнопка «Смотреть гороскоп». Сделай стильно и красиво, но без излишних усложнений.

Страница гороскопа на русском языке. На ней размещена иконка гороскопа (фото), под ней — название на русском и дата рождения, соответствующая этому знаку. Также есть кнопка «Смотреть гороскоп». Сделай стильно и красиво, но без излишних усложнений.
 теперь оформи все 12 знаков на одной странице

теперь оформи все 12 знаков на одной странице
 теперь добавь более красивые иконки под каждый гороскоп и выполни все в космическом стиле

теперь добавь более красивые иконки под каждый гороскоп и выполни все в космическом стиле

Фон получился динамическим, при наведении увеличивается кнопка. Лично я остался полностью доволен главной страницей. Теперь сохраним получившийся HTML.

Теперь, в один промт, попросим подготовить для нас страничку с гороскопом.

 оформи в этом же стиле страницу внутри гороскопа. иконка, описание и кнопка "На главную". Обязательно сохрани общий стиль

оформи в этом же стиле страницу внутри гороскопа. иконка, описание и кнопка «На главную». Обязательно сохрани общий стиль

И этой страницей я полностью доволен и теперь остается только ее сохранить.

Работа с базой данных

К шаблонам мы вернемся чуть позже, а сейчас подготовим простую базу данных под наш проект. В этой базе данных мы создадим одну таблицу и будем хранить в ней следующие поля: русское название зодиака, английское название зодиака, день когда начинается знак, день когда заканчивается знак и svg (нейронка сгенерировала все иконки чистым svg, так что в этом поле будем хранить HTML).

Для работы с базой данных в Django используется объектно-ориентированный подход. Если простыми словами, то создается класс таблицы и далее работа идет с каждым полем как с отдельным объектом класса.

Для работы нам необходимо создать модель таблицы. Файл для моделей уже создан в нашем приложении (zodiac_app) — models.py. Опишем модель.

from django.db import models   class ZodiacSign(models.Model):     zodiac_ru = models.CharField(max_length=50, unique=True)  # Название знака зодиака на русском     zodiac_en = models.CharField(max_length=50, unique=True)  # Название знака зодиака на английском     start_day = models.CharField(max_length=20, unique=True)  # Дата начала периода     end_day = models.CharField(max_length=20, unique=True)  # Дата окончания периода     svg = models.TextField()  # SVG-код      def __str__(self):         return self.zodiac_en

Описание очень похоже на работу с SQLAchemy. В комментариях дал описание на русском каждого поля.

Теперь нам необходимо создать миграцию на основе нашей модели.

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

Выполним команду:

python manage.py makemigrations

Эта команда создаст файлы миграций в директории migrations вашего приложения.

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

Выполните команду:

python manage.py migrate

Эта команда применит все созданные миграции и обновит структуру базы данных.

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

Если у вас была описана всего одна модель, то будет создана одна таблица. Напоминаю, что по умолчанию Django ориентирован на SQLite.

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

Название на русском, день начала, день завершения и название на английском (со ссылки)

Название на русском, день начала, день завершения и название на английском (со ссылки)

На выходе у меня получился такой массив данных:

zodiac_data = [     {         'zodiac_ru': 'овен',         'zodiac_en': 'aries',         'start_day': '20 марта',         'end_day': '19 апреля',         'svg': '''<svg class="horoscope-icon" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">             <circle cx="50" cy="50" r="45" fill="url(#ariesGradient)"/>             <path d="M50 20 C60 40 70 40 70 60 M50 20 C40 40 30 40 30 60" stroke="#FFD700" stroke-width="4"                   fill="none"/>             <defs>                 <radialGradient id="ariesGradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">                     <stop offset="0%" style="stop-color:#FF6B6B;stop-opacity:1"/>                     <stop offset="100%" style="stop-color:#FF4500;stop-opacity:1"/>                 </radialGradient>             </defs>         </svg>'''     }, …]

Кому будет нужно — с полным кодом всего проекта можно ознакомиться в моем телеграмм-канале «Легкий путь в Python».

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

from django.db import models   zodiac_data = [...]   class ZodiacSign(models.Model):     zodiac_ru = models.CharField(max_length=50, unique=True)  # Название знака зодиака на русском     zodiac_en = models.CharField(max_length=50, unique=True)  # Название знака зодиака на английском     start_day = models.CharField(max_length=20, unique=True)  # Дата начала периода     end_day = models.CharField(max_length=20, unique=True)  # Дата окончания периода     svg = models.TextField()  # SVG-код      def __str__(self):         return self.zodiac_en   def bulk_create_zodiac_signs():     # Создаем список объектов модели     zodiac_signs = [         ZodiacSign(             zodiac_ru=data['zodiac_ru'],             zodiac_en=data['zodiac_en'],             start_day=data['start_day'],             end_day=data['end_day'],             svg=data['svg']         )         for data in zodiac_data     ]      # Используйте bulk_create для добавления всех записей     ZodiacSign.objects.bulk_create(zodiac_signs)

Данные для добавления в таблицу я подготовил там-же.

Теперь войдем в оболочку Django и с нее выполним функцию bulk_create_zodiac_signs. Для этого:

  • Вводим команду:

    python manage.py shell

  • Импортируем функцию bulk_create_zodiac_signs

    from zodiac_app.models import bulk_create_zodiac_signs

  • Выполняем функцию

    bulk_create_zodiac_signs()

  • Выходим с оболочки:

    exit()

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

Все данные на месте

Все данные на месте

Все данные на месте, парсер написан и это значит что мы можем приступать к оформлению HTML-шаблонов.

Оформление HTML-шаблонов

Конечно, мы все сделаем по-красоте. Для этого, для начала, в папке приложения (zodiac_app) подготовим папку templates и внутри нее следующие папки: img (для фото), js (для JavaScript скриптов) и style (для CSS-стилей).

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

Для начала, я создал файл стилей main.css и в него перенес все стили с блока стилей, который подготовила нейросеть. Так как стилей много — просто приведу в пример скриншот (где искать исходники проекта вы знаете).

Далее, на главной странице, как вы могли заметить, представлены знаки зодиака плиткой, а это хорошая предпосылка для нас, так как мы сможем на основании каждой такой карточки оформить внутренний цикл FOR и просто переберем все значения с базы данных в HTML-шаблоне.

Сама карточка от нейронки имеет такой вид:

<div class="horoscope-card">         <svg class="horoscope-icon" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">             <circle cx="50" cy="50" r="45" fill="url(#geminiGradient)"/>             <path d="M30 30 L70 70 M30 70 L70 30" stroke="#FFD700" stroke-width="4" fill="none"/>             <defs>                 <radialGradient id="geminiGradient" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">                     <stop offset="0%" style="stop-color:#FFFF00;stop-opacity:1" />                     <stop offset="100%" style="stop-color:#FFA500;stop-opacity:1" />                 </radialGradient>             </defs>         </svg>         <h2>Близнецы</h2>         <p>21 мая - 20 июня</p>         <a href="ru/sign/gemini" class="btn">Смотреть гороскоп</a>     </div>

И в таком формате 12 раз. Адаптируем код под наш проект:

{% load static %} <html> <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>{{ title }}</title>     <!-- Устанавливает иконку сайта, загружаемую из статических файлов -->     <link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}">     <!-- импорт стилей из static/style/main.css -->     <link type="text/css" href="{% static 'style/main.css' %}" rel="stylesheet"/> </head> <body> <div class="horoscope-grid">     {% for info in main_data %}     <div class="horoscope-card">         {{ info.svg|safe }}         <h2>{{ info.zodiac_ru|title }}</h2>         <p>{{ info.start_day }} - {{ info.end_day }}</p>         <a href="/{{ info.zodiac_en }}" class="btn">Смотреть гороскоп</a>     </div>     {% endfor %} </div> </body> </html>

Это весь код главной страницы.

Тут стоит обратить внимание на начало файла. Я использовал {% load static %}. Благодаря этому мы указали Django что в этот файл необходимо подключить статические файлы (например, CSS, изображения).

Кроме того, я заранее подготовил иконку (фавикон) и закинул ее в папку img. Затем я импортировал файл стилей.

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

<a href="/{{ info.zodiac_en }}" class="btn">Смотреть гороскоп</a>

Благодаря этой строке, для страницы с гороскопом будет сформирована ссылка такого вида: http://127.0.0.1:5000/aries. Это мы используем в дальнейшем, когда опишем страницу каждого гороскопа.

Теперь изменим функцию-представления для главной страницы.

Для начала импортируем модель нашей таблицы в файл views.py

from .models import ZodiacSign

Теперь в представление index добавим обращение к базе данных с целью получения всех записей. С DjangoORM это делать очень просто.

def index(request):     main_data = ZodiacSign.objects.all()     return render(request,                   template_name='index.html',                   context={'title': 'Космический гороскоп - все знаки зодиака', 'main_data': main_data})

Всего одной строкой: main_data = ZodiacSign.objects.all() нам удалось извлечь все записи с нашей созданной таблицы. Каждая из этих записей теперь представлена списком питоновских словарей, что позволит нам обращаться к каждому значению через точку в шаблоне.

Перезапустим сервер и посмотрим что получилось с главной.

Получилось то что я планировал. Все записи выстроились корректно, стили подгрузились.

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

Для начала поработаем с маршрутом (файл zodiac_app/urls.py).

urlpatterns = [     path('', views.index, name='home'),     path('<slug:zodiac_name>/', views.zodiac, name='zodiac'), ]

Тут мы добавили новый маршрут для представления zodiac.

  • <slug:zodiac_name> — это динамическая часть URL, которая может принимать различные значения. Django распознает этот параметр и передает его в соответствующее представление в качестве аргумента.

  • slug — это конвертер, который ограничивает формат значения переменной zodiac_name. Он ожидает строку, состоящую из букв, цифр, дефисов и подчеркиваний (например, aries, leo, virgo, scorpio-2023). Slug используется для создания «чистых» URL, удобных для чтения и SEO.

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

Для начала мы импортируем метод sync_to_async из asgiref.sync (ветка у вас уже установлена). Данный метод позволит превратить синхронный код в асинхронный, что уже следует из названия.

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

from asgiref.sync import sync_to_async   @sync_to_async def get_zodiac_data(zodiac_name):     return ZodiacSign.objects.get(zodiac_en=zodiac_name)

На этом примере вы, в очередной раз, можете убедиться насколько удобное и функциональное ORM Django.

И опишем само представление.

async def zodiac(request, zodiac_name):     zodiac_data = await get_zodiac_data(zodiac_name)     html_description = await fetch_horoscope(zodiac_name)     return render(request, 'zodiac_page.html',                   {'title': zodiac_name, 'zodiac_data': zodiac_data, 'html_description': html_description})

Теперь у нас полностью асинхронное представление. Работает код по следующей логике:

  1. Получаем данные по знаку зодиака с базы данных

  2. Получаем описание гороскопа на завтра с сайта с гороскопом (не забудьте предварительно выполнить импорт парсера из утилит from .utils import fetch_horoscope

  3. Далее выполняем знакомый рендер (html шаблон у нас уже есть и его нужно только адаптировать).

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

{% load static %} <html> <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>Ваш космический гороскоп для {{ zodiac_data.zodiac_ru|title }}</title>     <link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}">     <link type="text/css" href="{% static 'style/horoscop.css' %}" rel="stylesheet"/> </head> <body> <div class="horoscope-container">     {{ zodiac_data.svg|safe }}     <h1>{{ zodiac_data.zodiac_ru|title }}</h1>     {{ html_description|safe}}     <a href="/" class="btn">На главную</a> </div>  <script src="{% static 'js/script.js' %}"></script> </body> </html>

Из нового только импорт js-скрипта и использование safe для корректного отображения HTML.

И, прежде чем запустим, давайте асинхронно перепишем и представление index, чтоб наш проект был максимально прогрессивным.

@sync_to_async def get_all_zodiac_signs():     return list(ZodiacSign.objects.all())   async def index(request):     main_data = await get_all_zodiac_signs()     return render(request, 'index.html', {'main_data': main_data})

Теперь перезапустим сервер и посмотрим на результат.

Сверим результат с тем что на сайте-доноре.

Видим что результат одинаков, а это значит что проект готов!

Подготовка к деплою

Сегодня я продемонстрирую один из самых простых способов деплоя Django приложения, используя отечественный аналог Heroku — Amvera Cloud. Перед этим подготовим наш проект.

Сначала настроим файл settings.py, где мы ранее регистрировали наше приложение.

Переведём проект из режима разработки:

DEBUG = False

Настроим разрешения доступа к сайту. Так как проект учебный, разрешим доступ со всех адресов:

ALLOWED_HOSTS = ['*']

Чтобы упростить работу со статическими файлами, добавим в список middleware следующую строку:

MIDDLEWARE = [     …,     'whitenoise.middleware.WhiteNoiseMiddleware', ]

WhiteNoise позволяет эффективно управлять статическими файлами, что особенно полезно, когда нет возможности использовать полноценный веб-сервер. Эта настройка избавляет от необходимости дополнительной конфигурации Nginx или Apache для обработки статики.

Затем укажем путь для хранения статических файлов в продакшене:

STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR / 'static'

STATIC_URL = ‘/static/’ определяет базовый URL для доступа к статическим файлам, а STATIC_ROOT = BASE_DIR / ‘static’ — директорию на сервере, куда будут собираться все статические файлы при выполнении команды collectstatic.

Деплой приложения

Теперь мы полностью готовы к деплою.

  • Зарегистрируйтесь на сайте Amvera Cloud, если еще не зарегистрированы (за регистрацию предусмотрен бонус в размере 111 рублей на основной счет).

  • Перейдите в раздел проектов.

  • Нажмите на «Создать проект», задайте ему название и выберите тариф.

  • Следующий экран пропустите — к нему мы вернемся позже.

  • На открывшемся экране появится возможность сгенерировать файл настроек. Заполните данные, как указано на скриншоте ниже (при необходимости их можно будет изменить позже).

  • Нажмите на «Завершить».

  • Войдите в проект, откройте вкладку «Настройки» и активируйте бесплатный домен (если у вас есть свой домен, его можно привязать на этом же экране).

  • Перейдите на вкладку «Репозиторий». Здесь вас будет интересовать ссылка на репозиторий. Скопируйте её.

На этом все настройки на стороне Amvera Cloud завершены. Теперь осталось с помощью GIT доставить файлы нашего Django проекта в проект на Amvera, после чего проект автоматически развернется и запустится (магия).

Перейдите в корень проекта (папка zodiac) и инициализируйте пустой Git-репозиторий:

git init

Привяжите проект к Amvera. В моем случае команда выглядит так:

git remote add amvera https://git.amvera.ru/yakvenalex/djangozodiac

Заберите файл настроек:

git pull amvera master

В моем случае файл имеет такой вид:

--- meta:   environment: python   toolchain:     name: pip     version: 3.12 build:   requirementsPath: requirements.txt run:   persistenceMount: /data   containerPort: 5000   command: gunicorn zodiac.wsgi:application  --bind 0.0.0.0:5000 

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

Для запуска важно наличие всех этих файлов именно в такой иерархии. Иначе запуск не произойдет.

Теперь доставим файлы:

git add . git commit -m "init commit" git pull amvera master

Если все прошло корректно, то после обновления, на вкладке «Репозиторий» вы должны увидеть файлы своего проекта.

После автоматически начнется сборка проекта и, если все было сделано правильно, то минут через 5 вы увидите следующее.

Теперь остается только перейти по доменному имени проекта и проверить все ли работает. В моем случае это: https://djangozodiac-yakvenalex.amvera.io/

Главный экран

Главный экран
Страница с гороскопом

Страница с гороскопом

Заключение

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

Этой публикацией я хотел показать, что Django — это не какой-то убер-сложный инструмент, доступный лишь избранным. Главное — преодолеть первоначальные барьер входа, и вы сможете понять, оценить и полюбить философию этого фреймворка.

Полный исходный код проекта, а также дополнительный эксклюзивный контент, который я не планирую публиковать на Хабре, вы сможете найти в моем телеграм-канале «Легкий путь в Python».

Напоминаю, что если вам интересно получить более подробное и глубокое погружение в фреймворк Django в моем авторстве, участвуйте в голосовании под этой статьей, ставьте лайки и оставляйте комментарии. Это займет у вас всего пару секунд, а мне будет очень приятно.

Спасибо за внимание и до скорого!

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

Хотите более глубокий и подробный разбор Django?

93.33% Да14
0% Возможно0
6.67% Нет1

Проголосовали 15 пользователей. Воздержавшихся нет.

ссылка на оригинал статьи https://habr.com/ru/articles/840612/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *