⚠️ Дисклеймер
Эта статья подготовлена по мотивам книги «Django 5 By Example» (автор: Antonio Melé, издательство: Packt Publishing, 5-е издание, ISBN: 9781805122340).
Статья не является официальным переводом книги и не копирует оригинальный текст. Все материалы в публикации — это мои личные переработки, пояснения, примеры и улучшения, сделанные с целью образовательной поддержки русскоязычного сообщества разработчиков.
Примеры кода, использованные в статье, основаны на открытом репозитории книги и распространяются по лицензии MIT, допускающей свободное использование с указанием авторства.
Все права на оригинальное содержание принадлежат автору книги и издательству Packt Publishing.
📖 Оригинальная книга доступна на официальном сайте:
https://www.packtpub.com/en-us/product/django-5-by-example-9781805122340
О чём эта статья и чем она будет полезна?
Эта статья явлется продолжением статьи Создание Блога на Django 5, PostgreSQL 16 с полнотекстовым поиском.
В этот раз мы пройдем путь от настройки представлений (views), маршрутов (urls) и шаблонов (templates) до подключения тёмной темы в стиле Киберпанк и адаптивного дизайна в духе Яндекс.Дзен.
Статья будет полезна:
- новичкам, которые хотят понять, как устроен MVC-подход в Django на практике;
- джунам и мидлам, желающим закрепить навыки создания кастомных представлений и шаблонов;
- разработчикам, стремящимся быстро задать профессиональный визуальный стиль без глубоких знаний CSS.
В процессе вы:
- создадите список и детальное представление постов,
- научитесь правильно подключать URL-маршруты через пространства имён,
- организуете шаблоны по best practices (base.html + наследование),
- создадите команду manage.py для управления публикациями,
- и добавите адаптивную тёмную тему — сначала яркую (киберпанк), затем минималистичную (в стиле Дзен).
Введение
Зачем нужны представления в Django?
Теперь, когда вы понимаете, как использовать ORM, вы готовы приступить к созданию представлений (views) для блога.
Представление в Django — это обычная Python‑функция, которая принимает веб‑запрос и возвращает веб‑ответ. Вся логика, необходимая для формирования нужного ответа, реализуется внутри представления.
Как связаны представления, маршруты и шаблоны?
Сначала вы создаете представления приложения, затем определяете шаблоны URL для каждого представления, и в конце — создаете HTML‑шаблоны для отображения данных, которые формируются представлениями. Каждое представление будет рендерить шаблон, передавать ему переменные и возвращать HTTP‑ответ с отрендеренным результатом.
Шаг 1. Создание представлений
Представление для списка постов (post_list)
Давайте начнём с создания представления, которое будет отображать список постов. Отредактируйте файл views.py в приложении blog, чтобы он выглядел следующим образом:
Это — наше первое представление в Django.
Функция post_list принимает единственный аргумент — объект запроса request. Этот параметр обязателен для всех представлений.
В этом представлении мы получаем все посты со статусом PUBLISHED с помощью менеджера published, который мы ранее создали.
Затем мы используем вспомогательную функцию render(), предоставленную Django, чтобы отрендерить список постов с использованием заданного шаблона.
Функция render() принимает три аргумента:
- Объект request,
- Путь к HTML-шаблону,
- Словарь с переменными контекста, которые будут переданы в шаблон.
Функция возвращает объект HttpResponse с отрендеренным текстом (обычно — HTML-кодом).
Функция render() автоматически учитывает контекст запроса, поэтому все переменные, определённые контекстными процессорами шаблонов, будут доступны в шаблоне.
Контекстные процессоры — это просто функции, которые добавляют переменные в контекст.
Представление для одного поста (post_detail)
Теперь давайте создадим второе представление — для детального отображения одного поста. Добавьте в views.py следующую функцию:
Это представление post_detail. Оно принимает аргумент id — идентификатор поста.
Внутри функции мы пытаемся получить объект Post с указанным id через метод get() менеджера published.
Если пост не найден и выбрасывается исключение DoesNotExist, мы вызываем исключение Http404, чтобы вернуть HTTP-ответ с ошибкой 404.
Мы снова используем функцию render() для отображения найденного поста с помощью соответствующего шаблона.
Как работает get_object_or_404?
Django предоставляет удобную функцию - get_object_or_404, которая вызывает метод get() на переданном менеджере модели и автоматически выбрасывает исключение Http404, если объект не найден, вместо стандартного DoesNotExist.
Отредактируйте файл views.py, чтобы импортировать get_object_or_404 и изменить представление post_detail следующим образом.
В обновлённом представлении post_detail мы используем функцию get_object_or_404() для получения нужного поста.
Эта функция возвращает объект, соответствующий переданным параметрам, либо вызывает исключение Http404, если такой объект не найден.
В файле blog/views.py должен быть следующий код:
Шаг 2. Настройка маршрутов (URL)
URL-шаблоны (URL patterns) позволяют связать адреса (URL) с определёнными представлениями.
Каждый URL-шаблон состоит из трёх компонентов:
- строкового паттерна (маршрута),
- вызываемого представления (view),
- (опционально) имени, по которому можно ссылаться на этот маршрут во всём проекте.
Django проходит по каждому шаблону URL сверху вниз и останавливается на первом совпадении с входящим URL.
После этого он импортирует соответствующее представление и вызывает его, передавая в него объект HttpRequest и аргументы маршрута (позиционные или именованные).
Создание urls.py в приложении blog
Создайте файл urls.py в директории приложения blog и добавьте в него следующий код:
Что здесь происходит:
- app_name = 'blog' — задаёт пространство имён (namespace) для приложения. Это критически важно, если в проекте несколько приложений с однотипными маршрутами. С помощью app_name можно ссылаться на маршруты по схеме blog:post_list и blog:post_detail.
- Первый маршрут — это корень (''), он ссылается на представление post_list.
- Второй маршрут — это '<int:id>/'. Он принимает один аргумент id и передаёт его в представление post_detail.
Django использует конвертеры маршрута (path converters) в фигурных скобках, чтобы преобразовывать значения из строки в тип данных:
- <int:id> — целое число;
- <slug:post> — "slug" строка (буквы, цифры, дефисы, подчёркивания);
- <str:name> — строка;
- <uuid:uuid> — UUID;
- <path:some_path> — путь с /.
Полный список доступен в документации:
📎 https://docs.djangoproject.com/en/5.0/topics/http/urls/#path-converters
Если базовых конвертеров path() недостаточно — можно использовать re_path() и регулярные выражения. Подробнее:
📎 https://docs.djangoproject.com/en/5.0/ref/urls/#django.urls.re_path
📎 https://docs.python.org/3/howto/regex.html
Совет от сеньора: Всегда создавай отдельный urls.py в каждом приложении — это делает его переиспользуемым и изолированным. Особенно важно в больших проектах и при публикации приложения как Django-пакета.
Подключение маршрутов blog в корневом mysite/urls.py
Теперь необходимо включить маршруты blog/urls.py из приложения blog в корневой маршрут mysite/urls.py проекта.
Откройте mysite/urls.py и измените его следующим образом:
Разбор:
- include('blog.urls', namespace='blog') — встраивает маршруты из blog/urls.py, и все они теперь будут доступны по префиксу /blog/.
- namespace='blog' — связывает пространство имён с этим блоком маршрутов. Это важно для надёжной ссылки на маршруты в шаблонах и функциях reverse().
Использование пространств имён (app_name, namespace)
Теперь можно использовать маршруты по их имени, через пространство имён:
Или в Python-коде (например, редирект):
Если кратко, настройка маршрутов — это архитектурная основа вашего проекта. Используя имена и пространства имён (app_name, name), вы обеспечиваете стабильную и удобную навигацию по проекту.
Шаг 3. Создание шаблонов
Мы уже создали представления и URL-шаблоны для блога.
URL-шаблоны связывают URL с представлениями, а представления определяют, какие данные возвращать пользователю.
Шаблоны (templates) — отвечают за то, как эти данные отображаются. Обычно они пишутся на HTML с использованием шаблонного языка Django.
📎 Подробнее о шаблонном языке Django:
https://docs.djangoproject.com/en/5.0/ref/templates/language/
Структура шаблонов в приложении blog
Добавим в наше приложение blog следующие каталоги и файлы:
Это будет структура шаблонов для блога.
- base.html — базовый шаблон сайта: включает общую HTML-структуру, общие стили, и делит страницу на основную часть и сайдбар.
- post/list.html — шаблон для отображения списка постов.
- post/detail.html — шаблон для отображения отдельного поста.
Оба шаблона list.html и detail.html наследуются от base.html, чтобы повторно использовать общую структуру сайта.
Как работает шаблонный язык Django
Django предоставляет мощный шаблонный язык, с помощью которого можно управлять отображением данных. Он состоит из трёх основных элементов:
- Шаблонные теги (template tags) — управляют логикой рендеринга и имеют вид: {% tag %}
Пример:
{% for post in posts %}, {% if user.is_authenticated %}
- Шаблонные переменные (template variables) — отображают значения и имеют вид: {{ variable }}
Пример:
{{ post.title }}, {{ user.username }}
- Шаблонные фильтры (template filters) — позволяют модифицировать значения перед отображением.
Вид: {{ variable|filter }}
Пример:
{{ post.body|truncatewords:30 }}, {{ publish|date:"d.m.Y" }}
Полный список встроенных тегов и фильтров:
📎 https://docs.djangoproject.com/en/5.0/ref/templates/builtins/
Совет от сеньора:
Пишите шаблоны так, чтобы повторяемая структура (хедер, футер, меню) находилась в base.html, а всё специфичное для страниц подключалось блоками ({% block content %} и т.д.) — это делает шаблоны поддерживаемыми и переиспользуемыми.
Базовый шаблон base.html: зачем он нужен?
Откройте файл base.html и добавьте в него следующий код:
Подробное объяснение на уровне senior
{% load static %}
Эта строка сообщает Django, что нужно загрузить теги шаблонов для работы со статикой. Они предоставляются встроенным приложением django.contrib.staticfiles, которое обязательно должно быть добавлено в список INSTALLED_APPS.
После этого можно использовать тег {% static %} для подключения CSS, JS, изображений и других файлов.
Пример:
Здесь подключается CSS-файл, находящийся по пути:
Использование {% block %}
Шаблон использует два блока:
Блоки позволяют шаблонам-наследникам вставлять свой контент в нужные места, переопределяя содержимое этих блоков. Это базовый механизм наследования шаблонов в Django.
Например, шаблон list.html будет выглядеть так:
Советы по best practices
- Храните всю повторяющуюся разметку (head, footer, menu, sidebar) в base.html.
- Используйте блочные теги {% block %} для участков, которые будут кастомизироваться в дочерних шаблонах.
- Всегда подключайте статику через {% static %} — это гарантирует, что пути будут корректными даже при использовании CDN, collectstatic, или в продакшн-окружении.
- Проверяйте, что STATICFILES_DIRS и STATIC_URL корректно настроены в settings.py.
Шаблон base.html — каркас всего блога. Он формирует основу визуального оформления и позволяет дочерним шаблонам гибко вставлять свои данные без дублирования структуры.
Шаблон списка постов post/list.html
Откройте файл post/list.html и вставьте в него следующий код:
Подробный разбор шаблона на уровне senior
{% extends "blog/base.html" %}
Этот тег сообщает Django, что данный шаблон наследуется от базового шаблона base.html, расположенного по пути blog/base.html.
Он автоматически подтянет структуру base.html, а в блоки title и content будет вставлено содержимое, определённое в этом дочернем шаблоне.
{% block title %} и {% block content %}
Мы переопределяем два блока из base.html:
- В блок title вставляется заголовок страницы "Блог ALEXPROIT".
- В блок content — весь основной контент: список постов.
{% for post in posts %}
Перебираем все посты, переданные из представления post_list, и для каждого выводим:
Заголовок, обёрнутый в ссылку на детальную страницу поста:
Тег {% url %} для динамической генерации URL
<a href="{% url 'blog:post_detail' post.id %}">{{ post.title }}</a>
- Здесь используется тег {% url %} для динамической генерации URL по имени маршрута.
'blog:post_detail' — это полное имя маршрута, с пространством имён blog (указан в app_name), и именем post_detail.
В аргументах передаётся post.id, необходимый для построения URL.
⚠️ Важно: Никогда не прописывайте URL жёстко (типа /blog/42/). Всегда используйте {% url %} — это делает код надёжным и нечувствительным к изменению маршрутов.
Фильтры шаблонов: truncatewords и linebreaks
{{ post.body|truncatewords:30|linebreaks }}
- truncatewords:30 — сокращает текст до 30 слов.
- linebreaks — преобразует переносы строк (\n) в HTML-теги <br> и <p>.
Можно комбинировать любое количество фильтров — каждый применяется к результату предыдущего.
Best practices:
- Делайте шаблоны максимально декларативными, используя фильтры и теги Django — это упрощает поддержку.
- Используйте truncatewords, чтобы не перегружать страницу длинными текстами.
- Следите, чтобы шаблоны были чистыми: без бизнес-логики и условий, которые лучше реализовать в представлении.
- Используйте {% empty %} внутри {% for %} для обработки случая, когда список пуст.
Почему стоит использовать {% empty %}?
{% empty %} внутри {% for %} для нашего блога
В файл post/list.html добавим {% empty %} внутри {% for %} для нашего блога.
Файл post/list.html целиком будет иметь вид:
Почему стоит добавить {% empty %}
Польза:
- Пользовательский опыт: посетитель не будет видеть пустую страницу.
- Явное поведение: вы чётко контролируете, что покажется, если posts пуст.
- Удобство отладки: если данные не пришли, вы это сразу увидите в браузере, а не будете думать "почему всё пусто".
Вывод
Блок {% empty %} желательно использовать всегда, когда работаешь с циклом for, особенно в представлениях, отображающих контент из базы данных. Это улучшает UX и делает шаблон более надёжным.
Шаг 4. Отладка и запуск блога
Чтобы проверить работу блога, выполните несколько завершающих шагов:
Как проставить статус "Опубликовано"
Выполните команду для запуска тестового веб сервера Django%
python manage.py runserver
Зайдите в админку сайта по ссылке:
http://127.0.0.1:8000/admin/
и проставьте у постов, которые должны быть опубликованы, статус "Опубликовано".
Затем создайте несколько новых постов — также со статусом "Опубликовано". Это необходимо, чтобы они отображались в публичной части сайта, так как представления фильтруют посты по этому статусу:
Post.published.all()
Как проверить отображение постов в браузере?
Откройте в браузере адрес:
http://127.0.0.1:8000/blog/
Результат:
Если всё сделано правильно, вы увидите страницу, на которой отображаются опубликованные посты.
Каждый заголовок — это кликабельная ссылка, ведущая на страницу поста.
Шаг 5. Управление публикацией через manage.py
Как создать кастомную команду unpublish_all_posts
Для проведения экспериментов создадим manage команду, которая автоматически будет снимать с публикации все посты блога.
Для этого создадим файл: blog/management/commands/unpublish_all_posts.py
Добавьте содержимое файла unpublish_all_posts.py:
⚠️ Важно: рядом должен быть пустой __init__.py файл в каждой папке (management/, commands/), чтобы Django их распознал как модули.
Проверка количества опубликованных и неопубликованных постов
Запустите команду:
python manage.py unpublish_all_posts
Результат:
Выполните команду:
python manage.py shell_plus --print-sql
Проверим, сколько опубликованных постов сейчас в базе.
Выполните запрос:
>>> from blog.models import Post
>>> Post.published.count()
Результат:
Опубликованных постов в базе нет - 0 шт.
Проверим сколько в базе неопубликованных постов:
Post.objects.filter(status=Post.Status.DRAFT).count()
Реузультат:
Запустим тестовый сервер и проверим как будет выглядеть список постов.
python manage.py runserver
Перейдем по ссылке:
http://127.0.0.1:8000/blog/
Результат:
Сделаем так чтобы наш sidebar блок был сверху, так как когда постов много его не видно.
Изменим код файла base.html:
Теперь наш блок sidebar всегда будет сверху - на виду.
Шаблон отдельного поста post/detail.html
Создадим шаблон для отображения детальной страницы поста.
Для этого откройте файл post/detail.html и вставьте в него следующий код:
Подробный разбор шаблона на уровне senior
{% extends "blog/base.html" %}
Этот шаблон наследуется от базового — base.html, который задаёт общую структуру страницы (HTML-обёртка, стили, сайдбар и т.п.).
Наследование позволяет избежать дублирования кода и повысить переиспользуемость.
Блоки title и content
{% block title %} — устанавливает HTML‑заголовок страницы (<title> в <head>). Он выводится как название вкладки в браузере.
{% block title %}{{ post.title }}{% endblock %}
{% block content %} — основной контент страницы:
<h1>{{ post.title }}</h1>
<p class="date">дата публикации:{{ post.publish }}, автор: {{ post.author }}</p>
{{ post.body|linebreaks }}
Здесь:
- {{ post.title }} — заголовок поста.
- {{ post.publish }} — дата публикации (можно дополнительно отформатировать фильтром |date:"d.m.Y").
- {{ post.author }} — имя пользователя, связанного с постом.
- {{ post.body|linebreaks }} — содержимое поста с автоматическим преобразованием \n в <br> и <p>.
Перейдем в админку блога и проставим статус "Опубликовано" на нескольких постах, чтобы попрактиковаться и поверить работу нашего блога.
Откроем список постов по ссылке:
http://127.0.0.1:8000/blog/
Результат:
Сверху видим наш сайдбар, а ниже список опубликованных постов. Кликнем по заголовку любого поста из списка и проверим работу шаблона post/detail.html.
Результат:
На скриншоте видим сверху наш сайдбар, ниже заголовок и тело поста.
Вывод - наш блог работает правильно.
Шаг 6. Улучшение UI: стиль Киберпанк
Добавление Bootstrap 5.3 и тёмной темы
Давайте добавим стили, чтобы наш блог выглядел в стиле киберпанк и был с темной темой и адаптивен для мобильных устройств.
Не будем сильно заморачиваться со стилями - воспользуемся bootsrap 5.3
Сделаем всю красоту с помощью ChatGPT.
Изучите и скопируйте промт, вставьте в чат и получите результат.
Откроем новый чат и опишем что мы хотим сделать:
Я сделал блог на Django 5, python 3.12. Блог показывает список постов и детали каждого поста. Сейчас нет стилей. Блог выглядит некраисиво.
Помоги сделать адаптивную верстку bootsrap 5.3, темную тему в стиле киберпанк.
Сейчас я загружу содержимое шаблонов. Твоя задача добавить стили по заданиювыше.
blog/base.html
{% load static %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
<link href="{% static "css/blog.css" %}" rel="stylesheet">
</head>
<body>
<div id="sidebar">
<h2>Блог ALEXPROIT</h2>
<p>Всем привет! Это мой блог на Django 5.</p>
</div>
<div id="content">
{% block content %}
{% endblock %}
</div>
</body>
</html>
blog/post/list.html
{% extends "blog/base.html" %}
{% block title %}Блог ALEXPROIT{% endblock %}
{% block content %}
<h1>Блог ALEXPROIT</h1>
{% for post in posts %}
<h2>
<a href="{% url 'blog:post_detail' post.id %}">
{{ post.title }}
</a>
</h2>
<p class="date">
дата публикации: {{ post.publish }}, автор: {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks }}
{% empty %}
<p>Нет доступных постов. Загляните позже!</p>
{% endfor %}
{% endblock %}
{% extends "blog/base.html" %}
{% block title %}Блог ALEXPROIT{% endblock %}
{% block content %}
<h1>Блог ALEXPROIT</h1>
{% for post in posts %}
<h2>
<a href="{% url 'blog:post_detail' post.id %}">
{{ post.title }}
</a>
</h2>
<p class="date">
дата публикации: {{ post.publish }}, автор: {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks }}
{% empty %}
<p>Нет доступных постов. Загляните позже!</p>
{% endfor %}
{% endblock %}
blog/post/detail.html
{% extends "blog/base.html" %}
{% block title %}{{ post.title }}{% endblock %}
{% block content %}
<h1>{{ post.title }}</h1>
<p class="date">
дата публикации: {{ post.publish }}, автор: {{ post.author }}
</p>
{{ post.body|linebreaks }}
{% endblock %}
Выполни задание на уровне сеньор
Результат:
blog/base.html
list.html
detail.html
blog.css
Теперь перенесите обновленный код в наши файлы стилей и шаблоны и запустите тестовый сервер по адресу:
http://127.0.0.1:8000/blog/
Результат:
Согласитесь это хороший результат за пару минут.
Теперь уменьшим разрещение экрана и проверим адапртивность нашего блога при отображении информации на маленьких экранах.
Результат:
Как видно из скриншотов - полный адаптив.
Шаг 7. Улучшение UX: стиль Яндекс.Дзен
Почему мы перешли от Киберпанка к Дзену?
Этот стиль слишком яркий и будет мешать читать наши посты. Поэтому давайте выполним следующий короткий промт в ChatGPT:
Теперь я хочу чтобы ты сделал все тоже самое только в стиле Дзен - блог платформы от Яндекса в темной теме
Результат:
Обновление стилей и шаблонов
base.html
list.html
detail.html
blog.css
Проверка адаптивности и читаемости
Обновите код в ваших файлах шаблонов и стилей и запустите тестовый веб сервер Django.
python manage.py runserver
Перейдите по ссылке:
http://127.0.0.1:8000/blog/
Результат:
Страница со списоком постов
Шапка сайта
Подвал
Страница поста
Как видно из скриншотов мы получили адаптивный удобный и споскойный дизайн в стиле Дзен, который позволит сконцентрировать внимание на посте и его содержании а не элементах интерфейса.
Этот дизайн мы будем использовать в дальнейшем при создании нашего приложения блог.
Вопросы, которые задают на собеседованиях
🟢 Вопросы для Junior-разработчика
- Что такое представление (view) в Django?
- Чем отличаются function-based views и class-based views?
- Какой аргумент обязательно принимает функция-представление?
- Как вернуть HTML-ответ из представления?
- Для чего используется функция render()?
- Что такое get_object_or_404() и зачем она нужна?
- Как передать переменные из представления в шаблон?
- Что делает тег {% url 'имя_маршрута' аргументы %} в шаблоне?
- Чем отличаются {{ переменная }} и {% тег %} в шаблонах Django?
- Что произойдёт, если в {% for %} не использовать {% empty %}?
🟡 Вопросы для Middle-разработчика
- Как работает механизм маршрутизации (path(), re_path(), include()) в Django?
- Зачем использовать app_name и namespace в urls.py?
- Как организовать маршруты в большом проекте с несколькими приложениями?
- В чём разница между HttpResponse, render() и redirect()?
- Как Django находит шаблоны при рендеринге?
- Какие способы передачи данных в шаблон ты знаешь, кроме контекста в render()?
- Как избежать дублирования кода в шаблонах?
- Как работает механизм наследования шаблонов в Django?
- Как подключать статику и медиафайлы в шаблонах?
- Какие фильтры шаблонов ты используешь чаще всего?
🔴 Вопросы для Senior-разработчика
- Как организовать структуру проекта, чтобы он был расширяемым и поддерживаемым при росте количества представлений и маршрутов?
- Как построить REST API на основе существующих views, не переписывая бизнес-логику?
- Как реализовать шаблоны с минимальным количеством логики, соблюдая Separation of Concerns?
- Как писать собственные template tags и фильтры в Django?
- Как реализовать универсальные компоненты шаблонов (например, карточку поста) для повторного использования?
- Как масштабировать маршрутизацию с использованием вложенных include() и пространств имён?
- Как обеспечить кэширование шаблонов и представлений для повышения производительности?
- Как настроить шаблонные контекстные процессоры и зачем это нужно?
- Какие подходы ты используешь для тестирования представлений и шаблонов?
- Как обезопасить шаблоны Django от XSS и других атак?
Заключение: чему мы научились и зачем это нужно
В этой статье мы прошли полный цикл разработки базового блога на Django 5:
- Создали представления для списка и деталей постов,
- Настроили маршруты с использованием пространства имён,
- Построили гибкую систему шаблонов на основе base.html,
- Освоили фильтрацию данных через менеджеры моделей,
- Добавили кастомную команду управления публикациями через manage.py,
- Оформили блог в тёмной теме с адаптивной вёрсткой, сначала в стиле киберпанк, а затем — в стиле Яндекс.Дзен.
Благодаря этому вы:
- На практике закрепили архитектуру Django: Model → View → Template.
- Поняли, как отделять логику отображения от бизнес-логики.
- Получили основу для любого контентного проекта: от блога до новостного портала.
- Познакомились с настройкой тем оформления и созданием интерфейсов, удобных для чтения.
Этот проект — отправная точка для масштабирования:
- Добавления пагинации, поиска, тегов;
- Подключения комментариев и авторизации;
- Развёртывания в продакшен с помощью Docker, Nginx и PostgreSQL.
Если статья была полезной
📌 Если статья оказалась полезной — поставьте лайк или отметьте её, чтобы я понял, что такой формат стоит развивать дальше.
✍️ Напишите в комментариях, как вы обычно создаёте шаблоны и маршруты — используете class-based views или предпочитаете function-based? А может, хотите увидеть сравнение двух подходов?
📤 Если у вас в команде есть те, кто только начинает изучать Django — поделись с ними ссылкой на статью. Это сэкономит им кучу времени и поможет сразу строить проект по best practices.
📚 Подписывайтесь, чтобы не пропустить следующие разборы: расскажу про пагинацию, теги, систему комментариев, авторизацию и деплой Django-проекта в прод с Docker, Nginx и PostgreSQL.
До встречи в следующих публикациях!