Пишем асинхронное web-приложение на Python3, статика

newbie

Опубликован:  2021-01-02T06:20:14.233136Z
Отредактирован:  2021-01-06T06:56:56.276520Z
4
0
0
Вы неавторизованы, рекомендую зарегистрироваться и авторизоваться.

Продолжаем разработку асинхронного web-приложения auriz. В этом выпуске поговорим о так называемом каталоге статичных файлов, я научу auriz обслуживать этот каталог и файлы в нём и подготовлю всё необходимое для разработки клиентской части web-приложения. Будет интересно...

1. Фронтенд, бэкенд и who is who

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

  1. Код, который исполняется на сервере, обычно эту часть web-приложения называют backend;
  2. Код, который исполняется на клиенте - frontend.

И клиентская и серверная части приложения, как правило, используют сторонний код. Сторонний код клиентской части, а так же оригинальные таблицы стилей, сценарии JavaScript, файлы изображений etc. хранятся на сервере и обычно их называют статикой, эти файлы не изменяются в процессе работы web-приложения. В этом обзоре я покажу, как можно подключить в приложение статику. Об этом далее...

2. Восстанавливаем проект в новом окружении

В предыдущей статье цикла я создал базовый каталог приложения - auriz, и в нём описал начальную конфигурацию проекта. Проблема в том, что все действия я выполнял на другом компьютере. Сейчас мне необходимо восстановить проект в моей рабочей операционной системе, и восстанавливать его я буду из Git-репозитория на github.com.

Иду на сайт и захожу в проект auriz, нахожу и копирую в буфер обмена ssh ссылку на проект.

YBAyPQxHsy.png

Замечание: чтобы использовать ssh-соединение с сервером github.com необходимо создать ключ и скопировать его публичную часть в свой профиль в соответствующем разделе настроек, подробности можно почерпнуть в документации Git-сервера.

Запускаю терминал, захожу в каталог workspace и клонирую Git-репозиторий используя ссылку из буфера обмена.

git clone git@github.com:newbie-c/auriz.git

7oIwBnDBUh.png

В результате, в моём текущем каталоге появился новый каталог с именем auriz. Вхожу в этот каталог.

cd auriz/

YYPHAthYbS.png

Я дома... Посмотрим на дерево базового каталога с помощью команды tree.

D6lUQzxjO5.png

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

HapeqaXwzE.png

Текущие настройки приложения можно восстановить из файла env.template.

cp env.template .env

YdslIzMwhm.png

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

python runserver.py

yRIekMjFb4.png

Здесь следует обратить внимание, что web-браузер после моего явного запроса к серверу запросил автоматически ещё один адрес (/favicon.ico) и получил на этот запрос ответ со статусом 404 Not Found. Далее я покажу, как этот статус можно исправить...

3. Определяем каталог для статики

Проект восстановлен, можно сосредоточить своё внимание на очередном этапе разработки. И сейчас мне нужно определить каталог, в котором будут храниться статические файлы auriz, для этого создаю во вложенном каталоге auriz новую директорию с именем static и в ней три вложенных каталога: css, images, js.

mkdir auriz/static
mkdir auriz/static/css
mkdir auriz/static/images
mkdir auriz/static/js

ZjzWJKWm5K.png

Открываю в текстовом редакторе файл с конфигурацией приложения.

vim auriz/__init__.py

В этом файле я добавлю несколько строчек. Мне понадобится ещё пара импортов.

...
from starlette.routing import Mount, Route                                      
from starlette.staticfiles import StaticFiles
...

Кроме этого, мне необходимо привязать каталог static к базовому каталогу.

...
static = os.path.join(base, 'static')
...

И, наконец, я могу дописать в роутер приложения ещё один адрес.

...
app = Starlette(
    debug=settings.get('DEBUG', cast=bool),
    routes=[Route('/', show_index, name='index'),
            Mount('/static',
                  app=StaticFiles(directory=static), name='static')])
... 

DgAoWnMncV.png

Чтобы это заработало, мне необходимо установить в виртуальное окружение ещё одну зависимость.

pip install aiofiles

I4Wylyg7LH.png

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

pip freeze > requirements.txt

Assb11DFuH.png

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

vim auriz/static/js/base.js

YEigA7hLEs.png

Запускаю сервер и стучусь в браузере по заданному адресу.

wpxvve4LgS.png

Как видно на снимке экрана выше, теперь файлы из каталога static стали доступны клиенту. Ещё одна сиюминутная цель достигнута. Продолжим далее...

