Проект Django может включать множество приложений, располагающихся каждое в своем физическом каталоге на жестком диске. Например, проект универсального интернет-магазина, где каждое приложение это каталог определенных товаров. Такая структура проекта позволяет комфортно работать с каждым приложением отдельно, не запутываясь среди файлов и папок других приложений.
В настоящей статье описано создание приложения Django в среде программирования Visual Studio на примере простейшего интернет-магазина электроники. Подробно описывается backend приложения, frontend состоит из минимальной html разметки с встроенными стилями. Для упрощения программного кода в этой статье не рассматриваются модели приложений.
Приложения Django устанавливаются в подготовленный проект на фреймворке Python Django. В один проект можно установить несколько приложений. Проект содержит набор конфигураций общих для всех приложений, зарегистрированных в проекте Django. Создание проекта Django смотрите на странице Django - создание проекта в Visual Studio.
Для практики создадим веб-приложение простого интернет-магазина электронных компонентов. Установка приложения предполагает создание базовой структуры каталогов и некоторых файлов. Приложение Django создается из окна командной строки, которое вызывается из контекстного меню названия проекта Visual Studio пунктом Открыть командную строку здесь…, в окно вводится команда: python manage.py startapp название_приложения
Создадим приложение для сайта интернет-магазина: python manage.py startapp electronics
Первоначально папка приложения electronics не включена в проект и невидима. В меню Обозревателя решений необходимо нажать кнопку Показать все файлы и затем включить в проект Visual Studio папку electronics, которая представляет пакет веб-приложения Django. В итоге получается такая структура проекта Django с приложением, смотрите скриншот ниже.
Чтобы фреймворк Django знал о приложении, его необходимо включить в проект. Приложение регистрируется в модуле проекта settings.py, в параметре INSTALLED_APPS. В этот параметр требуется добавить путь к классу конфигурации приложения: electronics.apps.ElectronicsConfig
как показано ниже в коде.
Регистрация приложения необходима для возможности получения программной функциональности от фреймворка Django, например для корректного поиска шаблонов html и работы с базой данных.
Добавим к уже подключенным стандартным приложениям фреймворка Django наше приложение интернет-магазина:
Перед созданием сайта необходимо спланировать его структуру. Структуру выберем такой:
Главная страница
Каталог разделов
Раздел
Электронный компонент раздела
Контакты
Error404
Теперь у нас есть минимальная структура сайта интернет-магазина, на ее базе уже можно создавать frontend и backend, постепенно повышая сложность и функциональность сайта.
Поскольку фреймворк Django поддерживает концепцию MVC, следует ожидать, что он должен иметь модели, представления и контроллеры.
Работая с фреймворком Django и придерживаясь описания классической схемы «модель-представление-контроллер» хочется определить структуру MVC так:
- модели (например, таблиц базы данных) определяются в модуле models.py,
- контроллеры в модуле views.py,
- страницы представлений — это html шаблоны, находящиеся в папке templates.
Разработчики Django придерживаются другой терминологии для своего детища. Django — это фреймворк MTV, то есть «модель-шаблон-представление». В их понимании представление описывает данные, которые предоставляются пользователю, но не те, которые отображаются. И представления (Views) находятся в одноименном модуле views.py. Контроллер, по замыслу разработчиков — это сам фреймворк Django, который отправляет запрос в соответствующее представление в соответствии с конфигурацией URL-адреса.
Различие мнений о концепции MVC в Django вероятно связаны с различной позиции взглядов: со стороны разработчиков или со стороны пользователей фреймворка. Эти рассуждения нисколько не умаляют достоинство фреймворка Django и скорее говорят о высокой его популярности среди веб-разработчиков на Python. Для тех, кто интересуется более подробной информацией вот ссылка на сообщество Django Community.
Фреймворк Django дает возможность определять человеко-понятные веб-адреса. Чистая, элегантная схема URL-адресов — важная деталь в любом высококачественном веб-приложении. URL-маршруты в фреймворке определяются в проекте и приложениях в модулях urls.py. В этом модуле переменная urlpatterns хранит список URL-шаблонов. Модуль urls.py проекта хранит интернет-адреса всего проекта, в папке приложения находится urls.py уровня приложения.
Шаблон для URL-адресов указывается относительно хоста и не включает протокол, адрес хоста, строку запроса, номер порта. Django просматривает каждый адрес по порядку и останавливается на первом, который соответствует запрошенному URL.
Список адресов urlpatterns состоит из функций, возвращающих элементы (в версии 4.2 объект класса URLResolver) для включения в urlpatterns: path( route , view , kwargs = None , name = None )
- route – строка шаблона URL;
- view – контроллер (метод или класс модуля views.py) для обработки данного запроса, или функция include(), которая импортирует списки веб-адресов из других модулей (в нашем случае в модуль маршрутов проекта из electronics.urls);
- kwargs - позволяет передавать дополнительные аргументы
- name – имя маршрута, упрощает корректировку веб-адресов во множестве html шаблонов.
Создадим файл маршрутов urls.py в папке electronics и определим веб-адреса для интернет-магазина согласно структуре его сайта (смотрите выше).
Модуль маршрутов приложения electronics:
from django.urls import path
from . import views
# Пространство имен для маршрутов данного приложения
app_name = "electronics"
# Маршруты для сайта электронного интернет-магазина
urlpatterns = [
# views.index - контроллер обрабатывающий данный запрос
# name хранит имя маршрута
path("", views.index, name="index"),
path("catalog/", views.catalog, name="catalog"),
path("catalog/section/", views.catalog_section, name="catalog_section"),
path("catalog/section/component/", views.catalog_component, name="catalog_component"),
path("electronics/contacts/", views.contacts, name="electronics_contacts")
]
Модуль маршрутов проекта Django:
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
# Список маршрутов импортируется из приложения electronics
path('', include("electronics.urls", "electronics")),
path('admin/', admin.site.urls),
]
# Переопределение шаблона страницы об ошибке 404
handler404 = 'electronics.views.error404'
Программная строка: handler404 = 'electronics.views.error404'
переопределяет стандартный обработчик Django для ошибки «Страница не найдена» на наш контроллер в модуле views.py приложения electronics. Обработчики ошибок переопределяются в модуле маршрутов urls.py уровня проекта. Установка обработчиков в urls.py приложений не будет иметь никакого эффекта. Значения должны быть вызываемыми или строками, представляющими полный путь импорта Python к контроллеру модуля views.py.
Для визуальных представлений Django использует шаблоны из текстовых файлов, например, html, xml, txt и даже без расширения, если так будет удобно программисту. В данной статье мы будем работать с html шаблонами, тем более что в Visual Studio для html разметки обеспечена мощная эргономичная поддержка: подсветка синтаксиса, интеллектуальное завершение кода с IntelliSense и форматирование.
По умолчанию фреймворк Django предлагает собственный встроенный язык шаблонов DTL. Поддержка DTL множества видов смарт-разметки и наследования шаблонов позволяет существенно уменьшить количество кода и построение четкой логики отношений шаблонов.
Для Django принято размещать шаблоны в папках templates приложений по такому пути: название_папки_приложения/templates/название_папки_приложения/название_шаблона.html
для нашего интернет-магазина electronics: electronics/templates/electronics/index.html
Повторную папку с названием приложения рекомендуется создавать для идентификации html шаблонов с одинаковым именем среди папок templates подключенных приложений (смотрите выше регистрация приложений).
В модуле views.ru пути к шаблонам веб-страниц указываются относительно каталога templates приложения, но поиск шаблонов осуществляется в модуле проекта, поочередно присоединяя относительный путь к абсолютному пути папок приложений. Первое успешное совпадение файла шаблона отменяет дальнейший поиск. Конечно, при единственном приложении проекта, артефакты совпадения имен шаблонов отсутствуют.
Псевдокод для наглядного объяснения необходимости повторной папки с названием приложения:
# =============================
# модуль views.py приложения
# Относительный путь шаблона templates/electronics/index.html
render(request, "electronics/index.html", context)
# Относительный путь шаблона templates/index.html
render(request, "index.html", context)
# =============================
# модуль settings.py проекта
# --- абсолютный путь в первом случае ---
# приложение app - файл не найден
D:/project/app/ + templates/electronics/index.html
# приложение electronics - файл найден
D:/project/electronics/ + templates/electronics/index.html
# --- абсолютный путь во втором случае ---
# приложение app - файл найден
D:/project/app/ + templates/index.html
# приложение electronics - файл найден
D:/project/electronics/ + templates/index.html
Используя возможности системы шаблонов Django (наследование, вставки частей html контента и др.) создадим такую структуру для веб-приложения electronics:
layout.html – мастер-страница для унификации вида всего сайта.
menu.html – шаблон меню для включения в мастер-страницу.
footer.html – шаблон подвала веб-страниц сайта.
page.html – шаблон для содержимого основных страниц.
error404.html – шаблон содержимого для оповещения об отсутствующей страницы.
Мастер-страница (или макет) представляет собой оформленную стилями страницу, которая формирует вид всех веб-страниц сайта. Мастер-страница имеет отмеченные поля для включения содержимого подчиненных страниц. Приложение electronics имеет мастер-страницу с полями: {% include 'electronics/menu.html' %} – включение кода сформированной страницы по ее пути; {% block content %}{% endblock %} – поле для вставки динамического контента подчиненных страниц, блок идентифицируется по имени, в данном случае - content; {{ title }} – здесь и в других шаблонах, вывод значения переменной, получаемой от контроллеров модуля views.py.
HTML разметка шаблона меню состоит из списка ссылок на страницы сайта. Код динамической генерации HTML файла menu.html содержит директивы: {# Меню сайта #} - здесь и в других шаблонах, комментарии не отображаемые при визуализации страницы в браузере. {% url 'electronics:index' %} - получение строки веб-адреса от контроллера views.py по имени маршрута. Использование имени маршрута (см. выше в маршрутизации приложения) вместо строки адреса значительно облегчает возможную корректировку веб-адресов.
Разметка основных страниц включается в мастер-страницу благодаря директиве: {% extends "electronics/layout.html" %} - директива указывает что текущий html-шаблон является расширением шаблона layout.html. {% block content %}...{% endblock %} - блок, отображаемый на мастер-странице.
Переменные {{ color }} и {{ content }} получают значение от контроллера из views.py.
Теперь надо написать код Python, который принимает веб-запросы по адресам, определенным в маршрутизаторе, и возвращает ответ в виде веб-страницы. Вспоминая классическое определение концепции MVC, этот код называется контроллерами, но в фреймворке Django – это представления.
Напишем код представлений-контроллеров, который по умолчанию располагается в модуле views.py. Программный код, принимающий запросы может быть оформлен в виде функций или классов. Для нашего простого интернет-магазина electronics напишем функции обрабатывающие входящие запросы и возвращающие веб-страницы с цветными строками. Названия функций используются в модуле маршрутов, см. выше в маршрутизации.
Веб-ответ построен на функциях быстрого доступа Django: render( request, template_name, context = None, content_type = None, status = None, using = None ) - объединяет данный шаблон с заданным словарем контекста и возвращает объект класса HttpResponse с этим визуализированным текстом.
request - полученный объект запроса. context - словарь-контейнер для отправки значений в данный шаблон страницы. Словарь контекста может вмещать множество значений. content_type - тип MIME ответа ( image/jpeg, application/pdf и др.), по умолчанию «text/html» status - код ответа (400, 403, 404, 500 и др.), по умолчанию 200. using - псевдоним для этого конкретного шаблонизатора. Это идентификатор, который позволяет выбрать движок для рендеринга веб-страниц.
Программный код модуля views.py приложения electronics:
from django.shortcuts import render
# ===== Контроллеры =====
# Контроллеры для главной страницы
def index(request):
return func(request, "Здравствуйте! Рады вас видеть в магазине Электроники!")
def catalog(request):
return func(request, "Каталог разделов интернет-магазина электроники", "blue")
def catalog_section(request):
return func(request, "Список электронных компонентов одного раздела", "green")
def catalog_component(request):
return func(request, "Страница Электронный компонент", "brown")
def contacts(request):
context = {
"title": "Контакты",
}
# render - функция быстрого доступа фреймворка Django,
# возвращает HttpResponse
return render(request, "electronics/contacts.html", context)
# Функция-контроллер, переопределяющая вызов шаблона при ошибке 404
def error404(request, exception):
context = {
"title": "Страница не найдена!"
}
return render(request, "electronics/error404.html", context)
# ===== /Контроллеры =====
# ===== Вспомогательные функции =====
# Вспомогательная функция, группирующая одинаковый код для некоторых контроллеров
def func(request, text="", color="black"):
context = {
"content": text,
"title": text,
"color": color
}
return render(request, "electronics/page.html", context)
# ===== /Вспомогательные функции =====
После создания маршрутов, контроллеров и представлений-шаблонов можно запускать приложение Django для проверки работы приложения. Должны запрашиваться и корректно загружаться веб-страницы по url-адресам:
- http://localhost:5000/catalog/
- http://localhost:5000/catalog/section/
- http://localhost:5000/catalog/section/component/
- http://localhost:5000/electronics/contacts/
Запросы любых несуществующих адресов должны выводить страницу с оповещением ошибки 404.
Python 3 версии по умолчанию определяет символы в кодировке UTF-8. Но для этого файлы в которых есть символы кириллицы или другие символы не относящиеся к ANSI, должны быть в кодировке UTF-8. Средствами Django текстовые файлы могут создаваться в формате ANSI и поэтому для правильного отображения символов кириллицы необходимо файл преобразовать в кодировку UTF-8.
Изменение кодировки в среде Visual Studio:
Главное меню Файл->Сохранить название_файла как…
Изменить кодировку файла можно также в редакторе Notepad++ или Блокноте Windows.
Теоретически можно красиво описывать любой исходный код, но все же практика критерий истины. Для целей тестирования и дальнейших разработок ниже прикреплен исходный код приложения Django. В проект включены два приложения electronics и тестовый app.
Архивный файл исходника содержит необходимую виртуальную среду для работы проекта на Python. Для успешного запуска проекта необходимо в файле pyvenv.cfg виртуальной среды прописать версию (не ниже 3.8) и путь до вашего базового интерпретатора, например:
home = G:\MyProjects\Programming\Pythons\Python310_7
include-system-site-packages = false
version = 3.10.7