Пишем web на Python3, создание приложения

newbie

Опубликован:  2019-01-08T11:51:24.583783Z
Отредактирован:  2019-01-09T07:56:44.159204Z

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

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

8krxsmW1RF.png

В этом терминале, находясь в базовом каталоге проекта с активированным виртуальным окружением, я буду выполнять все последующие команды и действия. И начну я с определения структуры проекта и создания его каталогов и файлов. Файлы и каталоги проекта я обычно создаю в консоли, для этого мне потребуются две команды: mkdir и touch. Напомню, mkdir создаёт новый каталог по указанному адресу, а touch создаёт пустой текстовый файл с указанным именем.

В рамках проекта selfish мне необходим каталог, в котором будут храниться файлы с кодом web-приложения. Для этого каталога выбираю имя, совпадающее с именем проекта - selfish.

mkdir selfish

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

touch selfish/__init__.py

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

mkdir deployment

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

mkdir selfish/main
touch selfish/main/__init__.py

Подпрограмме main понадобится модуль с функциями представления, создаю его.

touch selfish/main/views.py

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

mkdir selfish/templates
mkdir selfish/static

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

mkdir selfish/static/images

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

mkdir tests

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

touch config.py

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

touch manage.py

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

suKmQbJ0Ev.png

Запускаю интегрированную среду PyCharm и смотрю на свой проект.

TyU8Up8WvZ.png

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

Как многие уже наверно догадались по содержанию файла README.md, проект selfish будет использовать web-фреймворк общего назначения Flask. Flask - это сторонняя библиотека, которая предоставляет уже готовые инструменты для решения типовых прикладных задач серверной части web. Этот фреймворк достаточно гибок, приложение на его базе может состоять из одного файла, в тоже время он позволяет создавать сложные многоуровневые приложения, состоящие из нескольких подпрограмм. На текущий момент я приступаю к разработке первой подпрограммы своего web-приложения selfish, и чтобы воспользоваться инструментами Flask, мне необходимо его установить. Устанавливать его я буду в виртуальное окружение проекта selfish.

pip install flask

efzBXb4eFx.png

Открываю в PyCharm файл selfish/main/__init__.py и привожу его к следующему виду.

from flask import Blueprint

main = Blueprint('main', __name__)

from . import views

p2EIzMV8VN.png

Я импортировал класс Blueprint из пакета flask, создал экземпляр этого класса - переменную main, и импортировал модуль views из пакета main. Каталог selfish/main является пакетом, в дандерините пакета модули этого пакета могут быть импортированы относительным импортом посредством точки. Так как файл selfish/main/views.py уже существует, PyCharm подтвердил возможность импорта. Единственное замечание среды на PEP8 к сожалению исправить не получится, досадно, но придётся с этим смириться. В других случаях следует избегать подобных замечаний интегрированной среды и стремиться к чистоте кода.

Подпрограмма main создана, но на текущий стадии разработки ничего полезного она делать не умеет, это вскоре будет исправлено, а пока мне необходимо определиться с конфигурацией экземпляра Flask, которая будет храниться в файле config.py в корне проекта selfish. Этот файл уже создан, поэтому просто открываю его в редакторе PyCharm и привожу к следующему виду.

class Config:
    SECRET_KEY = 'My Secret Key'

    @staticmethod
    def init_app(app):
        pass


class Development(Config):
    DEBUG = True


class Testing(Config):
    TESTING = True


class Production(Config):
    pass


config = {'development': Development,
          'testing': Testing,
          'production': Production,
          'default': Development}

Здесь я определил класс Config и три дополнительных класса Development, Testing и Production, которые наследуют от класса Config. Дело в том, что жизненный цикл selfish предполагает, что приложение должно иметь несколько режимов работы. На стадии разработки и отладки приложение будет запускаться в режиме разработки. Автоматизированное тестирование приложения предполагает режим тестирования. И после того, как приложение наберёт необходимый функционал, его разворачивают на сервер, где оно работает в штатном режиме в составе сервера, исполняя заложенные в него задачи. Каждый из этих режимов может и будет иметь характерные для него опции конфигурации. Только что созданные в файле config.py классы позволят дифференцировать конфигурацию приложения для каждого режима работы. При этом класс Config будет определять опции конфигурации общие для всех режимов запуска приложения, а его наследники - опции конфигурации характерные для каждого конкретного режима работы. Все предусмотренные режимы сведены в словарь config, где каждому режиму работы определено название в виде строки - ключ словаря, и соответствующий класс конфигурации - значение в этом ключе. В том числе словарь config содержит ключ default.

Кроме файла конфигурации мне необходима специальная программа, которая будет особым образом создавать экземпляр класса Flask. Открываю файл selfish/__init__.py и пишу в него следующий код.

from flask import Flask

from config import config


