Flask 基础
What's flask
Flask是一个基于Python并且依赖于Jinja2模板引擎和Werkzeug WSGI 服务的一个微型框架。
“微”不代表它不强大,只是框架的开发者希望将更大的空间留给框架的使用者和站点的开发者。Flask的目标是保持核心简单而又可扩展。
Flask并不会像Django那样事无巨细的为你考虑的清清楚楚,帮你作出很多决定,Flask更多的时候力求给使用者最大的自由度。
与Django一样 它也是一个遵循了MTV(MVC)设计模式的框架。Models负责建模,Templates负责展示模版的处理,Views处理与用户交互的内容,主要是请求和响应。
值得说明的是因为flask的轻量化,使得构建Flask项目对初学者而言,尤其是初步接触web框架的人来说 要比Django那样的重量级框架友好很多。
Flask —— 路由 route
1 what's route?
客户端将请求发送给web服务器,web服务器再将请求发送给flask程序实例,程序实例需要知道每个url请求要运行哪些代码(视图函数),所以需要建立一个 url 到 视图函数的映射,处理url和函数之间的关系的过程或模式,就是路由。
在Flask中,路由是通过 @app.route 装饰器来表示的参数为 路径 和 请求方法
2 路由的各种形式
路由的基本表示
@app.route('/')
def index():
reutrn "xxx"
@app.route('/login')
def login():
return 'xxx'
带参数的路由
当URL这样写 http://localhost:5000/index/monkey/999
@app.route('/index/<string:name>/<int:page>')
def index(name:str, page:int) -> str:
return "name:{} page:{}".format(name, page)
代码会将后面的 monkey 传给
@<装饰器传入 url 里的变量名 必须和 视图函数 index的型参名保持一致>
指定参数类型的路由
如2中代码所示,url中的参数前都加上了参数类型,虽然这不是强制的,但是为了让代码像预期的那样工作,有必要限制传入参数的形式。在url中添加的类型会被flask的类型转化器处理成为我们预期的样子,保证参数类型的一致对代码而言很有必要。这与Django 2.X
版本的URLconf
极为相似。
int:page : 表示age参数时一个整型的数值而并非默认的字符串
int:类型转换器
Flask 中所支持的类型转换器
string: 缺省为字符串型,但不能有/(斜杠)
int: 整型
float: 浮点型
path: 字符串型,可以有 / (斜杠)
uuid: 接受UUID字符串
3 多 URL 的路由匹配
允许在一个视图处理函数中设置多个url路由规则,像下面这样子:
@app.route('/')
@app.route('/index')
def index():
reutrn "string..."
“/ ”和“/index”都将匹配到index处理函数。
4 路由中设置 HTTP 请求方法
Flask路由规则也允许设置对应的请求方法,只有将匹配上请求方法的路径交给视图处理函数去执行。像下面这样,在route装饰器中传入 method参数 list 型 来限制HTTP请求的方法,缺省 为["GET"]
@app.route('/home', methods=['GET','POST'])
def home():
return "string ..."
5 URL的反向解析
-
正向解析:程序自动解析,根据@app.route()中的访问路径来匹配处理函数
-
反向解析:通过视图处理函数的名称自动生成视图处理函数的访问路径
-
url_for('home' ) --> /home 同样的 它依然支持带参数的解析 像这样:
url_for('index',name='monkey', page=999) : # 结果 :/show/monkey/999
- 像Django那样它同样支持从静态文件反向解析文件URL
<img src="{{ url_for( 'static', filename='img/test.png') }}" alt="Error" title="test">
- 需要注意的是 即使静态文件配置成了别的名字 如 /src 等 在这里 还是需要写 static 而不能是 src
Flask —— 模版 Templates
what's templates?
模板是一个包含响应文本的文件(通常是html文件),该文件中允许包含"占位变量"来表示动态的内容,其具体值在请求中才能知道。"占位变量"最终会被真实的值所替换。模板最终也会被解析成响应的字符串,这一过程称为"渲染"。Flask使用的模版引擎为 jinja2。Django使用的是自己的模版。但是语法基本一致。
模板的设置
默认情况下,Flask 会在程序文件夹中的 templates 子文件夹中寻找模板文件,但是需要手动创建 templates 文件夹(但是这不是必须的),可以通过配置来修改目录名。
# 在实例化时传入参数:teplate_folder
app = Flask(__name__, template_folder='tmplt') # 模版文件 foldername default:templates
渲染模板
在 视图函数中 ,通过return render_template() 将模板渲染成字符串再响应给客户端,
render_template('xxx.html',arg1=value1,arg2=value2)
参数1 : xxx.html ,要渲染给客户端的html模板文件
参数2 ~ n :要传递给模板动态显示的变量占位符,如果没有动态的变量占位符,则可以省略
返回值:字符串
模版语法
变量
变量时一种特殊的占位符,告诉模板引擎该位置的值是从渲染模板时的数据中来获取的
在视图中
@app.route('/')
def index():
return render_template('xxx.html',name='sf.zh',age=18)
# name 和 age 就是要传递到 xxx.html 中的变量
在模板中
{{变量名}}
常见过滤器
过滤器是允许在变量输出显示之前改变变量的值
语法
{{变量|过滤器}}
# 常见的过滤器
capitalize # 首字符变大写,其他字符变小写
lower # 把值转换成小写
upper # 把值转换成大写
title # 把值中的每个单词的首字符变大写
trim # 把值两端的空格去掉
控制结构
if结构
{% if 条件 %}
满足条件要执行的代码
{% else %}
不满足条件要执行的代码
{% endif %}
for结构
{% for 变量 in 元组|列表|字典 %}
语句
{% endfor %}
宏
使用 {% macro %} 标签声明宏
<!-- 定义 -->
{% mscro deal(str) %}
<h1>{{str}}</h1>
{% endmacro %}
<!-- 调用 -->
{{deal(uname)}}
宏被允许在单独的模板文件中声明定义,像这样:
1 创建 macro.html
{% mscro deal1(str) %}
<h1>{{str}}</h1>
{% endmacro %}
{% mscro deal2(str) %}
<li>{{str}}</li>
{% endmacro %}
2 在使用的网页中导入 macro.html
{% import 'macro.html' as macros %}
{{ macros.deal1(uname) }}
{{ macros.deal2(uname) }}
模板的包含
在多处重复使用的模板代码可以放在单独的文件中,可以被其他的模板所包含(引用)通常我们会引用一些 navbar 等的布局。也可以将它在继承中实现,根据需要进行即可。
{% include 'xxx.html' %}
模版的继承
模板的继承类似于类的继承,如果在几个模版文件中出现大量重复的代码或结构,那么可以将结构相似或者代码相同部分抽象出来,作为父亲模版,子模版只需要继承父模版,然后重写不一样的部分就好了。可以大大降低代码量,提升代码的可读性和条理性。
使用方法
1 通过定义 代码块 来确定父模版中哪些代码是需要被重写的
{% block block %}
{% endblock %}
例如:
{% block title %}
{% endblock %}
<!-- 定义允许在子模板中被修改的内容,在父模板中正常显示,没有任何影响,在子模板中可以被重写。-->
2 子模板中
使用 {% extends '父模板名称' %} 来完成继承
使用 {% block 块名 %} 来重写父模板中的同名内容
{% block 块名 %}
覆盖掉父模板中的内容
{% endblock %}
3 子模版中 允许通过 {{super()}} 来调用父模板中的内容
静态文件
在Flask中不能与服务器动态交互的文件都是静态文件如:css,js,图片,音视频,.... .... 所有静态文件都保存在项目文件夹中的 static 文件夹中在访问静态文件的时候需要通过 /static/资源路径 进行访问(如templates一样这也不是必须遵循的)
app = Flask(__name__, template_folder='tmplt', static_folder='srcfile', static_url_path='/srcfile')
template_folder='tmplt', # 模版文件 default:templates
static_folder='srcfile', # 静态文件的目录名称 default:static
static_url_path='/srcfile', # 静态文件 路由的访问路径 / 表示从根目录开始
在静态文件中 允许这样进行反向解析URL:
url_for('static',filename='<file_path>')
<img src="{{url_for('static',filename='images/b04.jpg')}}">
flask —— 请求和响应 request & response
请求
请求对象 request
from flask import request
属性
request.method # 方法
request.args # 参数
request.form # 表单
request.cookies # cookies
request.headers # 请求头
request.headers.get('referer')
使用超链接发送get请求,拼地址栏参数
<a href="/request?name=zsf&age=85">xxx</a>
获取get请求数据
name=request.args.get('name')
age =request.args.get('age')
location发送请求
使用js中的location对象,发送get请求并拼接参数
<script>
$btn.click(function(){
location.href='xxxxx?arg1=value1&arg2=value2'
});
</script>
获取 post 请求数据
request.form.get('xxx')
request.form.getlist('name_list')
响应对象
除了可以响应字符串和模板之外,还可以是响应对象或重定向
响应对象 make_response
from flask import make_response
resp = make_response('xxxx')
return resp
resp = make_response(render_template('xx.html',params=locals()))
return resp
重定向
由服务器通知浏览器向新的地址发送一个请求
from flask import redirect
resp = redirect('重定向地址')
return resp
flask —— 文件 files
文件上传
和一般的web 文件上传流程一样,使用form 或 ajax 提交数据到服务器,然后存储。
前端页面
form中的method的值必须为 post
form中的enctype的值必须为 multipart/form-data
Ajax
提交数据注意声明资源的类型
当上传的文件过大时,(http协议不支持)需要使用单独的上传工具。
服务器端
使用 request.files 接收上传的文件
f = request.files['文件选择框名称']
f.save('static/'+f.filename)
flask —— 对象关系映射 ORM
模型 - Models
模型,是根据数据库中表的结构来创建出来的class。每一张表到编程语言中就是一个class,表中的每一个列,到编程语言中就是class中的一个属性。
同Django
一样,flask
也拥有ORM 但是flask需要你自己来配置,而Django 集成的非常完备。只是唯一的区别,虽然flask没有专用的ORM但是这使它显得更为灵活~。
ORM的三大特征
1.数据表(table) 到 编程类(class) 的映射
数据库中的每一张表 对应 到编程语言中,都有一个类,在ORM中允许将数据表 自动 生成一个类,也允许将类 自动 生成一张表。
2.数据类型的映射
将数据库表中的字段以及数据类型 对应到 编程语言中类的属性。在ORM中允许将表中的字段和数据类型自动映射到编程语言中也允许将类中的属性和类型也映射到数据库表中。
3.关系映射
将数据库中表之间的关系 对应 到编程语言中类之间的关系
定义模型
配置
1.安装 SQLAlchemy
pip3 install sqlalchemy
pip3 install flask-sqlalchemy
2.创建数据库
create database flask default charset utf8 collate utf8_general_ci;
3.配置数据库
from flask import Flask
#将SQLAlchemy导入进来
from flask_sqlalchmey import SQLAlchemy
app = Flask(__name__)
#app.config['SQLALCHEMY_DATABASE_URI']='mysql://username:pwd@host:port/dbname'
app.config['SQLALCHEMY_DATABASE_URI']='mysql://root:123456@localhost:3306/flask'
#创建SQLAlchemy的实例
db = SQLAlchemy(app)
#db是SQLAlchemy的实例,表示程序正在使用的数据库,同时也获得了SQLAlchemy中的所有功能
if __name__ == "__main__":
app.run(debug=True)
自定义错误页面
404 的错误处理
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'),404
500的错误处理
@app.errorhandler(500)
def internal_server_error(e):
return render_template('500.html'),500