如何构建大型FLASK应用
作者:O.S. Tezer 发表时间:2014年1月16日 原文链接: How To Structure Large Flask Applications
引言
有许多构建Python Web应用的方法和惯例。尽管某些框架附带了工具(充当脚手架),以自动化和简化任务(和令人头疼的问题),但几乎所有解决方案都依赖于打包/模块化应用程序,因为代码库在相关文件和文件夹中有逻辑地分布。
极简主义的WEB应用程序开发框架Flask有自己的工具——blueprints。
在本 DigitalOcean 文章中,我们将了解如何创建应用程序目录,并将其构建为使用 Flask blueprints创建的可重用组件。这些部分极大地允许(并简化了)应用程序组件的维护和开发。
章节目录
- Flask: 极简主义的应用程序开发框架
- 本文中的选择
- 为Flask准备系统
- 准备操作系统
- 设置Python、pip、virtualenv
- 构建应用程序目录
- 创建应用程序文件夹
- 创建虚拟环境
- 创建应用程序文件
- 安装Flask
- 使用模块和Blueprints(组建)
- 模块基础知识
- 模块模板
- 创建应用程序(run.py、init.py等)
- 使用 nano 编辑run.py
- 使用nano编辑config.py
- 创建模块/组件
- 第1步:构建模块
- 第2步:定义模块数据模型
- 第3步:定义模块表单
- 第4步:定义应用程序控制器(视图)
- 第5步:在"应用/init.py"中设置应用程序
- 第6步:创建模板
- 第7步:在操作中查看你的模块
Flask: 极简主义的应用程序开发框架
Flask是一个极简主义(或微型的)框架,它避免强加处理关键事物的方式。相反,Flask允许开发人员使用他们期望且熟悉的工具。为此,它附带了自己的扩展索引,并且已经存在大量工具来处理从登录到日志记录的所有内容。
它不是一个严格的"常规"框架,部分依赖于配置文件,坦率地说,当涉及到开始和保持事情在控制中,这使得很多事情更容易。
本文中的选择
正如我们刚刚在上一节中介绍的那样,Flask 的做事方式包括使用你感到最舒服的工具。在我们的文章中,我们将使用扩展和库(即数据库提取层)方面最常见的(也是明智的)选择:
- SQLAlchemy (通过Flask-SQLAlchemy)
- WTForms (通过Flask-WTF)
Flask-SQLAlchemy
向 Flask 添加 SQLAlchemy 支持。又快又容易。
这是被认可的扩展。
[mitsuhiko/flask-sqlalchemy
Flask-WTF
Flask-WTF 提供与 WTForms 的简单集成。此集成包括可选的 CSRF 处理,以提高安全性。
这是被认可的扩展。
(created by Dan Jacob
为Flask准备系统
在我们开始构建大型 Flask 应用程序之前,让我们准备我们的系统并下载(和安装)Flask 。
注意: 我们将在运行了最新版可用操作系统(即 Ubuntu 13)的新近Droplet(一款DigitalOcean云主机产品)实例上工作。强烈建议你在新系统上测试所有内容,尤其是如果你积极为客户服务。
准备操作系统
为了有一个稳定的服务器,我们必须有所有相关工具和库的最新和良好维护。
为了确保我们拥有默认应用程序的最新可用版本,让我们从更新开始。
在基于 Debian 的系统(即 Ubuntu、Debian)上运行以下命令:
aptitude update
aptitude -y upgrade
要获得必要的开发工具,请使用以下命令安装"build-essential":
aptitude install -y build-essential python-dev python2.7-dev
设置Python, pip and virtualenv
在 Ubuntu 和 Debian 上,默认有一个最新版本的 Python 解释器(您可以使用)。只剩有限几个额外软件包需要我们去安装:
- python-dev(开发工具)
- pip(用于管理包)
- virtualenv(用于创建独立的虚拟环境)
注意: 此处给出的说明保持简短。要了解更多信息,请查看我们关于 pip 和 virtualenv 的"how-to"一文:Using virtualenv, Installing with Pip, and Managing Packages.
pip
pip 是一个包管理器,它将帮助我们安装我们需要的应用程序包。
运行以下命令以安装 pip:
| python -
curl https://raw.github.com/pypa/pip/master/contrib/get-pip.py
virtualenv
最好将 Python 应用程序及其所有依赖项一起包含在其自己的环境中。环境可以被理解为(简单地说)一个存有所有东西的独立位置(一个文件夹)。为此,使用名为 virtualenv 的工具。
运行以下操作以使用 pip 安装 virtualenv:
sudo pip install virtualenv
构建应用程序目录
我们将使用LargeApp作为我们的示例应用程序文件夹的名称。其中,我们将在应用程序包(即app)和其他一些文件(例如用于运行测试或开发服务器的“run.py”和用于保存Flask配置的“config.py”)旁边有一个虚拟环境(即env)。
该结构(如下所示)是高度可扩展的,并且它是被构建来利用Flask和其他库提供的所有有用工具的。当你看到它的时候别害怕,因为我们将通过构建所有内容来逐步解释所有内容。
目标示例结构:
|-- run.py
创建应用程序文件夹
让我们从创建主文件夹开始。
依次运行以下命令:
mkdir ~/LargeApp
mkdir ~/LargeApp/app
mkdir ~/LargeApp/app/templates
mkdir ~/LargeApp/app/static
我们目前的结构:
|__ /app
创建一个虚拟环境
使用虚拟环境能带来大量好处。强烈建议你为每个应用程序使用心的虚拟环境。将virtualenv文件夹保留在应用程序内部是一种使事情井然有序的好方法。
运行以下命令以创建安装了pip的新虚拟环境。
cd ~/LargeApp
virtualenv env
创建应用程序文件
这一步,我们将在继续使用模块和蓝图(blueprints)之前形成基本的应用程序文件。
运行以下命令以创建基本的应用程序文件:
touch ~/LargeApp/run.py
touch ~/LargeApp/config.py
touch ~/LargeApp/app/__init__.py
我们目前的结构:
|-- run.py
安装Flask和应用程序依赖项
一切准备就绪后,要开始使用Flask进行开发,请使用pip下载并安装它。
运行以下命令在虚拟环境env中安装Flask。
cd ~/LargeApp
env/bin/pip install flask
env/bin/pip install flask-sqlalchemy
env/bin/pip install flask-wtf
注意:在这里,我们在未激活虚拟环境的情况下下载和安装Flask。但是,鉴于我们使用的是虚拟环境本身的pip,它可以完成相同的任务。如果你使用的是激活的环境,则可以使用pip代替。
就是这样! 现在,我们准备使用蓝图(blueprints)构建模块化的更大的Flask应用程序。
使用模块和Blueprints(组件)
模块基础
至此,我们已经建立了应用程序结构,并已下载和准备好了其依赖项。
我们的目标是模块化(即使用Flask blueprints创建可重复使用的组件)所有可以逻辑分组的相关模块。
认证系统就是一个例子。将所有视图(views),控制器(controllers),模型(models)和帮助器(helpers)放在一个地方,并以允许可重用性的方式进行设置,从而使这种结构成为维护应用程序并提高生产率的好方法。
目标示例模块(组件)结构(在/ app内部):
# 我们在这里的模块示例称为* mod_auth *
模块模板
为支持最大模块化,我们将按照上面的约定构造“templates”文件夹,并包含一个新文件夹(与模块具有相同或相似的相关名称)以包含其模板文件。
目标示例模板目录结构(在LargeApp内部):
|-- 404.html
创建应用程序(run.py、init.py等)
在本节中,我们将继续前面的步骤,并从实际的应用程序编码开始,然后继续创建我们的第一个模块化组件(使用blueprints):mod_auth,用于处理所有与身份验证有关的过程(即登录,注册等)。
使用nano编辑“run.py”
注意:nano是Linux系统中的一种文本编辑器。
nano ~/LargeApp/run.py
敲入内容:
# 运行测试服务器
使用CTRL + X保存并退出,然后使用Y确认。
使用nano编辑“config.py”
nano ~/LargeApp/config.py
敲入内容:
# 设置允许调试,此语句只用于开发环境
使用CTRL + X保存并退出,然后使用Y确认。
创建模块/组件
本节是定义本文核心的第一步。在这里,我们将了解如何使用Flask的蓝图(blueprints)创建模块(即组件)。
这样做的高明之处在于,未来的你将不胜感激它所提供的易于维护的代码具有可移植性、可重用性,因为通常情况下,要回来了解剩下的东西是相当困难的。
步骤1:结构化模块
如我们所愿,让我们创建第一个模块的(mod_auth)目录和文件以开始对其进行操作。
# 在 *app* 模块中创建mod_auth模块
mkdir ~/LargeApp/app/mod_auth
完成这些操作后,文件夹结构应如下所示:
|-- run.py
步骤2:定义模块数据模型
nano ~/LargeApp/app/mod_auth/models.py
将如下内容敲入 models.py
# 从主应用程序模块导入数据库对象(db)
使用CTRL + X保存并退出,然后使用Y确认。
步骤3:定义模块表单
nano ~/LargeApp/app/mod_auth/forms.py
将如下内容敲入 forms.py
# 导入 Form 和 RecaptchaField (可选)
使用CTRL + X保存并退出,然后使用Y确认。
步骤4:定义应用程序控制器(视图)
nano ~/LargeApp/app/mod_auth/controllers.py
将如下内容敲入 controllers.py
# 导入flask依赖项
使用CTRL + X保存并退出,然后使用Y确认。
步骤5:在“app/init.py”中设置应用程序
nano ~/LargeApp/app/__init__.py
敲入如下内容:
# 导入Flask与模板渲染函数
使用CTRL + X保存并退出,然后使用Y确认。
步骤6:创建模板
nano ~/LargeApp/app/templates/auth/signin.html
敲入如下内容:
{% macro render_field(field, placeholder=None) %}
{% if field.errors %}
<div>
{% elif field.flags.error %}
<div>
{% else %}
<div>
{% endif %}
{% set css_class = 'form-control ' + kwargs.pop('class', '') %}
{{ field(class=css_class, placeholder=placeholder, **kwargs) }}
</div>
{% endmacro %}
<div>
<div>
<legend>Sign in</legend>
{% with errors = get_flashed_messages(category_filter=["error"]) %}
{% if errors %}
<div>
{% for error in errors %}
{{ error }}<br>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% if form.errors %}
<div>
{% for field, error in form.errors.items() %}
{% for e in error %}
{{ e }}<br>
{% endfor %}
{% endfor %}
</div>
{% endif %}
<form method="POST" action="." accept-charset="UTF-8" role="form">
{{ form.csrf_token }}
{{ render_field(form.email, placeholder="Your Email Address",
autofocus="") }}
{{ render_field(form.password, placeholder="Password") }}
<div>
<label>
<input type="checkbox" name="remember" value="1"> Remember Me
</label>
<a role="button" href="">Forgot your password?</a><span class="clearfix"></span>
</div>
<button type="submit" name="submit">Sign in</button>
</form>
</div>
</div>
使用CTRL + X保存并退出,然后使用Y确认。
注意:这个模板文件是一个非常简单且不完整的示例,仅出于演示目的而创建。强烈建议你阅读Jinja2文档并使用基本文件来构建网站的模板。
步骤7:使用模块
创建完第一个模块后,就该查看所有实际效果了。
使用run.py运行开发服务器:
cd ~/LargeApp
env/bin/python run.py
这将启动位于端口8080的开发(即测试)服务器。
通过如下URL来访问模块:
[your droplet
尽管你无法登录,但是已经可以通过输入一些示例性数据或测试其验证器来查看它的运行情况了。
翻译说明
文中代码中的一些库由于版本问题导致导入代码无法运行,我做了更改和说明。这应该是我翻译的第二篇技术文章,没有太多翻译经验,如有问题,欢迎批评指正!