Python Flask框架详解
<p>记录请求使用的HTTP方法</p><p> Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展,都需要用第三方的扩展来实现,比如可以用 Flask 扩展加入ORM、窗体验证工具,文件上传、身份验证等。Flask 没有默认使用的数据库,你可以选择 MySQL,也可以用 NoSQL。</p>
<p> 其 WSGI 工具箱采用 Werkzeug(路由模块),模板引擎则使用 Jinja2。这两个也是 Flask 框架的核心。</p>
<p>Flask常用扩展包:</p>
<ul>
<li>Flask-SQLalchemy:操作数据库;</li>
<li>Flask-script:插入脚本;</li>
<li>Flask-migrate:管理迁移数据库;</li>
<li>Flask-Session:Session存储方式指定;</li>
<li>Flask-WTF:表单;</li>
<li>Flask-Mail:邮件;</li>
<li>Flask-Bable:提供国际化和本地化支持,翻译;</li>
<li>Flask-Login:认证用户状态;</li>
<li>Flask-OpenID:认证;</li>
<li>Flask-RESTful:开发REST API的工具;</li>
<li>Flask-Bootstrap:集成前端Twitter Bootstrap框架;</li>
<li>Flask-Moment:本地化日期和时间;</li>
<li>Flask-Admin:简单而可扩展的管理接口的框架</li>
</ul>
<ol>
<li>中文文档(http://docs.jinkan.org/docs/flask/)</li>
<li>英文文档(http://flask.pocoo.org/docs/0.11/)</li>
<li>扩展列表:http://flask.pocoo.org/extensions/</li>
</ol>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">安装</span>
pip install flask==0.10.1 <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 后面为版本号</span></pre>
</div>
<h2>1、新建文件helloworld.py</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 导入Flask类</span>
<span style="color: rgba(0, 0, 255, 1)">from</span> flask <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Flask
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> Flask函数接收一个参数__name__,它会指向程序所在的包</span>
<span style="color: rgba(0, 0, 0, 1)">
app </span>= Flask(<span style="color: rgba(128, 0, 128, 1)">__name__</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 装饰器的作用是将路由映射到视图函数 index</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> index():
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Hello World</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> Flask应用程序实例的 run 方法 启动 WEB 服务器</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">:
app.run() </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 可以指定运行的主机IP地址,端口,是否开启调试模式</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> app.run(host="0.0.0.0", port=8888, debug = True)</span></pre>
</div>
<h2>2、相关配置参数</h2>
<p>Flask 程序实例在创建的时候,需要默认传入当前 Flask 程序所指定的包(模块)</p>
<pre><span>app = Flask(__name__<span>)</span></span></pre>
<p><img src="https://img2020.cnblogs.com/blog/1472531/202004/1472531-20200408225458213-80217692.png"></p>
<ul>
<li>import_name
<ul>
<li>Flask程序所在的包(模块),传 <code>__name__</code> 就可以</li>
<li>其可以决定 Flask 在访问静态文件时查找的路径</li>
</ul>
</li>
<li>static_path
<ul>
<li>静态文件访问路径(不推荐使用,使用 static_url_path 代替)</li>
</ul>
</li>
<li>static_url_path
<ul>
<li>静态文件访问路径,可以不传,默认为:<code>/ + static_folder</code></li>
</ul>
</li>
<li>static_folder
<ul>
<li>静态文件存储的文件夹,可以不传,默认为 <code>static</code></li>
</ul>
</li>
<li>template_folder
<ul>
<li>模板文件存储的文件夹,可以不传,默认为 <code>templates</code></li>
</ul>
</li>
</ul>
<h2>3.加载配置文件</h2>
<p>在 Flask 程序运行的时候,可以给 Flask 设置相关配置,比如:配置 Debug 模式,配置数据库连接地址等等,设置 Flask 配置有以下三种方式:</p>
<ul>
<li>从配置对象中加载(常用)
<ul>
<li>app.config.form_object()</li>
</ul>
</li>
从配置文件中加载
<ul>
<li>app.config.form_pyfile()</li>
</ul>
从环境变量中加载(不常用)
<ul>
<li>app.config.from_envvar()</li>
</ul>
</ul>
<h3>3.1配置对象加载</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 配置对象,里面定义需要给 APP 添加的一系列配置</span>
<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Config(object):
DEBUG </span>=<span style="color: rgba(0, 0, 0, 1)"> True
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 创建 Flask 类的对象,指向程序所在的包的名称</span>
app = Flask(<span style="color: rgba(128, 0, 128, 1)">__name__</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 从配置对象中加载配置</span>
app.config.from_object(Config)</pre>
</div>
<h3>3.2配置文件加载</h3>
<p>创建配置文件 <code>config.ini</code>,在配置文件中添加配置</p>
<p>格式eg: DEBUG = True</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 创建 Flask 类的对象,指向程序所在的包的名称</span>
app = Flask(<span style="color: rgba(128, 0, 128, 1)">__name__</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 从配置文件中加载配置</span>
app.config.from_pyfile(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">config.ini</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<h3 id="读取配置">3.4读取配置</h3>
<ul>
<li>app.config.get()</li>
<li>在视图函数中使用 current_app.config.get()</li>
</ul>
<blockquote>
<p>注:Flask 应用程序将一些常用的配置设置成了应用程序对象的属性,也可以通过属性直接设置/获取某些配置:app.debug = True</p>
</blockquote>
<h2>4 路由定义</h2>
<h3>4.1指定路由地址</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 指定访问路径为 hello</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/hello</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> demo1():
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hello world</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>
</div>
<h3>4.2 给路由传参</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 路由传递参数</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/user/<user_id></span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> user_info(user_id):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hello %s</span><span style="color: rgba(128, 0, 0, 1)">'</span> %<span style="color: rgba(0, 0, 0, 1)"> user_id
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 路由传递的参数默认当做 string 处理,也可以指定参数的类型</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 路由传递参数</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/user/<int:user_id></span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> user_info(user_id):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hello %d</span><span style="color: rgba(128, 0, 0, 1)">'</span> % user_id</pre>
</div>
<h3>4.3指定请求方式</h3>
<p>在 Flask 中,定义一个路由,默认的请求方式为:</p>
<ul>
<li>GET</li>
<li>OPTIONS(自带)</li>
<li>HEAD(自带)</li>
</ul>
<div class="cnblogs_code">
<pre>@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/login</span><span style="color: rgba(128, 0, 0, 1)">'</span>, methods=[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">GET</span><span style="color: rgba(128, 0, 0, 1)">'</span>, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">POST</span><span style="color: rgba(128, 0, 0, 1)">'</span>])<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 支持GET和POST,并且支持自带的OPTIONS和HEAD</span>
<span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> login():
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 直接从请求中取到请求方式并返回</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> request.method</pre>
</div>
<h3>4.4 正则匹配路由</h3>
<p>在 web 开发中,可能会出现限制用户访问规则的场景,那么这个时候就需要用到正则匹配,根据自己的规则去限定请求参数再进行访问</p>
<p>具体实现步骤为:</p>
<ul>
<li>导入转换器基类:在 Flask 中,所有的路由的匹配规则都是使用转换器对象进行记录</li>
<li>自定义转换器:自定义类继承于转换器基类</li>
<li>添加转换器到默认的转换器字典中</li>
<li>使用自定义转换器实现自定义匹配规则</li>
</ul>
<p>(1)导入转换器基类</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span> werkzeug.routing <span style="color: rgba(0, 0, 255, 1)">import</span> BaseConverter</pre>
</div>
<p>(2)自定义转换器</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span> flask <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Flask, redirect, url_for
</span><span style="color: rgba(0, 0, 255, 1)">from</span> werkzeug.routing <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> BaseConverter
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> RegexConverter(BaseConverter):
</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, url_name, *<span style="color: rgba(0, 0, 0, 1)">args):
super().</span><span style="color: rgba(128, 0, 128, 1)">__init__</span><span style="color: rgba(0, 0, 0, 1)">(url_name)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将接受的第1个参数当作匹配规则进行保存</span>
self.regex =<span style="color: rgba(0, 0, 0, 1)"> args
</span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ListConverter(BaseConverter):
regex </span>= <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">(\\d+,?)+\\d$</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> to_python(self, value):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> value.split(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">,</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> to_url(self, value):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">,</span><span style="color: rgba(128, 0, 0, 1)">"</span>.join(str(i) <span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span> value)</pre>
</div>
<p>(3)添加转换器到默认的转换器字典中,并指定转换器使用时名字为: re</p>
<div class="cnblogs_code">
<pre>app = Flask(<span style="color: rgba(128, 0, 128, 1)">__name__</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: re</span>
app.url_map.converters[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">re</span><span style="color: rgba(128, 0, 0, 1)">"</span>] =<span style="color: rgba(0, 0, 0, 1)"> RegexConverter
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: list</span>
app.url_map.converters[<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">list</span><span style="color: rgba(128, 0, 0, 1)">"</span>] = ListConverter</pre>
</div>
<p>(4)使用转换器去实现自定义匹配规则</p>
<div class="cnblogs_code">
<pre>@app.route(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/demo/<re('\d{6}'):use_name></span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> demo1(use_name):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">用户名是 %s</span><span style="color: rgba(128, 0, 0, 1)">"</span> %<span style="color: rgba(0, 0, 0, 1)"> use_name
@app.route(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/users/<list:user_list></span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> demo11(user_list):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">用户列表为 %s</span><span style="color: rgba(128, 0, 0, 1)">"</span> % user_list</pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 系统自带转换器</span>
DEFAULT_CONVERTERS =<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">default</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">: UnicodeConverter,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">string</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">: UnicodeConverter,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">any</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">: AnyConverter,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">path</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">: PathConverter,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">int</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">: IntegerConverter,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">float</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">: FloatConverter,
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">uuid</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">: UUIDConverter,
}
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 系统自带的转换器具体使用方式在每种转换器的注释代码中有写,请留意每种转换器初始化的参数</span></pre>
</div>
<p id="自定义转换器其他两个函数实现">自定义转换器其他两个函数实现:</p>
<p>继承于自定义转换器之后,还可以实现 to_python 和 to_url 这两个函数去对匹配参数做进一步处理:</p>
<ul>
<li>to_python:
<ul>
<li>该函数参数中的 value 值代表匹配到的值,可输出进行查看</li>
<li>匹配完成之后,对匹配到的参数作最后一步处理再返回,比如:转成 int 类型的值再返回:</li>
</ul>
</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> RegexConverter(BaseConverter):
</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span>(self, url_map, *<span style="color: rgba(0, 0, 0, 1)">args):
super(RegexConverter, self).</span><span style="color: rgba(128, 0, 128, 1)">__init__</span><span style="color: rgba(0, 0, 0, 1)">(url_map)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将接受的第1个参数当作匹配规则进行保存</span>
self.regex =<span style="color: rgba(0, 0, 0, 1)"> args
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> to_python(self, value):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> int(value) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 在视图函数中可以查看参数的类型,由之前默认的 str 已变成 int 类型的值</span></pre>
</div>
<ul>
<li> to_url:
<ul>
<li> 在使用 url_for 去获取视图函数所对应的 url 的时候,会调用此方法对 url_for 后面传入的视图函数参数做进一步处理</li>
<li> 具体可参见 Flask 的 app.py 中写的示例代码:ListConverter</li>
</ul>
</li>
</ul>
<h2> 5.简单视图</h2>
<h3>5.1 返回json</h3>
<p>在使用 Flask 给客户端返回 JSON 数据时,可以直接使用 jsonify 生成一个 JSON 的响应</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回JSON</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/demo</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> demo():
json_dict </span>=<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">user_id</span><span style="color: rgba(128, 0, 0, 1)">"</span>: 10<span style="color: rgba(0, 0, 0, 1)">,
</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">user_name</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">laowang</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span> jsonify(json_dict)<br>注:不推荐使用 json.dumps 转成 JSON 字符串直接返回,因为返回的数据要符合 HTTP 协议规范,如果是 JSON 需要指定 content-type:application/json</pre>
</div>
<h3>5.2重定向</h3>
<p>(1)重定向到百度</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 重定向</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/demo</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> demo():
</span><span style="color: rgba(0, 0, 255, 1)">return</span> redirect(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">http://www.baidu.com</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<p>(2)重定向到自己写的视图函数</p>
<ul>
<li>直接填写自己 url 路径</li>
<li>使用 url_for 生成指定视图函数所对应的 url</li>
</ul>
<div class="cnblogs_code">
<pre>@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/demo1</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> demo1():
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">demo1</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 重定向,采用url_for生成demo1对应的url</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/demo2</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> demo2():
</span><span style="color: rgba(0, 0, 255, 1)">return</span> redirect(url_for(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">demo1</span><span style="color: rgba(128, 0, 0, 1)">'</span>))</pre>
</div>
<p>(3)重定向到带有参数的视图函数</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 路由传递参数</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/user/<int:user_id></span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> user_info(user_id):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hello %d</span><span style="color: rgba(128, 0, 0, 1)">'</span> %<span style="color: rgba(0, 0, 0, 1)"> user_id
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 重定向,在url_for中传入参数</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/demo5</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> demo5():
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 使用 url_for 生成指定视图函数所对应的 url</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> redirect(url_for(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">user_info</span><span style="color: rgba(128, 0, 0, 1)">'</span>, user_id=100))</pre>
</div>
<h3>5.3自定义状态码</h3>
<p>自定义不符合 http 协议的状态码</p>
<div class="cnblogs_code">
<pre>@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/demo</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> demo():
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">状态码为 666</span><span style="color: rgba(128, 0, 0, 1)">'</span>, 666</pre>
</div>
<h2>6、异常捕获</h2>
<h3>6.1 HTTP主动抛出异常</h3>
<ul>
<li>abort 方法
<ul>
<li>抛出一个给定状态代码的 HTTPException 或者 指定响应,例如想要用一个页面未找到异常来终止请求,你可以调用 abort(404)。</li>
</ul>
</li>
<li>参数:
<ul>
<li>code – HTTP的错误状态码</li>
</ul>
</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> abort(404)</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 抛出状态码的话,只能抛出 HTTP 协议的错误状态码</span>
abort(500)</pre>
</div>
<h3>6.2捕获错误</h3>
<ul>
<li>errorhandler 装饰器
<ul>
<li>注册一个错误处理程序,当程序抛出指定错误状态码的时候,就会调用该装饰器所装饰的方法</li>
</ul>
</li>
<li>参数:
<ul>
<li>code_or_exception – HTTP的错误状态码或指定异常</li>
</ul>
</li>
</ul>
<p>例如统一处理状态码为500的错误给用户友好的提示:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 处理所有500类型的异常</span>
<span style="color: rgba(0, 0, 0, 1)">
@app.errorhandler(</span>500<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> internal_server_error(e):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">服务器搬家了</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 处理特定的异常项</span>
<span style="color: rgba(0, 0, 0, 1)">@app.errorhandler(ZeroDivisionError)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> zero_division_error(e):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">除数不能为0</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>
</div>
<h2> 7、勾子函数</h2>
<p>在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:</p>
<ul>
<li>在请求开始时,建立数据库连接;</li>
<li>在请求开始时,根据需求进行权限校验;</li>
<li>在请求结束时,指定数据的交互格式;</li>
</ul>
<p>为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,即请求钩子。</p>
<p>请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子:</p>
<ul>
<li>before_first_request
<ul>
<li>在处理第一个请求前执行</li>
</ul>
</li>
<li>before_request
<ul>
<li>在每次请求前执行</li>
<li>如果在某修饰的函数中返回了一个响应,视图函数将不再被调用</li>
</ul>
</li>
<li>after_request
<ul>
<li>如果没有抛出错误,在每次请求后执行</li>
<li>接受一个参数:视图函数作出的响应</li>
<li>在此函数中可以对响应值在返回之前做最后一步修改处理</li>
<li>需要将参数中的响应在此参数中进行返回</li>
</ul>
</li>
<li>teardown_request:
<ul>
<li>在每次请求后执行</li>
<li>接受一个参数:错误信息,如果有相关错误抛出</li>
</ul>
</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span> flask <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Flask
</span><span style="color: rgba(0, 0, 255, 1)">from</span> flask <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> abort
app </span>= Flask(<span style="color: rgba(128, 0, 128, 1)">__name__</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 在第一次请求之前调用,可以在此方法内部做一些初始化操作</span>
<span style="color: rgba(0, 0, 0, 1)">@app.before_first_request
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> before_first_request():
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">before_first_request</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 在每一次请求之前调用,这时候已经有请求了,可能在这个方法里面做请求的校验</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 如果请求的校验不成功,可以直接在此方法中进行响应,直接return之后那么就不会执行视图函数</span>
<span style="color: rgba(0, 0, 0, 1)">@app.before_request
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> before_request():
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">before_request</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> if 请求不符合条件:</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> return "laowang"</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 在执行完视图函数之后会调用,并且会把视图函数所生成的响应传入,可以在此方法中对响应做最后一步统一的处理</span>
<span style="color: rgba(0, 0, 0, 1)">@app.after_request
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> after_request(response):
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">after_request</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
response.headers[</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Content-Type</span><span style="color: rgba(128, 0, 0, 1)">"</span>] = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">application/json</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> response
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 请每一次请求之后都会调用,会接受一个参数,参数是服务器出现的错误信息</span>
<span style="color: rgba(0, 0, 0, 1)">@app.teardown_request
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> teardown_request(e):
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">teardown_request</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
@app.route(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> index():
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">index</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">:
app.run(debug</span>=True)</pre>
</div>
<p>执行结果</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">在第1次请求时的打印:
before_first_request
before_request
after_request
teardown_request
在第2次请求时的打印:
before_request
after_request
teardown_request</span></pre>
</div>
<h2> 8. request请求参数</h2>
<p> request 就是flask中代表当前请求的 request 对象,作为请求上下文变量(理解成全局变量,在视图函数中直接使用可以取到当前本次请求)</p>
<p> 常用属性:</p>
<table style="height: 148px; width: 655px" border="0" align="left">
<tbody>
<tr>
<td>属性</td>
<td>说明</td>
<td>类型</td>
</tr>
<tr>
<td>data</td>
<td>记录请求的数据,并转换为字符串</td>
<td>*</td>
</tr>
<tr>
<td>form</td>
<td>记录请求中的表单数据</td>
<td>MultiDict</td>
</tr>
<tr>
<td>args</td>
<td>记录请求中的查询参数</td>
<td>MultiDict</td>
</tr>
<tr>
<td>cookies</td>
<td>记录请求中的cookie信息</td>
<td>Dict</td>
</tr>
<tr>
<td>headers</td>
<td>记录请求中的报文头</td>
<td>EnvironHeaders</td>
</tr>
<tr>
<td>method</td>
<td>记录请求使用的HTTP方法</td>
<td>GET/POST</td>
</tr>
<tr>
<td>url</td>
<td>记录请求的URL地址</td>
<td>string</td>
</tr>
<tr>
<td>files</td>
<td>记录请求上传的文件</td>
<td>*</td>
</tr>
</tbody>
</table>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 获取上传的图片并保存到本地</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/</span><span style="color: rgba(128, 0, 0, 1)">'</span>, methods=[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">POST</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">])
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> index():
pic </span>= request.files.get(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">pic</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
pic.save(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">./static/aaa.png</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">index</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>
</div>
<h2>9、flask上下文参数</h2>
<p> 上下文:相当于一个容器,保存了 Flask 程序运行过程中的一些信息。</p>
<p> Flask中有两种上下文,请求上下文(request context)和应用上下文(application context)</p>
<ol>
<li>
<p><em>application</em> 指的就是当你调用<code>app = Flask(__name__)</code>创建的这个对象<code>app</code>;</p>
</li>
<li>
<p><em>request</em> 指的是每次<code>http</code>请求发生时,<code>WSGI server</code>(比如gunicorn)调用<code>Flask.__call__()</code>之后,在<code>Flask</code>对象内部创建的<code>Request</code>对象;</p>
</li>
<li>
<p><em>application</em> 表示用于响应WSGI请求的应用本身,<em>request</em> 表示每次http请求;</p>
</li>
<li>
<p><em>application</em>的生命周期大于<em>request</em>,一个<em>application</em>存活期间,可能发生多次http请求,所以,也就会有多个<em>request</em></p>
</li>
</ol>
<p><em> 源码了解一下 flask 如何实现这两种context:</em><em> </em></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 代码摘选自flask 0.5 中的ctx.py文件, 进行了部分删减</span>
<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> _RequestContext(object):
</span><span style="color: rgba(0, 0, 255, 1)">def</span> <span style="color: rgba(128, 0, 128, 1)">__init__</span><span style="color: rgba(0, 0, 0, 1)">(self, app, environ):
self.app </span>=<span style="color: rgba(0, 0, 0, 1)"> app
self.request </span>=<span style="color: rgba(0, 0, 0, 1)"> app.request_class(environ)
self.session </span>=<span style="color: rgba(0, 0, 0, 1)"> app.open_session(self.request)
self.g </span>=<span style="color: rgba(0, 0, 0, 1)"> _RequestGlobals()
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> flask 使用_RequestContext的代码如下:</span>
<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Flask(object):
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> request_context(self, environ):
</span><span style="color: rgba(0, 0, 255, 1)">return</span> _RequestContext(self, environ)</pre>
</div>
<p>在<code>Flask</code>类中,每次请求都会调用这个<code>request_context</code>函数。这个函数则会创建一个<code>_RequestContext</code>对象。这个对象在创建时,将<code>Flask</code>实例的本身作为实参传入<code>_RequestContext</code>自身,因此,<code>self.app = Flask()</code>。</p>
<p>所以,虽然每次http请求都会创建一个<code>_RequestContext</code>对象,但是,每次创建的时候都会将同一个<code>Flask</code>对象传入该对象的<code>app</code>成员变量,使得:</p>
<blockquote>
<p>由同一个<code>Flask</code>对象响应的请求所创建的<code>_RequestContext</code>对象的<code>app</code>成员变量都共享同一个application</p>
</blockquote>
<p>通过在<code>Flask</code>对象中创建<code>_RequestContext</code>对象,并将<code>Flask</code>自身作为参数传入<code>_RequestContext</code>对象的方式,实现了多个request context对应一个application context 的目的。 </p>
<p>(1)请求上下文(request context)</p>
<p> 请求上下文对象有:request、session</p>
<ul>
<li style="list-style-type: none">
<ul>
<li>request
<ul>
<li>封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get('user'),获取的是get请求的参数。</li>
</ul>
</li>
<li>session
<ul>
<li>用来记录请求会话中的信息,针对的是用户信息。举例:session['name'] = user.id,可以记录用户信息。还可以通过session.get('name')获取用户信息。</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>(2)应用上下文(application context)</p>
<p> 应用上下文对象有:current_app,g</p>
<p> ①current_app</p>
<p> 应用程序上下文,用于存储应用程序中的变量,可以通过current_app.name打印当前app的名称,也可以在current_app中存储一些变量,例如:</p>
<ul>
<li>应用的启动脚本是哪个文件,启动时指定了哪些参数</li>
<li>加载了哪些配置文件,导入了哪些配置</li>
<li>连了哪个数据库</li>
<li>有哪些public的工具类、常量</li>
<li>应用跑再哪个机器上,IP多少,内存多大</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">current_app.name
current_app.test_value</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>
</div>
<p> ②g变量</p>
<p> g 作为 flask 程序全局的一个临时变量,充当中间媒介的作用,我们可以通过它传递一些数据,g 保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别 </p>
<div class="cnblogs_code">
<pre>g.name=<span style="color: rgba(128, 0, 0, 1)">'zhangsan</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>
</div>
<ul>
<li>请求上下文:保存了客户端和服务器交互的数据</li>
<li>应用上下文:flask 应用程序运行过程中,保存的一些配置信息,比如程序名、数据库连接、应用信息等</li>
</ul>
<h2>10.cookie使用</h2>
<p>Cookie:指某些网站为了辨别用户身份、进行会话跟踪而储存在用户本地的数据(通常经过加密)。</p>
<ul>
<li>复数形式Cookies。</li>
<li>Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。</li>
<li>Cookie的key/value可以由服务器端自己定义。</li>
</ul>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 设置cookie</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息</span>
<span style="color: rgba(0, 0, 255, 1)">from</span><span style="color: rgba(0, 0, 0, 1)"> flask imoprt Flask, make_response
@app.route(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/cookie</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> set_cookie():
resp </span>= make_response(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">this is to set cookie</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
resp.set_cookie(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">username</span><span style="color: rgba(128, 0, 0, 1)">'</span>, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">zhangsan</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
resp.set_cookie(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">pwd</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">12321</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> resp
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 设置过期时间</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/cookie</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> set_cookie():
response </span>= make_response(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hello world</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
response.set_cookie(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">username</span><span style="color: rgba(128, 0, 0, 1)">'</span>, <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">zhangsan</span><span style="color: rgba(128, 0, 0, 1)">'</span>, max_age=3600)<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 过期时间为3600秒</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> response
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 获取cookie</span>
<span style="color: rgba(0, 0, 255, 1)">from</span> flask <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Flask, request
@app.route(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/request</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> resp_cookie():
resp </span>= request.cookies.get(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">username</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> resp
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 删除cookie</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/logout</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> logout():
resp </span>= make_response(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">success</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
resp.delete_cookie(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">username</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
resp.delete_cookie(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">pwd</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> resp</pre>
</div>
<h2>11、Session使用</h2>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> session数据的获取</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> session:请求上下文对象,用于处理http请求中的一些数据内容</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 设置secret_key</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 作用:设置一个secret_key值,用作各种 HASH</span>
app.secret_key = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">python</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 考虑到安全性, 这个密钥不建议存储在程序中. 最好的方法是存储在你的系统环境变量中, 通过 os.getenv(key, default=None) 获得.</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">设置session,并重定向到获取session的index函数</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/login</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> login():
session[</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">username</span><span style="color: rgba(128, 0, 0, 1)">"</span>] = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">zhangsan</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">
session[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">password</span><span style="color: rgba(128, 0, 0, 1)">'</span>] = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1234321</span><span style="color: rgba(128, 0, 0, 1)">"</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> redirect(url_for(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">index</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 获取session</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> index():
username </span>= session.get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">username</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
password </span>= session.get(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">password</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">世界真美好%s======%s</span><span style="color: rgba(128, 0, 0, 1)">"</span> %<span style="color: rgba(0, 0, 0, 1)"> (username, password)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 删除session,并重定向到获取session的index函数</span>
@app.route(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/logout</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> logout():
session.pop(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">username</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
session.pop(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">password</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> redirect(url_for(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">index</span><span style="color: rgba(128, 0, 0, 1)">"</span>))</pre>
</div>
<h2>12、蓝图Blueprint</h2>
<p>Blueprint 是一个存储操作方法的容器,这些操作在这个Blueprint 被注册到一个应用之后就可以被调用,Flask 可以通过Blueprint来组织URL以及处理请求。</p>
<p>Flask使用Blueprint让应用实现模块化,在Flask中,Blueprint具有如下属性:</p>
<ul>
<li>一个应用可以具有多个Blueprint</li>
<li>可以将一个Blueprint注册到任何一个未使用的URL下比如 “/”、“/sample”或者子域名</li>
<li>在一个应用中,一个模块可以注册多次</li>
<li>Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法,它并不是必须要实现应用的视图和函数的</li>
<li>在一个应用初始化时,就应该要注册需要使用的Blueprint</li>
</ul>
<p><span style="color: rgba(255, 0, 0, 1)">但是一个Blueprint并不是一个完整的应用,它不能独立于应用运行,而必须要注册到某一个应用中。</span></p>
<p>蓝图/Blueprint对象用起来和一个应用/Flask对象差不多,最大的区别在于一个 蓝图对象没有办法独立运行,必须将它注册到一个应用对象上才能生效</p>
<p>使用蓝图可以分为三个步骤</p>
<ul>
<li>1,创建一个蓝图对象</li>
</ul>
<div class="cnblogs_code">
<pre>admin=Blueprint(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">admin</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 128, 1)">__name__</span>)</pre>
</div>
<ul>
<li>2,在这个蓝图对象上进行操作,注册路由,指定静态文件夹,注册模版过滤器</li>
</ul>
<div class="cnblogs_code">
<pre>@admin.route(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/admin</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> index():
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">admin_home</span><span style="color: rgba(128, 0, 0, 1)">'</span></pre>
</div>
<ul>
<li>3,在应用对象上注册这个蓝图对象</li>
</ul>
<div class="cnblogs_code">
<pre>app.register_blueprint(admin,url<br>_prefix=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/admin</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">当这个应用启动后,通过/admin/admin/可以访问到蓝图中定义的视图函数</span></p>
<h3 id="运行机制">运行机制</h3>
<ul>
<li>蓝图是保存了一组将来可以在应用对象上执行的操作,注册路由就是一种操作</li>
<li>当在应用对象上调用 route 装饰器注册路由时,这个操作将修改对象的url_map路由表</li>
<li>然而,蓝图对象根本没有路由表,当我们在蓝图对象上调用route装饰器注册路由时,它只是在内部的一个延迟操作记录列表defered_functions中添加了一个项</li>
<li>当执行应用对象的 register_blueprint() 方法时,应用对象将从蓝图对象的 defered_functions 列表中取出每一项,并以自身作为参数执行该匿名函数,即调用应用对象的 add_url_rule() 方法,这将真正的修改应用对象的路由表</li>
</ul>
<h3 id="蓝图的url前缀">蓝图的url前缀</h3>
<ul>
<li>当我们在应用对象上注册一个蓝图时,可以指定一个url_prefix关键字参数(这个参数默认是/)</li>
<li>
<p>在应用最终的路由表 url_map中,在蓝图上注册的路由URL自动被加上了这个前缀,这个可以保证在多个蓝图中使用相同的URL规则而不会最终引起冲突,只要在注册蓝图时将不同的蓝图挂接到不同的自路径即可</p>
</li>
<li>
<p>url_for</p>
</li>
</ul>
<div class="cnblogs_code">
<pre>url_for(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">admin.index</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> /admin/admin/ 将admin下index函数路由注册 </span></pre>
</div>
<h3 id="注册静态路由">注册静态路由</h3>
<p>和应用对象不同,蓝图对象创建时不会默认注册静态目录的路由。需要我们在 创建时指定 static_folder 参数。</p>
<p>下面的示例将蓝图所在目录下的static_admin目录设置为静态目录</p>
<div class="cnblogs_code">
<pre>admin = Blueprint(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">admin</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 128, 1)">__name__</span>,static_folder=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">static_admin</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
app.register_blueprint(admin,url_prefix</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/admin</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<p>现在就可以使用/admin/static_admin/ 访问static_admin目录下的静态文件了 定制静态目录URL规则 :可以在创建蓝图对象时使用 static_url_path 来改变静态目录的路由。下面的示例将为 static_admin 文件夹的路由设置为 /lib</p>
<div class="cnblogs_code">
<pre>admin = Blueprint(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">admin</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 128, 1)">__name__</span>,static_folder=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">static_admin</span><span style="color: rgba(128, 0, 0, 1)">'</span>,static_url_path=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/lib</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
app.register_blueprint(admin,url_prefix</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/admin</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<h3><span style="font-size: 1.17em; font-family: "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif">设置模版目录</span></h3>
<p>蓝图对象默认的模板目录为系统的模版目录,可以在创建蓝图对象时使用 template_folder 关键字参数设置模板目录</p>
<div class="cnblogs_code">
<pre>admin = Blueprint(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">admin</span><span style="color: rgba(128, 0, 0, 1)">'</span>,<span style="color: rgba(128, 0, 128, 1)">__name__</span>,template_folder=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">my_templates</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<p>注:如果在 templates 中存在和 my_templates 同名文件,则系统会优先使用 templates 中的文件,参考链接:https://stackoverflow.com/questions/7974771/flask-blueprint-template-folder</p>
<h2>13、Flask-Script 扩展</h2>
<p>通过使用Flask-Script扩展,我们可以在Flask服务器启动的时候,通过命令行的方式传入参数。而不仅仅通过app.run()方法中传参,比如我们可以通过:</p>
<div class="cnblogs_code">
<pre>python main.py runserver -host ip地址 -P 端口</pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 1 、安装 Flask-Script 扩展</span>
pip install flask-<span style="color: rgba(0, 0, 0, 1)">script
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 2、集成 Flask-Script</span>
<span style="color: rgba(0, 0, 255, 1)">from</span> flask <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Flask
</span><span style="color: rgba(0, 0, 255, 1)">from</span> flask_script <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Manager
app </span>= Flask(<span style="color: rgba(128, 0, 128, 1)">__name__</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 把 Manager 类和应用程序实例进行关联</span>
manager =<span style="color: rgba(0, 0, 0, 1)"> Manager(app)
@app.route(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">/</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> index():
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hello world</span><span style="color: rgba(128, 0, 0, 1)">'</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(128, 0, 128, 1)">__name__</span> == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
manager.run()</span></pre>
</div>
<p> </p><br><br>
来源:https://www.cnblogs.com/caijunchao/p/12663871.html
頁:
[1]