Flask基础学习-路由和数据库篇

因为是工作期间学习,暂时不是跟着老师逐行敲代码,之前有过flask基础,现在只是记录老师讲课中的一些知识点。

了解flask的路由机制

我们是如何通过一个url定位到对应的视图函数呢?

image-20180802212409743

看上图描述了flask中的路由机制,包括了三个部分:url,endpoint,视图函数。

我们可以正向以键值对的方式由url找到视图函数,反向可以通过endpoint由视图函数找到url。

上一节中我们知道注册路由的两种方式:

1
2
3
@app.route('/hello', endpoint='')

app.add_url_rule('/hello', view_func=hello, endpoint='')

上面其实都是可以传endpoint的,具体什么作用,我们看下源码。

首先是装饰器route的源码

1
2
3
4
5
6
7
8
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator

我们看到如果传入了endpoint将会作为参数传入add_url_rule

接着看add_url_rule的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@setupmethod
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options['endpoint'] = endpoint

rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options
self.url_map.add(rule)

if view_func is not None:
old_func = self.view_functions.get(endpoint)
if old_func is not None and old_func != view_func:
raise AssertionError('View function mapping is overwriting an '
'existing endpoint function: %s' % endpoint)
self.view_functions[endpoint] = view_func

我们看到当我们没有指定endpoint的时候,flask会将视图函数view_func作为endpoint。

注意:如果我们使用的是蓝图注册,则是蓝图名字加视图函数名字作为endpoint。

首先会生成url到endpoint的映射

1
self.url_map.add(rule)

然后会生成endpoint到视图函数view_func的键值对字典关系

1
self.view_functions[endpoint] = view_func

这样就完成了路由的查找。

flask中的蓝图

我们看下蓝图的层级

image-20180802215955861

flask的实例化对象就像一个插座,上面可以插很多接口(插件),蓝图就像一个接口。蓝图也可以拥有自己的静态文件,视图函数,模板等。

__init__.py文件除了能够将文件变成包,也可以进行代码的初始化。

如何使用蓝图呢?

首先实例化一个蓝图对象:

1
2
3
from flask import Blueprint

web = Blueprint('web', __name__, template_folder='templates')

Blueprint的第一个参数是蓝图的名字,第二个参数是蓝图所在的模块。

实例化完了之后需要注册到flask的核心对象app上。

1
app.register_blueprint(web)

这样我们就完成了一个简单使用。

request对象

相比于response对象,request对象封装了客户端的请求信息。包括查询参数,POST请求参数,远程IP地址等。

request.args可以获得url请求参数,这是一个不可变字典,我们可以将其转为一个Python中的普通字典。

1
request.args.to_dict()

注意:request是一个代理模式的实现,如果我们想要使用request,所在的方法必须是http请求触发的(例如视图函数)。如果你在普通方法中使用了,该普通方法被http请求触发的方法调用,则是可以实现request的。其实根本就是判断是否在flask的上下文环境中,我们一般在视图函数中就已经在了上下文环境中。

使用WTForms进行数据验证

我们在进行表单提交的时候,数据验证是一大头,如果不使用wtforms将会出现一堆if…else。

WTForms文档:http://docs.jinkan.org/docs/flask/patterns/wtforms.html

我们看下文档中的使用:

1
2
3
4
5
6
7
8
9
10
11
from wtforms import Form, BooleanField, TextField, PasswordField, validators

class RegistrationForm(Form):
username = TextField('Username', [validators.Length(min=4, max=25)])
email = TextField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('New Password', [
validators.Required(),
validators.EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [validators.Required()])

在视图函数中的使用:

1
2
3
4
5
6
7
8
9
10
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm(request.form)
if request.method == 'POST' and form.validate():
user = User(form.username.data, form.email.data,
form.password.data)
db_session.add(user)
flash('Thanks for registering')
return redirect(url_for('login'))
return render_template('register.html', form=form)

一些知识点:

  1. 如果数据是以 POST 方式提交的,那么基于请求的 form 属性的值创建表单。反过来,如果是使用 GET 提交的,就从 args 属性创建。
  2. 验证表单数据,调用 validate() 方法。如果数据验证通过,此方法将会返回 True,否则返回 False 。
  3. 访问表单的单个值,使用 form..data 。
  4. 验证失败的错误信息存储在form.errors
使用Flask-SQLAlchemy进行数据库管理

flask-sqlalchemy文档:http://www.pythondoc.com/flask-sqlalchemy/index.html

如何使用呢?

  1. 实例化SQLAlchemy对象
1
2
3
4
from flask.ext.sqlalchemy import SQLAlchemy


db = SQLAlchemy()
  1. 注册到flask核心对象上
1
2
3
4
def create_app():
app = Flask(__name__)

db.init_app(app)

或者在创建对象的时候直接传入核心对象

1
2
3
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
  1. 在模型中引入使用
1
2
3
4
5
from app import db


class User_tag(db.Model):
__tablename__ = 'user_tag'
  1. 指明数据库连接

完成上面的操作之后还要指明连接的数据库,才能真正使用。我们需要在配置文件中进行配置链接

1
SQLALCHEMY_DATABASE_URI = 'mysql://username:password@server/db'

SQLAlchemy同样支持数据库集群配置,如果要指定数据库连接驱动需要在配置里面mysql后面加+驱动类型。驱动类型如cymysqlpymysql等。

  1. 创建数据表

最后一步将模型同步到数据库

1
2
db.init_app(app)
db.create_all(app=app)

上面的create_all方法如果不是指定app的话,会报:no application found. either work inside a view function or push 。这个报错我们下一节深入学习下

业务逻辑应该写在MVC的哪一层?

模型层。

知识就是财富
如果您觉得文章对您有帮助, 欢迎请我喝杯水!