Проектируя дипломный проект, и разбираясь попутно в возможностях Flask и Werkzeug решил для себя небольшую задачку, и нашел удобные средства, которые могут решаться без применения middleware, на уровне приложения и модуля, что весьма удобно.
Объект Request в Flask, позволяет получить доступ к аргументам, полученным после парсинга URL. К примеру, у нас имеется Rule('/user/<username>')
. При получении запроса, совпадающего с этим правилом, в request будет создан не пустой словарь request.view_args
, который будет содержать аргументы для view. Но иногда, есть задачи, когда на основе этих аргументов требуется выполнять какую-то одну и ту же обработку в нескольких view, либо требуется, чтобы такая обработка была выполнена перед выполнением самого view, или возможно постобработка.
В Flask, приложение имеет возможность задать пост и пред обработчики, как уровня приложения, так и уровня модуля (если модули используются в приложении), и при последнем варианте, модуль может объявлять свои обработчики уровня приложения. Все они выполняются после создания объекта _RequestContext
, объекты которого будут доступны, при запросе из в обработчиках. Это request, session, g и остальные. Поэтому, в обработчиках можно задействовать и request.view_args
.
Рассмотрим на примере. Пример взят из моего дипломного проекта.
Допустим, мы пишем web-приложение, которое работает с несколькими базами данных. Выбор базы зависит от аргументов переданных view. То есть, модули приложения, содержат алгоритмы для обработки данных, и не должны использовать любую базу данных. В нашем примере, выбор базы данных будет основываться на базе полученного имени проекта (база данных на проект). В нашем примере, мы используем MongoDB, и пул соединений (объект mongokit.Connection
) доступен как глобальный объект mongodb. Префик URL для всех модулей '/<project>'
, что позволяет однозначно идентифицировать проект, с которым ведется работа.
Напишем, глобальный обработчик приложения, который помещает в g.projectdb
соединение с базой данных текущего проекта.
@app.before_request
def select_project_db():
if 'project' in request.view_args:
g.projectdb = mongodb[request.view_args['project']]
Простой и маленький обработчик, а упрощает жизнь разработчику. Теперь в любом view, не нужно думать о том, к какой базе соединится, и не надо думать как регистрировать модель. Запрос можно посылать просто, как:
cursor = g.projectdb.Tasks.find({...})
В вышеприведенном примере, предположим, что Tasks
- это зарегистрированная в пуле соединений модель, с указанным __collection__
. Просто? Как дважды два. Мы не думаем, какая база, какой проект, когда регистрировать модель (если позаботились о регистрации ранее), не мучаемся импортами. Мы просто используем соединение, и обрабатываем данные, мы думаем о задаче. А если уж потребуется знать, какой проект текущий - то переменная project
всегда доступна, как аргумент view.
При этом мы легко можем организовать структуру как отдельно взятой базы, так и структуру баз в целом. Неявный routing получается. А все благодаря, маленькой возможности Flask. =)))