def create_app(config_name):
    app = Flask(__name__)
    conf_obj = config[config_name]
    app.config.from_object(conf_obj)
    conf_obj.init_app(app)
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)
    return app

HFLs159Q37.png

Здесь я импортировал класс Flask из пакета flask и словарь config из конфигурационного файла config.py. Далее я создал функцию create_app, которая принимает в качестве аргумента строку, содержащую название режима работы приложения. Эта функция создаёт экземпляр класса Flask, производит его конфигурацию в соответствии с переданным функции аргументом, регистрирует подрограммы и возвращает созданный экземпляр Flask - переменную app.

Файл конфигурации config.py и функция create_app дадут мне возможность в будущем расширять полученный экземпляр Flask, подключать в него новые модули, полученные из сторонних библиотек, создавать собственные подпрограммы, регистрировать их и управлять опциями конфигурации приложения.

Моей следующей целью будет менеджер проекта - специальная программа, которая позволит управлять проектом в процессе разработки, отладки и тестирования кода приложения. Файл, в котором будет храниться код этой программы уже создан - manage.py. Менеджер проекта я построю на основе расширения Flask-Script, которое необходимо установить в виртуальное окружение проекта.

pip install Flask-Script

zmFGTPCS4R.png

Открываю файл manage.py в PyCharm и пишу в него новый код. Импортирую необходимые объекты из Flask-Script и selfish.

from flask_script import Manager, Shell

from selfish import create_app

При помощи функции create_app создаю приложение, а при помощи класса Manager - экземпляр менеджера.

app = create_app('default')
manager = Manager(app)

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

def make_shell_context():
    return {'app': app}

Создаю команду менеджера для активации служебной консоли проекта.

manager.add_command('shell', Shell(make_context=make_shell_context))

И запускаю менеджер проекта в стандартной идиоме Питона.

if __name__ == '__main__':
    manager.run()

Таким образом файл manage.py приобретает следующий вид.

vW6qjwcTaX.png

Давайте посмотрим, что мне даёт этот код в manage.py. Перехожу в терминал и просто тестирую программу ручками.

python manage.py --help

Nszy1Qq1ef.png

Справка менеджера проекта показывает, что в настоящий момент он содержит две команды: shell и runserver. Первая запускает консоль Питона в контексте приложения selfish (экземпляра Flask), которая мне пригодится в будущем для интерактивной отладки кода приложения. Пробую.

3iUVPtUU6k.png

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

Поскольку selfish в перспективе планирует стать web-сайтом сети, ему понадобится иконка для избранного. Иконку для избранного я позаимствую у этого сайта, скачиваю изображение в каталог selfish/static/images.

wget -O selfish/static/images/favicon.ico http://auriz.ru/favicon.ico

IPrd5aSvJL.png

Пришло время создать первый url-адрес web-приложения selfish. Открываю в PyCharm файл selfish/main/views.py - это модуль, в котором будут храниться функции представления подпрограммы main, этот файл уже создан. Пишу в него следующий код.

from os.path import join

from flask import current_app, request, send_from_directory

from . import main


@main.route('/favicon.ico')
def show_favicon():
    return send_from_directory(
        join(current_app.static_folder, 'images'),
        request.path[1:],
        mimetype='image/vnd.microsoft.icon')

4hD1CqMg0X.png

Здесь я импортировал функцию join из модуля стандартной библиотеки os.path, которая поможет мне воспроизвести адрес каталога, в котором хранится файл иконки. Из пакета flask я импортировал следующие инструменты:

  • объект current_app, с помощью которого воспроизведу адрес каталога статических файлов текущего приложения;
  • объект request, при помощи которого получу доступ к атрибутам запроса;
  • служебную функцию send_from_directory, которая позволит получить доступ к указанному файлу иконки и сформировать HTTP-ответ.

Далее я импортирую объект main из одноимённой подпрограммы, который является экземпляром класса Blueprint и позволит задать url-адреса для каждой функции представления этого модуля. В данном случае импорт относительный посредством точки. Затем на основе импортированных инструментов создаю первую функцию преставления - show_favicon, в декораторе этой функции указываю заданный url-адрес, а в теле функции при помощи send_from_directory формирую экземпляр класса Response и возвращаю этот экземпляр.

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

python manage.py runserver

55RQ0EqbLR.png

Замечание: отладочный сервер в процессе работы выдаёт в терминал важную отладочную информацию, её следует научиться читать и всегда обращать внимание на выхлоп сервера, остановить отладочный сервер можно сочетанием ctrl+c.

Отладочный сервер работает, запускаю Интернет браузер и пробую стучаться в созданный url-адрес.

7uiltxc43S.png

На снимке экрана выше запрошенный url в адресной строке браузера подчёркнут синим фломастером, на отправленный запрос баузер показал изображение иконки для избранного проекта selfish. Можно сказать вуаля...

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

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