官方文档: http://flask.pocoo.org/docs/0.11/
中文文档: http://docs.jinkan.org/docs/flask/
HTTP协议:
请求
- 请求行
- 请求头
- 请求体
响应
响应行
HTTP / 1.1 200 OK
响应状态:
- 200:响应成功
- 302:重定向
- 304:资源未更新
- 404:资源不存在
- 500:服务器内部错误
- 键值对:说明
Content-Type:文件类型 text/html image/jpeg application/json text/xml
- 响应体
1.定义正则:
1.导包
from werkzeug.routing import BaseConverter
2.创建正则类,重写__init__
方法,并调用父类方法
class XXXX(BaseConverter):
def __init__(self, url_map, *args): super(XXXX,self).__init__(url_map)
self.regex = args[0]
3.添加至app
# 创建Flask对象
app = Flask(__name__)
app.url_map.converters['re'] = XXXX
# 视图入口
if __name__ == "__main__":
app.run(debug=True) # 调试模式
2.传参
- 在@app.route(‘/<>’)路由中添加可变参数:
<id>
- 规定参数类型:
<int:id>
- 引用正则:
<re('[a-z]'):id>
3.返回JSON数据
- 导入json数据包
- 调用返回:
json.jumps(json-data)
4.状态码
def ret():
return 'data', 200
# 抛出异常,404代表异常类型
def abort_test();
abort(404)
return 'data' # 可以返回字符串,Flask自动封装为响应对象
自定义状态码视图
@app.errorhandler(500) # 注册状态码处理函数
def error_test(value):
return '服务器忙...'
5.上下文对象(request.response)
request
sesion
current_app
g
(response)
Flask 封装request和response为全局对象
request方法:
方法 | 解释 |
---|---|
args | 一个包含解析过的查询字符串( URL 中问号后的部分)内容的 MultiDict |
form | 一个包含解析过的从 POST 或 PUT 请求发送的表单对象的 MultiDict 。请注意上传的文件不会在这里,而是在 files 属性中 |
value | 一个包含 form 和 args 全部内容的 CombinedMultiDict |
cookies | 一个包含请求中传送的所有 cookie 内容的 dict |
headers | 进入请求的标头存为一个类似字典的对象 |
files | 一个包含 POST 和 PUT 请求中上传的文件的 MultiDict. 包含save()方法 |
method | 当前请求的 HTTP 方法 |
如下参考完整url信息 | http://www.example.com/myapplication/page.html?x=y |
path | /page.html |
script_root | /myapplication |
base_url | http://www.example.com/myapplication/page.html |
url | http://www.example.com/myapplication/page.html?x=y |
url_root | http://www.example.com/myapplication/ |
response方法:
方法 | 解释 |
---|---|
headers | Headers 对象用于设置响应的头信息 |
status | 用于设置响应状态描述 |
status_code | 整数,用于设置响应状态码 |
mimetype | 用于设置响应的MIME类型 |
set_cookie() | 设置cookie |
示例:
response = make_response('显示文字') # 创建response对象
response.set_cookie(key, value) # 设置cookie
request.headers.get('User-Agent') # 获取请求头中内容
session['key'] = value # 设置session
session.get('key') # 获取session
6.应用上下文current_app和变量g
current_app 可以获取当前app所在环境信息(ip,内存等)
current_app.name # 获取应用名称
current_app.test_value='value' # 利用应用上下文存取变量
g.name='abc' # 临时性全局变量
*手动创建应用上下文:应用上下文只存在于当前主线程中,额外创建的子线程中需要手动创建
with app.app_context():
other_code_for_you
7.Flask扩展包
- Flask-SQLalchemy:操作数据库;
- Flask-Migrate:管理迁移数据库;
- Flask-Mail:邮件;
- Flask-WTF:表单;
- Flask-Bable:提供国际化和本地化支持,翻译;
- Flask-Script:插入脚本;
- Flask-Login:认证用户状态;
- Flask-OpenID:认证;
- Flask-RESTful:开发REST API的工具;
- Flask-Bootstrap:集成前端Twitter Bootstrap框架;
- Flask-Moment:本地化日期和时间;
8.Flask_script扩展
from flask import Flask
from flask_script import Manager # 导入
app = Flask(__name__)
manager = Manager(app) # 注册
@app.route('/')
def index():
return '床前明月光'
if __name__ == "__main__":
manager.run() # 使用
9.Flask-Script插件
添加管理功能:
pip install Flask-Script # 安装
from flask_script import Manager
app = Flask(__name__)
...
manager = Manager(app)
...
manager.run()
python app.py runserver # 运行
测试的命令行环境(调试):
python app.py shell
... # 修改调试上下文(app.app_context()返回current_app)
... # app.test_request_ctx()
… 上下文对象存储于栈结构中:先进后出,后进先出
10.模板
模板语言
代码块:
{{ }}
逻辑代码:
{% %}
也可以使用过滤器{{ loop.index }} # 返回循环索引,从1开始
{{ loop.cycle('1', 'a', 'c') }} # 返回cycle中作为索引
禁止解析:
{% raw %} <script>js处理</script> {% raw %}
过滤器:
{{ variable | filter_name(*args) }} # *args在没有条件的情况下可以省略
示例:
{{ 111 | float }}
{{ 111.11 | int }}
{{ [python , flask] | join(',')}}
{{ '123' | length }}
{{ 3.1415 | round(2) }} # 四舍五入
{{ 4.22 | round(1, 'common') }} # 四舍五入
{{ 4.28 | round(1, 'floor') }} # 舍位
{{ 4.22 | round(1, 'ceil') }} # 进位
{{ {'key': 'value'} | tojson }} # json输出
{{ 'abcdefg' | truncate(3, True) }} # 截取,True代表包含空格
{{ False_args | default('Treu_args, True') }} # 变量为假时,替换为default值
{{ '%s is %d' | format('name',17) }} # 格式化输出
{{ ' hello world ' | trim }} # 去掉首尾空格
{{ '<em>hello</em>' | striptags }} # 渲染前去掉HTML标签
- title upper lower capitalize等
自定义过滤器
app.jinjia_env.filters['key'] = filter_function # 注册过滤器函数
模板渲染
模板文件放在项目根目录下templates目录下
render_template('index.html')
模板传参
render_template('index.html', name=name, pwd=pwd)
11.宏
实现HTML代码重用(类似于代码公共部分抽取,继承)
{% macro func(name,label,value='',type='text') %}
<input type="{{type}}" name="{{name}}"
value="{{value|escape}}" class="form-control">
{% endmacro %}
调用:
func(name, 'username') # 当前文件调用
封装为文件:
{% macro function() %}
<div class="form-group">
<input type="{{type}}" name="{{name}}"
value="{{value|escape}}" class="form-control">
</div>
{% endmacro %}
其他文件调用:
{% import 'macro.html' as func %}
{% func.function() %}
12.模板继承
调用父类模板内容
{% block content %}
{% super() %}
... // 自定义内容
{% endblock %}
13.Flask 特有变量和函数
url_for() # 获取视图函数对应的url
redirect(url_for('views_function')) # 重定向(发送两次请求,地址栏改变)
设置: app.config['aaa']='xxx' 获取: {{config.aaa}} # 作为配置文件信息使用
设置: session['aaa']='xxx' 获取: {{session.get('aaa')}}
flash('a')=b # 应用中设置
{%for message in get_flashed_messages()%}
{{message}} // 获取输入框提示信息等
{%endfor%}
14.Form
1.WTF–简化form生成以及验证过程
常用字段:
表单内容验证函数:
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField
from wtforms.validators import DataRequired,EqualTo
class Login(FlaskForm):
username = StringField(lable='用户名', validators=[DataRequired()])
password = PasswordField(label='密码', validators=[DataRequired(), EqualTo('ps2','err')])
submit = SubmitField('提交')
# u(原生字符)可以使用如下代码替代:
app.config['SECRET_KEY'] = 'abc' # 非对称加密公钥
@app.route('/register')
def register():
form = login() # 创建对象
return render_template('register.html', form=form)
<form method="post" action="">
{{ form.csrf_token() }}
{{ form.username.label }}
<p>{{ form.us }}</p>
{{ form.password.label }}
<p>{{ form.ps }}</p>
<p>{{ form.submit() }}</p>
{% for x in get_flashed_messages() %}
{{ x }}
{% endfor %}
</form>
@app.route('/',methods=['GET','POST'])
def index():
form = Login()
if form.validate_on_submit(): # 表单提交有效性验证
name = form.username.data # 两种获取方式
pswd = request.form['password']
return redirect(url_for("success"))
else:
if request.method=='POST':
flash(u'信息有误,请重新输入!')
print form.validate_on_submit()
return render_template('index.html',form=form)
2.原生
from flask import Flask
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST']) # 默认为GET请求(渲染页面),需要添加POST(提交表单)
def login():
if request.method == 'POST':
# 第二次请求使用POST
username = requst.forms['username'] # 表单中无action=''提交路径,默认返回当前页面
# 第一次访问,渲染表单页面
return render_template('login.html', method=request.method)
@app.route('/login_handle', methods=['POST']) # 一般提交至第二个视图处理,默认为GET请求,需要添加POST
def login_handle():
username = request.forms['username'] # 获取表单数据
return ...
if __name__ == '__main__':
app.run()
15.SQLALchemy
Flask中关系型扩展,用来操作数据库
1.配置:
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://user_name:password@127.0.0.1:3306/database_name'
2.常用字段类型:
字段约束类型:
- 主键约束:唯一且非空
- 唯一约束:可以为null,但非null不可重复
- 非空约束:not null
- 外键约束:区关联主键,或者null
3.常用列选项:
4.常用关系选项:
一对多
class Role(db.Model):
...
# 关键代码
us = db.relationship('User', backref='role', lazy='dynamic')
...
class User(db.Model):
...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
backref
为类User申明新属性的方法
lazy
决定了什么时候SQLALchemy从数据库中加载数据,如果设置为子查询方式subquer
,则会在加载完User对象后,就立即加载与其关联的对象,这样会让总查询数量减少,但如果返回的条目数量很多,就会比较慢,另外,也可以设置为动态方式dynamic
,这样关联对象会在被使用的时候再进行加载,并且在返回前进行过滤,如果返回的对象数很多,或者未来会变得很多,那最好采用这种方式
多对多
registrations = db.Table('registrations',
db.Column('student_id', db.Integer, db.ForeignKey('students.id')),
db.Column('course_id', db.Integer, db.ForeignKey('courses.id'))
)
class Course(db.Model):
...
class Student(db.Model):
...
classes = db.relationship('Course',secondary=registrations,
backref='student',
lazy='dynamic')"
registrations
为格外创建的关联表
5.创建表以及插入数据
db.create_all()
data1 = Student(name = '1')
db.session.add(data1) # 或者 db.session.add_all([data1, data2])
db.session.commit()
6.查询
常用SQLAlchemy查询过滤器
常用查询执行器
逻辑与:and_()
逻辑或:or_()
逻辑非:not_()
7.删除查询对象
stu1 = Student.query.first()
db.session.delete(stu1)
db.session.commit()
8.更新数据
stu1 = Student.query.first()
stu1.name = 'new_name'
db.session.commit()
16.数据库迁移flask-migrate
准备:
migrate = Manager(app, db)
manager = Manager(app)
manager.add_command('db', MiagrateCommand) # 注册至flask-script,方便在命令行管理
操作:
python app.py db init # 初始化 # db 为add_command()中设置的名称
python app.py db migrate -m'版本名' # 创建迁移文件,版本参数可以省略
python app.py db upgrade # 迁移
python app.py db history # 历史版本
python app.py db downgrade 版本号 # 回滚
传入shell对象字典,避免每次shell操作导入
def make_shell_context():
return dict(app=app, db=db,...)
manager.add_command('shell', Shell(make_context=make_shell_context))
17.发送邮件flask-mail
1.配置:(服务器,端口,安全套接字层/传输安全层协议,邮箱名,密码等)
app.config['MAIL_SERVER'] = 'smtp.126.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME']=
app.config['MAIL_PASSWORD']=
app.config['MY_MAIL_SENDER'] = #发送者
app.config['MY_MAIL_TO']= # 接收者
2.注册:
mail= Mail(app)
3.设置消息:
msg = Message(subject, sender='', recipientes=['to_1'], ...)
msg.body='' 或者 msg.html=''
4.发送:
mail.send(msg)
18.flask-bootstrap
bootstrap = Bootstrap(app)
19.flask-Moment(未完成)
moment = Moment(app)
moment.include_moment()
20.Blueprint
将项目文件模块化
1.创建蓝图对象
login = Blueprint('login', __name__,static_folder='', template_folder='')
# 同名文件,系统默认使用项目下默认的templates下文件,可以使用相对路径避免此问题
2.注册路由,指定静态文件夹,模板文件夹
@login.route('/')
def login_index():
return 'login_index'
@login.route('/handle)
def login_handle():
return 'login_handle'
3.在应用对象上注册蓝图
app.register_blueprint(login, url_prefix='/login')
static_url_path
:可以为当前蓝图静态文件目录指定一个别名
使用url_for
查询视图函数:url_for('login.login_index')