4. Собираем комплект статичных файлов проекта

Для клиентской части auriz я буду использовать следующие библиотеки:

  • Bootstrap v3.4 - комплексный фреймворк общего назначения;
  • jQuery - JavaScript-библиотека для работы с DOM;
  • Moment.js - JavaScript-библиотека для работы с датами и временем.

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

mkdir auriz/static/vendor
cd auriz/static/vendor/

ifhBguSoW7.png

Открываю браузер, иду на сайты перечисленных вендоров и копирую ссылки для загрузки библиотек. Начнём с Bootstrap.

wget https://github.com/twbs/bootstrap/releases/download/v3.4.1/bootstrap-3.4.1-dist.zip

KJsVH5I2VX.png

Распаковываю архив, а затем переименовываю каталог и удаляю лишнее.

unzip -q bootstrap-3.4.1-dist.zip 
mv bootstrap-3.4.1-dist bootstrap
rm -rf bootstrap/js/npm.js
rm -rf bootstrap/js/bootstrap.min.js
rm -rf bootstrap/css/*.min.*
rm -rf bootstrap-3.4.1-dist.zip 

KoeDeIgAU3.png

Следующий jQuery...

wget -nv https://code.jquery.com/jquery-3.5.1.js
wget -nv https://code.jquery.com/jquery-3.5.1.min.map

И, наконец, Moment.js.., хоть эта библиотека по мнению авторов и устарела, в этом проекте я буду использовать именно её.

wget -nv https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.js
wget -nv https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/locale/ru.js

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

xc4ZJouEPb.png

Можно сменить текущий каталог терминала.

cd ~/workspace/auriz

И продолжить разработку, об этом далее...

5. Устанавливаем иконку для избранного

У каждого web-сайта есть обязательные url-адреса, на которые сервер будет получать автоматические запросы от разных клиентов, например: /favicon.ico, /robots.txt, /sitemap.xml и так далее... Пришло время определить в auriz первый из перечисленных url.

Чтобы определить в приложении url-адрес страницы, необходимо выполнить следующую последовательность действий:

  1. Определить функцию представления, которая будет исполняться при поступлении на сервер HTTP-запроса на этот url, и разработать логику этой функции представления;
  2. Определить сам url-адрес в роутере приложения и связать его с разработанной функцией представления.

В рамках этого проекта я уже выполнял эти два действия для стартовой страницы сайта. Настало время научить сервис отдавать иконку для избранного. Для этого открываю в текстовом редакторе файл views.py из каталога main.

vim auriz/main/views.py

В этом файле я допишу два новых импорта и определю в качестве функции-представления новую корутину.

import os

from starlette.responses import FileResponse, HTMLResponse


async def show_favicon(request):
    if request.method == 'GET':
        base = os.path.dirname(os.path.dirname(__file__))
        return FileResponse(
            os.path.join(base, 'static', 'images', 'favicon.ico'))


...

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

uqnotLEFO1.png

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

Открываю в текстовом редакторе файл с конфигурацией приложения.

vim auriz/__init__.py

В этом файле мне необходимо дописать ещё один импорт.

...
from .main.views import show_index, show_favicon
...

И вписать корутину show_favicon в роутер приложения.

...
app = Starlette(
    debug=settings.get('DEBUG', cast=bool),
    routes=[Route('/', show_index, name='index'),
            Route('/favicon.ico', show_favicon, name='favicon'),
            Mount('/static',
                  app=StaticFiles(directory=static), name='static')])
...

EDpgfBFovn.png

Запускаю сервер, затем web-браузер и стучусь в браузере по адресу иконки для избранного нашего приложения.

python runserver.py

4RhSrQGbFx.png

Ещё одна маленькая меркантильная цель достигнута.

6. Сохраняем проект в Git

Поскольку на этом этапе разработки я добавил в базовый каталог приложения новые текстовые файлы с кодом сторонних разработчиков, мне необходимо исключить их из Git-репозитория. Открываю в текстовом редакторе файл .gitignore и вписываю в него ещё одну строчку.

vim .gitignore

SCIAoMn2Iy.png

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

mkdir dep

Сменю текущий каталог терминала.

cd auriz/static

И создам в заданном каталоге архив другого заданного каталога.

zip -r ~/workspace/auriz/dep/static-vendor.zip vendor/

BRnvBSnLex.png

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

7. Продолжение следует

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

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

Комментарии: