整理翻译自How To Structure Large Flask Applications
介绍 其实已经有许多关于如何组织架构 Python Web 应用的方法和约定。尽管现在有些框架本身承载了一些工具(脚手架)从而可以达到实现自动化和降低任务难度的效果,但是究根结底几乎所有的解决方案都是依赖于打包/模块化应用作为代码块从而达到分发到相关的文件和文件夹的目的。
最小的 web 应用开发框架 Flask 有着它特有的(工具)-blueprints。
在这篇数码海洋的文章里,我们将会了解到如何使用 Flask 的 blueprints 来创建一个应用目录和组织架构它从而使其变成可重用的组件。这些将会给你的维护和组件的开发带来巨大的好处和便捷。
学术表
Flask:最小的应用开发框架
关于我们在这篇文章的选择
准备Flask系统
准备操作系统
安装Python,pip以及virtualenv
组织架构应用的目录
创建应用目录
创建虚拟环境
创建应用文件
安装 Flask
使用模块和 Blueprints(组件)
模块基础
模块模板
创建应用(run.py,init.py 等等)
使用 nano 编辑 run.py
使用 nano 编辑 config.py
创建一个模块/组件
组织架构模型
定义模块数据类型
定义模块表单
定义应用控制器(views)
在 “app/init.py” 中建立应用
创建模板
实际操作中查看你的模型
Flask:最小的应用开发框架 Flask 迷你的框架但是丝毫不会影响重要事情的处理方式。相反, Flask 允许开发者使用他们渴望的并且熟悉的工具。出于这个目的,它由此产生了自己的扩展索引和大量已经存在并解决大多数事情的的工具从登陆到日志方方面面。
它不是一个严格的“常规”框架,部分依赖于配置文件,这些配置文件使得其在开始使用和保持事项时变得更容易。
我们在文章中的选择 通过我们前面浏览的内容了解到,Flask 的方式就是让我们使用那些用起来最舒服的工具。在我们的文章中,我们将会使用最常见的扩展和库。这些选择包括:
SQLAlchemy
WTForms
Flask-SQLAlchemy 在 Flask 中添加 SQLAlchemy 支持很快捷。这是一个很好的扩展。
1 2 3 4 Author: Armin Ronacher PyPI Page: Flask-SQLAlchemy Documentation: Read docs @ packages.python.org On Github: [mitsuhiko/flask-sqlalchemy](https://github.com/mitsuhiko/flask-sqlalchemy)
Flask-WTF Flask-WTF 提供简单的 WTForms 集成。集成包括可选择的 用来提供更好安全保障的 CSRF。这也是一个很好的扩展。
1 2 3 4 Author: Anthony Ford (created by Dan Jacob) PyPI Page: Flask-WTF Documentation: Read docs @ packages.python.org On Github: [ajford/flask-wtf](https://github.com/mitsuhiko/flask-wtf)
准备 Flask 系统 准备操作系统 使用如下命令安装必要的开发工具
1 2 3 aptitude update aptitude -y upgrade aptitude install -y build-essential python-dev python2.7-dev
安装python,pip以及virtualenv 参考 Flask入门——从无到有构建一个网站 (二)环境搭建
组织应用的目录 我们将使用典型的大型应用名称作为我们的应用的文件夹。在文件夹里,我们将会有一个虚拟环境与此同时还有应用的包以及一些其他的文件夹包括 用来运行 测试(开发)环境的 “run.py” 和 Flask 的配置文件 “config.py”
下面给出的作为样例的目录结构,该目录结构是高度可扩展的,它构建的目的是充分利用 Flask 和其他库提供的工具。不要被它吓着了,我们将会一步一步构建它直至完成。
目标样例结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ~/LargeApp |-- run.py |-- config.py |__ /env # Virtual Environment |__ /app # Our Application Module |-- __init__.py |-- /module_one |-- __init__.py |-- controllers.py |-- models.py |__ /templates |__ /module_one |-- hello.html |__ /static |__ .. |__ . |__ .. |__ .
创建应用文件夹 让我们开始创建我们需要的主要目录。 逐条去执行下述命令:
1 2 3 4 mkdir ~/LargeApp mkdir ~/LargeApp/app mkdir ~/LargeApp/app/templates mkdir ~/LargeApp/app/static
执行完成之后我们的当前目录
1 2 3 4 ~/LargeApp |__ /app # Our Application Module |__ /templates |__ /static
创建一个虚拟环境 使用一个虚拟环境能给你带来很多好处。对于你的每一个应用都强烈推荐使用一个新的虚拟环境。在你的应用中创建一个虚拟环境是一个很好的让你应用有序和干净的方法。
使用下列命令创建一个虚拟环境
1 2 cd ~/LargetApp virtualenv env
创建应用文件 在这步,我们将会在使用 modules 和 blueprints 之前创建我们基础应用文件。
运行下列文件创建基本应用文件:
1 2 3 touch ~/LargeApp/run.py touch ~/LargeApp/config.py touch ~/LargeApp/app/__init__.py
我们当前的结构:
1 2 3 4 5 6 7 8 ~/LargeApp |-- run.py |-- config.py |__ /env # Virtual Environment |__ /app # Our Application Module |-- __init__.py |__ /templates |__ /static
安装 Flask 和相关依赖库 目录什么都创建好之后,我们开始使用 pip 下载安装我们的Flask
使用下述命令将 Flask 安装到虚拟环境当中:
1 2 3 4 cd ~/LargeApp env/bin/pip install flask env/bin/pip install flask-sqlalchemy env/bin/pip install flask-wtf
使用 Modules 和 Blueprints(组件) 基础模块 在走到这一步的时候,我们已经将我们的应用结构创建好了并且也将所有的依赖下载完成了。
我们的目标是模块化可逻辑分组的所有相关模块。
举个简单的例子比如认证系统。将所有视图,控制器,模型和帮助器置于一个位置,以允许可重用性的方式进行设置,这使得这种结构化成为维护应用程序同时提高生产力的好方法。
目标案例模块(组件)结构(在/app里面):
1 2 3 4 5 6 7 8 9 # Our module example here is called *mod_auth* # You can name them as you like as long as conventions are followed /mod_auth |-- __init__.py |-- controllers.py |-- models.py |-- .. |-- .
模块模板 为了使得达到最大的模块化,我们将遵循上述规定创建 “templates” 文件夹,同时并保护一个与模块相同或相似的相关名称的新文件夹,以包含其模板文件。
目标样例模板目录结构(在 LargeApp 中):
1 2 3 4 5 6 7 8 /templates |-- 404.html |__ /auth |-- signin.html |-- signup.html |-- forgot.html |-- .. |-- .
创建应用 在本节中,我们将继续前面的步骤,并从我们的应用程序的实际编码开始,然后再转到创建第一个模块化组件(使用蓝图):mod_auth,其用来处理所有与身份验证相关的过程。
使用 nano 编辑 “run.py”
输入如下内容:
1 2 3 # Run a test server. from app import app app.run(host='0.0.0.0', port=8080, debug=True)
保存退出。
使用 nano 编辑 “config,py” 1 nano ~/LargeApp/config.py
输入如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # Statement for enabling the development environment DEBUG = True # Define the application directory import os BASE_DIR = os.path.abspath(os.path.dirname(__file__)) # Define the database - we are working with # SQLite for this example SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, 'app.db') DATABASE_CONNECT_OPTIONS = {} # Application threads. A common general assumption is # using 2 per available processor cores - to handle # incoming requests using one and performing background # operations using the other. THREADS_PER_PAGE = 2 # Enable protection agains *Cross-site Request Forgery (CSRF)* CSRF_ENABLED = True # Use a secure, unique and absolutely secret key for # signing the data. CSRF_SESSION_KEY = "secret" # Secret key for signing cookies SECRET_KEY = "secret"
保存退出。
创建模块/组件 本节是定义本文核心的第一个主要步骤。 在这里,我们将看到如何使用Flask的蓝图来创建一个模块(即组件)。
第一步 结构化模块 正如我们已经开始做的,让我们创建我们的第一个模块(mod_auth)目录和文件来开始工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # Create the module directory inside the *app* module mkdir ~/LargeApp/app/mod_auth # Create where module's templates will reside mkdir ~/LargeApp/app/templates/auth # Create __init__.py to set the directory as a Python module touch ~/LargeApp/app/mod_auth/__init__.py # Create module' s controllers and models etc.touch ~/LargeApp/app/mod_auth/controllers.py touch ~/LargeApp/app/mod_auth/models.py touch ~/LargeApp/app/mod_auth/forms.py # Create module's templates touch ~/LargeApp/app/templates/auth/signin.html # Create a HTTP 404 Error page touch ~/LargeApp/app/templates/404.html
在上述操作过程之后,我们的目录结构类似这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ~/LargeApp |-- run.py |-- config.py |__ /env # Virtual Environment |__ /app # Our Application Module |-- __init__.py |-- /mod_auth # Our first module, mod_auth |-- __init__.py |-- controllers.py |-- models.py |-- forms.py |__ /templates |-- 404.html |__ /auth |-- signin.html |__ /static
第二步 定义模块数据模型 1 nano ~/LargeApp/app/mod_auth/models.py
输入下述内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 from app import dbclass Base (db.Model ): __abstract__ = True id = db.Column(db.Integer, primary_key=True ) date_created = db.Column(db.DateTime, default=db.func.current_timestamp()) date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp()) class User (Base ): __tablename__ = 'auth_user' name = db.Column(db.String(128 ), nullable=False ) email = db.Column(db.String(128 ), nullable=False , unique=True ) password = db.Column(db.String(192 ), nullable=False ) role = db.Column(db.SmallInteger, nullable=False ) status = db.Column(db.SmallInteger, nullable=False ) def __init__ (self, name, email, password ): self.name = name self.email = email self.password = password def __repr__ (self ): return '<User %r>' % (self.name)
保存并退出
第三步 定义模块表单 1 nano ~/LargeApp/app/mod_auth/forms.py
输入下述内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from flask.ext.wtf import Form from wtforms import TextField, PasswordField from wtforms.validators import Required, Email, EqualToclass LoginForm (Form ): email = TextField('Email Address' , [Email(), Required(message='Forgot your email address?' )]) password = PasswordField('Password' , [ Required(message='Must provide a password. ;-)' )])
保存并退出
第四步 定义应用控制器(视图) 1 nano ~/LargeApp/app/mod_auth/controllers.py
输入下述内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 from flask import Blueprint, request, render_template, \ flash, g, session, redirect, url_for from werkzeug import check_password_hash, generate_password_hashfrom app import dbfrom app.mod_auth.forms import LoginFormfrom app.mod_auth.models import Usermod_auth = Blueprint('auth' , __name__, url_prefix='/auth' ) @mod_auth.route('/signin/' , methods=['GET' , 'POST' ] ) def signin (): form = LoginForm(request.form) if form.validate_on_submit(): user = User.query.filter_by(email=form.email.data).first() if user and check_password_hash(user.password, form.password.data): session['user_id' ] = user.id flash('Welcome %s' % user.name) return redirect(url_for('auth.home' )) flash('Wrong email or password' , 'error-message' ) return render_template("auth/signin.html" , form=form)
保存并退出
第五步 在应用中创建 “app/init.py” 1 nano ~/LargeApp/app/__init__.py
输入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 from flask import Flask, render_templatefrom flask.ext.sqlalchemy import SQLAlchemyapp = Flask(__name__) app.config.from_object('config' ) db = SQLAlchemy(app) @app.errorhandler(404 ) def not_found (error ): return render_template('404.html' ), 404 from app.mod_auth.controllers import mod_auth as auth_moduleapp.register_blueprint(auth_module) db.create_all()
保存并退出
第六步 创建模板 1 nano ~/LargeApp/app/templates/auth/signin.html
输入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 {% 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 >
保存并退出
第七步 从网页浏览你定义的模块 模块创建成功了,接下来就是查看我们定义的模板了
运行 run.py
文件启动开发环境服务器
1 2 cd ~/LargeApp env/bin/python run.py
上述命令将会初始化一个开发环境服务器,端口为 8080. 通过 URL 去访问我们的模块
1 http://[your droplet's IP]/auth/signin
虽然您无法登录,但您可以通过输入一些示例数据或通过测试其验证器来查看它。