1.入门程序
from flask import Flask
app = Flask(__name__)
app.run()
flask提供了自动重启服务的功能:调试模式
app.run(debug=True)
2.定义路由
@route(\'/user/<username>\')
@route(\'/post/<int:uid>\')
@route(\'/post/<float:price>\')
@route(\'/post/<path:path>\')
路由装饰器:
def route(self, rule, **options): """Like :meth:`Flask.route` but for a blueprint. The endpoint for the :func:`url_for` function is prefixed with the name of the blueprint. """ def decorator(f): endpoint = options.pop("endpoint", f.__name__) self.add_url_rule(rule, endpoint, f, **options) return f return decorator
from flask import Flask
app = Flask(__name__)
# 视图函数
@app.route("/hello/") -->/hello /hello/
def hello():
return "hello world"
app.run()
基于类的视图(即插视图)
另一种注册路由的方式:app.add_url_rule("/hello", view_func=hello)
@app.route和app.add_url_rule参数: rule, URL规则 view_func, 视图函数名称 defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={\'k\':\'v\'}为函数提供参数 endpoint=None, 名称,用于反向生成URL,即: url_for(\'名称\') methods=None, 允许的请求方式,如:["GET","POST"] strict_slashes=None, 对URL最后的 / 符号是否严格要求, 如: @app.route(\'/index\',strict_slashes=False), 访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可 @app.route(\'/index\',strict_slashes=True) 仅访问 http://www.xx.com/index redirect_to=None, 重定向到指定地址 如: @app.route(\'/index/<int:nid>\', redirect_to=\'/home/<nid>\') 或 def func(adapter, nid): return "/home/888" @app.route(\'/index/<int:nid>\', redirect_to=func) subdomain=None, 子域名访问 from flask import Flask, views, url_for app = Flask(import_name=__name__) app.config[\'SERVER_NAME\'] = \'wupeiqi.com:5000\' @app.route("/", subdomain="admin") def static_index(): """Flask supports static subdomains This is available at static.your-domain.tld""" return "static.your-domain.tld" @app.route("/dynamic", subdomain="<username>") def username_index(username): """Dynamic subdomains are also supported Try going to user1.your-domain.tld/dynamic""" return username + ".your-domain.tld" if __name__ == \'__main__\': app.run()
反向构建URL
<img src="{{ url_for(\'static\', filename=\'/js/jquery.js\') }}" />
参数一:endpoint
3.配置文件
# 导入配置文件 app.config.from_object(\'app.secure\') app.config.from_object(\'app.setting\') app.config[\'DEBUG\'] --配置文件的变量必须大写 在业务逻辑层使用配置文件: from flask import current_app current_app.config[\'KEY\']
4.返回结果
4.1 json 【API】
对于基本类型:
return flask.jsonify(data)
对于对象类型:
return json.dumps(obj, default=lambda o:o.__dict__)
4.2 context-type:text/plain 返回纯文本
from flask import make_response
# 默认 content-type:text/html
# 返回response对象
headers = {
\'content-type\':\'application/json\',
# \'content-type\':\'text/plain\',
\'location\':\'www.baidu.com\'
}
response = make_response("hello wolrdd", 200)
response.headers = headers
# return response
# return \'hello flask\', 200, headers
4.3 返回带cookie的页面
response = make_response(render_template(\'index.html\')) # response是flask.wrappers.Response类型 response.delete_cookie(\'key\') response.set_cookie(\'key\', \'value\') response.headers[\'X-Something\'] = \'A value\' return response
5.session
session[\'k\']=value
# session.pop()
6.将视图函数拆分多个文件中
7.request参数
7.1 url?q=xxx&page=xxx形式的参数,【get请求】
通过request对象获取请求参数:
from flask import request
request.args[\'q\'] 或 request.args.get(\'q\')
request.args是不可变字典, 转化成可变字典:a = request.args.to_dict()
7.2 form post
request.form接受post请求参数
7.3 URL方式接受参数
@app.route(\'/detail/<int:uid>\') def detail(uid): pass
8.WTFroms参数验证,验证层
安装WTForms:pipenv install wtforms
from wtforms import Form, StringField, IntegerField from wtforms.validators import Length, NumberRange, DataRequired class SearchForm(Form): # DataRequired要求参数不能为空格 q = StringField(validators=[DataRequired(message=\'关键字不能为空格\'), Length(min=1,max=30, message=\'关键字的长度应该在1-30\')]) page = IntegerField(validators=[NumberRange(min=1, max=20)], default=1)
自定义验证器:
业务需求:对邮箱进行验证,除了验证形式的合法性,还要验证数据库中是否存在
class RegisterForm(Form): email = StringField(validators=[DataRequired(), Length(8, 64), Email(message=\'邮箱格式不合法\')]) password = StringField(validators=[DataRequired(message=\'密码不能为空\'), Length(6,32)]) nickname = StringField(validators=[DataRequired(), Length(2, 10, message=\'昵称长度2-10\')]) # 这个函数由WTForm自动调用,field为email属性 def validate_email(self, field): if User.query.filter_by(email=field.data).first(): raise ValidationError(\'电子邮箱已经被注册\') # 如果不合法,抛出指定的异常
视图函数:
from flask import Flask, make_response, jsonify, request from app.forms.book import SearchForm from . import web # 参数 @web.route(\'/book/search\', methods=[\'GET\', \'POST\']) def search(): form = SearchForm(request.args) if form.validate(): print(\'验证通过\') q = form.q.data.strip() #去空格 page = form.page.data # 调用业务逻辑层 result = {\'q\': q, \'page\': page} return jsonify(result) else: print(\'验证失败\') return jsonify(form.errors)
9.数据库操作【ORM】 code first sqlalchemy ->flask_SQLAlchemy
安装flask_SQLAlchemy:pipenv install flask-sqlalchemy
安装数据库驱动:mysq->cymysql 或者pymysql
from sqlalchemy import Column, Integer, String, Float class Book(object): id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(50), nullable=False) author = Column(String(20), nullable=False) price = Column(Float, nullable=True, default=0) isbn = Column(String(15), nullable=False, unique=True) summery = Column(String(200), default=\'没有简介\')
10.AppContext, RequestContext, Flask, Request关系【LocalProxy】
12.模板渲染
render(html, data)
对于css、js文件,直接返回给客户端
13.静态文件【css,js,images..】和 模板文件【HTML】
Flask内部仍然使用路由、视图函数对静态文件进行返回。
静态文件的默认位置:__name__/static
模板文件的默认位置:__name__/templates
修改默认位置:
app = Flask(__name__, static_folder=\'view_model/static\', templates_folder=\' xxx \') # 相对路径
模板文件也可以放在蓝图下面:在蓝图的__init__文件,Blueprint(\'web\', templates_folder=\' xxx\')
14. 模板引擎:jinja2 【官网:http://jinja.pocoo.org/docs/2.10/】
14.1 基本设置
为了让IDE【pycharm】更友好点(定位模板页面的路径),将对应文件夹设置为模板文件夹:
设置模板引擎:
实例:
@web.route(\'/index\', methods=[\'GET\']) def index(): data = { \'name\':\'张三\', \'age\':20 } return render_template(\'index.html\', data=data)
对于字典和对象类型的data,可以使用点来访问,也可以使用索引
<body> <div> <p>姓名:{{data.name}}</p> <p>年龄:{{data.age}}</p> </div> </body>
字符串【raw】:默认字符串当做纯字符串
{% set str=\'<input type="text">\' %}
{{ str }}
如果需要HTML解析的字符串,在后台使用Markup(‘’)构造
宏定义:
{% macro xx(name, type=\'text\', value=\'\') %}
<input type="{{ type }}" name="{{ name }}" value="{{ value }}" />
{% endmacro %}
{{ xx(\'age\') }}
14.2 流程控制语句
所有的流程控制语句都要被包含在{% %}内。
(1)条件判断语句
比较运算符、and 、or都可以使用
{% if data.age < 20 %}
{{ data.name }}
{% elif data.age == 20 %}
<p>年龄为 20</p>
{% else %}
<p>年龄大于20</p>
{% endif %}
(2)循环语句
{% for i in range(5) %}
<h3>{{ i }}</h3>
{% endfor %}
14.3 使用模板继承
模板页:layout.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>鱼书</title> </head> <body> {% block head %} head {% endblock %} {% block content %}
content {% endblock %} {% block foot %} footer {% endblock %} </body> </html>
继承模板页:
{% extends \'layout.html\' %}
{% block content %}
{{ super() }}
<p>姓名:{{data.name}}</p>
<p>年龄:{{data.age}}</p>
{% if data.age < 20 %}
{{ data.name }}
{% elif data.age == 20 %}
<p>年龄为 20</p>
{% else %}
<p>年龄大于20</p>
{% endif %}
{% for i in range(5) %}
<h3>{{ i }}</h3>
{% endfor %}
{% endblock %}
14.4 过滤器【filter】
default:
{{ data.name | default(\'未名\',False) }} 如果不存在name属性,显示未名,【异常处理】
boolean=True => None,False, \'\', {}, [] -->default
str = False or \'hello\' ->hello
str = None or \'hello\' ->hello
str = \'\' or \'hello\' ->hello
length:
{{ data | length() }} 输出data的长度
16.消息闪现
@web.route(\'/index\', methods=[\'GET\']) def index(): data = { \'name\':\'张三\', \'age\':20 } flash(\'登录成功\', category=\'ok\') flash(\'成功进入系统\', category=\'error\') return render_template(\'index.html\', data=data)
使用消息:
使用set定义的变量,作用域为blocks的全局变量
{% set message = get_flashed_messages(category_filter=\'error\') %}
{{ message }}
19.密码加密 【werkzeug.security】
from werkzeug.security import generate_password_hash
20.redirect重定向
redirect(url_for(\'web.login\')) # 蓝图名.endpoint
21.cookie
response = make_response()
response.set_cookie(key, value, timeout)
flask提供了管理登录的插件:pipenv install flask_login 帮助文档
login_user(user) 并不是将用户的所有信息都保存到cookie下,而是只需要保存用户的唯一标识ID。因此,在User类中需要定义一个方法get_id(self): return self.id
或者让User继承UserMixin,该类提供了更多的登录相关的方法、属性。
访问权限控制:插件装饰器
user.py
@login_manager.user_loader def get_user(uid): return User.query.get(int(uid))
gift.py
@web.route(\'/my/gift\') @login_required def my_gift(): return \'my gift\'
@web.route(\'/login\', methods=[\'GET\', \'POST\']) def login(): form = LoginForm(request.form) if request.method == \'POST\' and form.validate(): user = User.query.filter_by(email=form.email.data).first() if user and user.check_password(form.password.data): # 使用登录管理器 管理登录 login_user(user, remember=True) next = request.args.get(\'next\') if not next or not next.startswith(\'/\'): next = url_for(\'web.index\') return redirect(next) else: flash(\'账号不存在或者密码错误\') return render_template(\'auth/login.html\', form=form)