前言
Flask也被称为 “microframework” ,因为它使用简单的核心,用 extension 增加其他功能。Flask没有默认使用的数据库、窗体验证工具。
一、安装
我们推荐使用最新版本的 Python 3 。 Flask 支持 Python 3.4 及更高版本的 Python 3 、 Python 2.7 和 PyPy 。
1、安装python
安装Python3.7,下载windows安装包,一路next安装到C:python37。
2、创建环境
这里我说下python是如何安类库的,因安装类库比较方便的是直接在线安装,因官方安装源被国内墙了,且因地域的问题,经常出现timeout,这里面我们来配置国内的源来进行快速进行在线安装python的类库。
设置WORKON_HOME环境变量 :E:virtualenv
执行虚拟环境搭建
mkvirtualenv --python=C:python37python.exe py37
查看安装的所有虚拟环境:workon
进入虚拟环境:workon py37
退出虚拟环境:deactivate
接下来我们用独立环境py37 安装flask
workon py37
pip install Flask
如果想要在正式发行之前使用最新的 Flask 开发版本,可以使用如下命令从主分支 安装或者更新代码:
pip install -U https://github.com/pallets/flask/archive/master.tar.gz
二、HelloWorld
HelloWorld
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
首先我们导入了 Flask 类。 该类的实例将会成为我们的 WSGI 应用。
接着我们创建一个该类的实例。第一个参数是应用模块或者包的名称。如果你使用 一个单一模块(就像本例),那么应当使用 __name__ ,因为名称会根据这个 模块是按应用方式使用还是作为一个模块导入而发生变化(可能是 ‘__main__’ , 也可能是实际导入的名称)。这个参数是必需的,这样 Flask 才能知道在哪里可以 找到模板和静态文件等东西。更多内容详见 Flask 文档。然后我们使用 route() 装饰器来告诉 Flask 触发函数的 URL 。
函数名称被用于生成相关联的 URL 。函数最后返回需要在用户浏览器中显示的信息。
把它保存为 hello.py 或其他类似名称。请不要使用 flask.py 作为应用名称,这会与 Flask 本身发生冲突。
可以使用 flask 命令或者 python 的 -m 开关来运行这个应用。在 运行应用之前,需要在终端里导出 FLASK_APP 环境变量:
$ export FLASK_APP=hello.py
$ flask run
开启Debug模式
app.run(debug=1) 开启调试模式,代码修改,保存之后服务器自动重启。
三、路由
现代 web 应用都使用有意义的 URL ,这样有助于用户记忆,网页会更得到用户的青睐, 提高回头率。
使用 route() 装饰器来把函数绑定到 URL:
@app.route('/who')
def hello():
return 'ztloo'
url 变量操作
<username> 尖括号里面的值=函数里面的 username = 返回值 %右面的 username ,这样url里面的尖括号里面的变量就可以传递给函数,再由函数传递给返回值。
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
路由转换器:指定参数类型,就是只要在尖括号内指定类型,post后面的参数必须是哪个类型,如果是其他类型就会报错。
@app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post %d' % post_id
如果上述变量约束规则不够用,可以自定义正则转换器,下面实现custer 后面的参数必须是三个a到z的小写字母。
自定义转换器
class Regex_url(BaseConverter):
def __init__(self, url_map, *args):
super(Regex_url, self).__init__(url_map)
self.regex = args[0]
# 将自定义转换器类添加到转换器字典中
app.url_map.converters['re'] = Regex_url
@app.route('/custer/<re("[a-z]{3}"):id>')
def hello_itheima(id):
return 'hello %s' % id
唯一的 URL / 重定向行为
以下两条规则的不同之处在于是否使用尾部的斜杠。:
@app.route('/projects/')
def projects():
return 'The project page'
@app.route('/about')
def about():
return 'The about page'
projects 的 URL 是中规中举的,尾部有一个斜杠,看起来就如同一个文件夹。 访问一个没有斜杠结尾的 URL 时 Flask 会自动进行重定向,帮你在尾部加上一个斜杠。
about 的 URL 没有尾部斜杠,因此其行为表现与一个文件类似。如果访问这个 URL 时添加了尾部斜杠就会得到一个 404 错误。这样可以保持 URL 唯一,并帮助 搜索引擎避免重复索引同一页面。
例如,这里我们使用 test_request_context() 方法来尝试使用 url_for() 。 test_request_context() 告诉 Flask 正在处理一个请求,而实际上也许我们正处在交互 Python shell 之中, 并没有真正的请求。参见 本地环境 。
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def index():
return 'index'
@app.route('/login')
def login():
return 'login'
@app.route('/user/<username>')
def profile(username):
return '{}'s profile'.format(username)
with app.test_request_context():
print(url_for('index'))
print(url_for('login'))
print(url_for('login', next='/'))
print(url_for('profile', username='John Doe'))
/
/login
/login?next=/
/user/John%20Doe
四、HTTP方法、渲染模板、静态文件
Web 应用使用不同的 HTTP 方法处理 URL 。当你使用 Flask 时,应当熟悉 HTTP 方法。 缺省情况下,一个路由只回应 GET 请求。 可以使用 route() 装饰器的 methods 参数来处理不同的 HTTP 方法:
如果当前使用了 GET 方法, Flask 会自动添加 HEAD 方法支持,并且同时还会 按照 HTTP RFC 来处理 HEAD 请求。同样, OPTIONS 也会自动实现。
登陆demo
@app.route("/login",methods = ['GET', 'POST'])
def login():
if request.method == "POST":
username = request.form.get('username')
password = request.form.get('password')
if username=="zhangsan" and password=="123":
return "<h1>welcome, %s !</h1>" %username
else:
return "<h1>login Failure !</h1>"
else:
return login_index()
@app.route("/show_login")
def login_index():
return render_template("login_index.html")
login_index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
<html>
<head>
<title>login</title>
</head>
<body>
<form action="/login" method="post">
username: <input type="text" name="username">
password: <input type="password" name="password">
<input type="submit" id="submit">
</form>
</body>
</html>
渲染模板详解
在 Python 内部生成 HTML 不好玩,且相当笨拙。因为你必须自己负责 HTML 转义, 以确保应用的安全。因此, Flask 自动为你配置 Jinja2 模板引擎。
官方demo
@app.route('/rt/')
@app.route('/rt/<name>')
def rtDemo(name=None):
return render_template('rt.html', name=name)
<!doctype html>
<title>Hello from Flask</title>
{% if name %}
<h1>Hello {{ name }}!</h1>
{% else %}
<h1>Hello, World!</h1>
{% endif %}
博客demo:
渲染模板:
1、静态页面模板放在templates文件夹中
2、需要导入render_template
3、视图函数中使用render_template函数渲染模板本例中使用的是return render_template('index.html', **context)
4、传多个参数的时候可以使用字典的形式如本例中的context={}
5、html代码中参数使用{{}}进行引用 本例中是
<p>用户名:{{ username }}</p>
<p>年龄:{{ age }}</p>
6、传参数类,字典 请看本例中的person类以及context中的wwwurl字典
@app.route('/persioninfo')
def persion():
class Person(object):
Email = '1071235258@qq.com';
time = time.time();
dell=Person()
context={
'username':"ztloo",
'age': "17",
'gender': "男",
'flag': "IT",
'hero': "一哥",
'person':dell,
'wwwurl':{
'baidu':'www.baidu.com',
'google':'www.google.com'
}
}
return render_template('persion.html', **context)
persion.html
<!DOCTYPE html>
<html lang="utf-8">
<head>
<meta charset="UTF-8">
<title>falsk勾搭html</title>
</head>
<body>
这是一个简单的页面,falsk勾搭html
<p style="color:#FF00FF">用户名:{{ username }}</p>
<p>年龄:{{ age }}</p>
<p style="color:#7B68EE">性别:{{ gender }}</p>
<p>等级:{{ flag }}</p>
<p style="color:#FF00FF">英雄:{{ hero }}</p>
<hr>
<!--引用类中的参数-->
<p style="color:#7B68EE"> 申请邮箱:{{person.Email}}</p>
<p style="color:#FF00FF">申请时间:{{person.time }}</p>
<hr>
<!--引用wwwurl字典中的参数,有两种形式-->
<p style="color:#7B68EE">百度:{{wwwurl.baidu}}</p>
<p style="color:#FF00FF">谷歌:{{wwwurl['google'] }}</p>
</body>
</html>
操作请求数据
对于 web 应用来说对客户端向服务器发送的数据作出响应很重要。在 Flask 中由全局 对象 request 来提供请求信息。如果你有一些 Python 基础,那么 可能 会奇怪:既然这个对象是全局的,怎么还能保持线程安全?答案是本地环境:
flask在接受到客服端发来的请求后,会将其中的请求参数根据数据类型的区别分别存储在request对象的属性当中,调用这些属性就可以获得相应的请求参数
属性
|
说明
|
类型
|
environ
|
底层的WSGI环境。
|
|
以下6种URL的资源目录属性
|
|
|
path
|
u'/π/page.html'
|
|
full_path
|
u'/π/page.html?x=y'
|
|
script_root
|
u'/myapplication'
|
|
url
|
||
|
||
|
||
accept_charsets
|
||
accept_encodings
|
此客户接受的编码列表。HTTP术语中的编码是压缩编码,例如gzip。对于charsets看看 accept_charset
|
|
accept_languages
|
||
accept_mimetypes
|
||
access_route
|
如果存在转发的头,则这是从客户端ip到最后一个代理服务器的所有IP地址的列表。
|
|
classmethod application(f )
|
装饰一个函数作为响应者,接受请求作为第一个参数。这与responder()装饰器类似,但函数作为第一个参数传递请求对象,请求对象将自动关闭:
|
参数:
f - WSGI可调用以进行装饰
返回:
一个新的WSGI可调用
|
authorization
|
解析形式的Authorization对象
|
|
blueprint
|
当前蓝图的名称
|
|
cache_control
|
RequestCacheControl用于输入缓存控制标头的对象
|
|
close()
|
关闭此请求对象的关联资源。这将显式关闭所有文件句柄。您还可以在with语句中使用请求对象,该语句将自动关闭它。
|
|
content_encoding
|
Content-Encoding实体标题字段用作媒体类型的修饰符
|
|
content_length
|
Content-Length实体头字段以字节为单位指示实体主体的大小,或者在HEAD方法的情况下,指示在请求为GET时已发送的实体主体的大小。
|
|
content_md5
|
RFC 1864中定义的Content-MD5实体头字段是实体主体的MD5摘要,用于提供实体主体的端到端消息完整性检查(MIC)。(注意:MIC适用于检测传输中实体的意外修改,但不能抵御恶意攻击。
|
|
content_type
|
Content-Type entity-header字段指示发送给接收者的实体主体的媒体类型,或者在HEAD方法的情况下,指示在请求是GET时已经发送的媒体类型。
|
|
cookies
|
||
data
|
包含传入的请求数据作为字符串,以防它带有mimetype Werkzeug无法处理
|
|
date
|
Date general-header字段表示发起消息的日期和时间,与RFC 822中的orig-date具有相同的语义
|
|
dict_storage_class
|
||
endpoint
|
||
files
|
||
form
|
表单参数。默认情况下 ImmutableMultiDict ,从此函数返回。可以通过设置parameter_storage_class为其他类型来更改此设置 。如果表单数据的顺序很重要,则可能需要这样做。
|
|
form_data_parser_class
classmethod from_values(* args,** kwargs )
|
根据提供的值创建新的请求对象。如果给出了环境,则从那里填充缺失值。当您需要模拟来自URL的请求时,此方法对小脚本很有用。不要使用此方法进行单元测试,有一个功能齐全的客户端对象(Client),允许创建多部分请求,支持cookie等。
|
返回:请求对象
|
get_data(cache = True,as_text = False,parse_form_data = False )
|
这会将来自客户端的缓冲传入数据读入一个字节串。默认情况下,这是缓存的,但可以通过将缓存设置为False来更改该行为。
|
如果表单数据已经被解析,
则此方法不会返回任何内容。 如果as_text设置为True,则返回值将是解码的unicode字符串
|
get_json(force = False,silent = False,cache = True )
|
解析并将数据作为JSON返回
参数:
|
|
headers
|
||
host
|
只有主机包括端口(如果有)
|
|
host_url
|
只是作为IRI计划的主机。另见:trusted_hosts。
|
|
if_match
|
包含If-Match标头中所有etags的对象。
|
|
if_modified_since
|
已解析的If-Modified-Since标头为datetime对象。
|
|
if_none_match
|
包含If-None-Match标头中所有etags的对象。
|
|
if_range
|
解析的If-Range标头。
|
|
if_unmodified_since
|
已解析的If-Unmodified-Since标头为datetime对象
|
|
is_json
|
检查mimetype是否指示JSON数据, application / json或application / * + json。
|
|
is_multiprocess
|
boolean 如果应用程序由生成多个进程的WSGI服务器提供,则为True。
|
|
is_multithread¶
|
boolean 如果应用程序由多线程WSGI服务器提供,则为True
|
|
is_run_once
|
boolean 如果应用程序在进程生命周期中只执行一次,则为True。例如,CGI就是这种情况,但不保证执行只发生一次。
|
|
is_secure
|
如果请求是安全的,则为True。
|
|
is_xhr
|
如果请求是通过JavaScript XMLHttpRequest触发的,则为True。这仅适用于支持X-Requested-With 标头的库并将其设置为“XMLHttpRequest”。这样做的库是原型,jQuery和Mochikit,可能还有更多。
|
|
json
|
||
list_storage_class
|
||
make_form_data_parser()
|
||
max_content_length
|
MAX_CONTENT_LENGTH配置密钥的只读视图
|
|
max_forwards
|
Max-Forwards请求标头字段提供了一种TRACE和OPTIONS方法的机制,用于限制可以将请求转发到下一个入站服务器的代理或网关的数量。
|
|
method
|
请求方法。(例如'GET'或'POST')。
|
|
mimetype
|
||
mimetype_params
|
mimetype参数为dict。例如,如果内容类型是params将是 。text/html; charset=utf-8{'charset': 'utf-8'}
|
|
on_json_loading_failed(e )
|
||
parameter_storage_class¶
|
||
pragma
|
Pragma general-header字段用于包括可能适用于请求/响应链中任何收件人的特定于实现的指令
|
|
query_string
|
URL参数为raw bytestring
|
|
range
|
解析的Range标头
|
|
referrer
|
Referer [sic] request-header字段允许客户端为服务器的好处指定从中获取Request-URI的资源的地址(URI)(“referrer”,尽管头字段拼写错误)。
|
|
remote_addr
|
客户端的远程地址
|
|
remote_user
|
如果服务器支持用户身份验证,并且脚本受到保护,则此属性包含用户已通过身份验证的用户名
|
|
routing_exception=null
|
||
scheme
|
URL方案(http或https)
|
|
stream
|
||
user_agent
|
当前的用户代理。
|
|
url_rule=无
|
与请求匹配的内部URL规则。这可以用于检查来自前/后处理程序(request.url_rule.methods)等的URL允许哪些方法。
|
|
values
|
||
view_args=无
|
与请求匹配的视图参数的字典。如果匹配时发生异常,则会出现异常None。
|
|
want_form_data_parsed
|
如果请求方法携带内容,则返回True
|
上传
已上传的文件被储存在内存或文件系统的临时位置。你可以通过请求对象 files 属性来访问上传的文件。每个上传的文件都储存在这个 字典型属性中。这个属性基本和标准 Python file 对象一样,另外多出一个 用于把上传文件保存到服务器的文件系统中的 save() 方法。
pip install flask-uploads
pip install flask_wtf
app.config['SECRET_KEY'] = 'I have a dream'
app.config['UPLOADED_PHOTOS_DEST'] = os.getcwd()
photos = UploadSet('photos', IMAGES)
configure_uploads(app, photos)
patch_request_class(app) # set maximum file size, default is 16MB
class UploadForm(FlaskForm):
photo = FileField(validators=[
FileAllowed(photos, u'只能上传图片!'),
FileRequired(u'文件未选择!')])
submit = SubmitField(u'上传')
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
form = UploadForm()
if form.validate_on_submit():
filename = photos.save(form.photo.data)
file_url = photos.url(filename)
else:
file_url = None
return render_template('upload.html', form=form, file_url=file_url)
upload.html
<!DOCTYPE html>
<title>Upload File</title>
<h1>图片上传</h1>
<form method="POST" enctype="multipart/form-data">
{{ form.hidden_tag() }}
{{ form.photo }}
{% for error in form.photo.errors %}
<span style="color: red;">{{ error }}</span>
{% endfor %}
{{ form.submit }}
</form>
{% if file_url %}
<img src="{{%20file_url%20}}">
{% endif %}
Cookies
要访问 cookies ,可以使用 cookies 属性。可以使用响应 对象 的 set_cookie 方法来设置 cookies 。请求对象的 cookies属性是一个包含了客户端传输的所有 cookies 的字典。在 Flask 中,如果使用 会话 ,那么就不要直接使用 cookies ,因为 会话 比较安全一些。
读取 cookies:
from flask import request
@app.route('/')def index():
username = request.cookies.get('username')
# use cookies.get(key) instead of cookies[key] to not get a
# KeyError if the cookie is missing.
储存 cookies:
from flask import make_response
@app.route('/')
def index():
resp = make_response(render_template(...))
resp.set_cookie('username', 'the username')
return resp
重定向和错误
使用 redirect() 函数可以重定向。使用 abort() 可以 更早退出请求,并返回错误代码:
from flask import abort, redirect, url_for
@app.route('/')
def index():
return redirect(url_for('login'))
@app.route('/login')
def login():
abort(401)
this_is_never_executed()
上例实际上是没有意义的,它让一个用户从索引页重定向到一个无法访问的页面(401 表示禁止访问)。但是上例可以说明重定向和出错跳出是如何工作的。
from flask import render_template
@app.errorhandler(404)
def page_not_found(error):
return render_template('page_not_found.html'), 404
关于响应
视图函数的返回值会自动转换为一个响应对象。如果返回值是一个字符串,那么会被转换 为一个包含作为响应体的字符串、一个 200 OK 出错代码 和一个 text/html 类型的响应对象。以下是转换的规则:
-
如果视图返回的是一个响应对象,那么就直接返回它。
-
如果返回的是一个字符串,那么根据这个字符串和缺省参数生成一个用于返回的 响应对象。
-
如果返回的是一个元组,那么元组中的项目可以提供额外的信息。元组中必须至少 包含一个项目,且项目应当由(response, status, headers) 或者 (response, headers) 组成。 status 的值会重载状态代码, headers 是一个由额外头部值组成的列表或字典。
-
如果以上都不是,那么 Flask 会假定返回值是一个有效的 WSGI 应用并把它转换为 一个响应对象。
设想有如下视图:
@app.errorhandler(404)
def not_found(error):
return render_template('error.html'), 404
@app.errorhandler(404)
def not_found(error):
resp = make_response(render_template('error.html'), 404)
resp.headers['X-Something'] = 'A value'
return resp
会话
除了请求对象之外还有一种称为 session 的对象,允许你在不同请求 之间储存信息。这个对象相当于用密钥签名加密的 cookie ,即用户可以查看你的 cookie ,但是如果没有密钥就无法修改它。
使用会话之前你必须设置一个密钥。举例说明:
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
# Set the secret key to some random bytes. Keep this really secret!app.secret_key = b'_5#y2L"F4Q8znxec]/'
@app.route('/')def index():
if 'username' in session:
return 'Logged in as %s' % escape(session['username'])
return 'You are not logged in'
@app.route('/login', methods=['GET', 'POST'])def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return ''' <form method="post"> <p><input type=text name=username> <p><input type=submit value=Login> </form> '''
@app.route('/logout')def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
如何生成一个好的密钥
生成随机数的关键在于一个好的随机种子,因此一个好的密钥应当有足够的随机性。 操作系统可以有多种方式基于密码随机生成器来生成随机数据。使用下面的命令 可以快捷的为 Flask.secret_key ( 或者 SECRET_KEY )生成值:
基于 cookie 的会话的说明: Flask 会取出会话对象中的值,把值序列化后储存到 cookie 中。在打开 cookie 的情况下,如果需要查找某个值,但是这个值在请求中 没有持续储存的话,那么不会得到一个清晰的出错信息。请检查页面响应中的 cookie 的大小是否与网络浏览器所支持的大小一致。
除了缺省的客户端会话之外,还有许多 Flask 扩展支持服务端会话。
消息闪现
一个好的应用和用户接口都有良好的反馈,否则到后来用户就会讨厌这个应用。 Flask 通过闪现系统来提供了一个易用的反馈方式。闪现系统的基本工作原理是在请求结束时 记录一个消息,提供且只提供给下一个请求使用。通常通过一个布局模板来展现闪现的 消息。
日志
Changelog
有时候可能会遇到数据出错需要纠正的情况。例如因为用户篡改了数据或客户端代码出错 而导致一个客户端代码向服务器发送了明显错误的 HTTP 请求。多数时候在类似情况下 返回 400 Bad Request 就没事了,但也有不会返回的时候,而代码还得继续运行 下去。
这时候就需要使用日志来记录这些不正常的东西了。自从 Flask 0.3 后就已经为你配置好 了一个日志工具。
以下是一些日志调用示例:
集成 WSGI 中间件
如果想要在应用中添加一个 WSGI 中间件,那么可以包装内部的 WSGI 应用。假设为了 解决 lighttpd 的错误,你要使用一个来自 Werkzeug 包的中间件,那么可以这样做:
扩展是帮助完成公共任务的包。例如 Flask-SQLAlchemy 为在 Flask 中轻松使用 SQLAlchemy 提供支持。