zoukankan      html  css  js  c++  java
  • Flask QuickBoot

    路由

    客户端把请求发送给Web服务器,Web服务器再把请求发送给程序实例。程序实例需要知道对每个URL请求运行哪些代码,所以保存了一个 URL 到 Python 函数的映射关系。处理URL和函数之间关系的程序称路由

    Flask中使用 app.route 装饰器,把装饰器的函数注册到路由。

    @app.route('/')
    def index():
        return '<h1> hello </h1>'
    

    这个例子将 index() 函数注册为程序根 '/' 地址。
    访问 http://localhost:5000/ 后,会触发服务器执行 index() 函数,这个函数的返回值称为响应,是客户端接收到的内容。

    index() 这样的函数称为视图函数。视图函数返回的响应可以是包含 HTML 的简单字符串,也可以是复杂的表单。

    动态路由

    如 Github 中,登录到某人的主页, 这时URL为 https://github.com/<user-name>,用户名 user-name 是地址的一部分。

    Flask 中,只需要在 route 装饰器中使用特殊的句法即可。

    @app.route('/user/<name>')
    def user(name):
        return '<h1> hello, %s </h1>' % name
    

    尖括号中的内容就是动态部分,任何匹配静态部分的URL都会映射到这个路由上。调用视图函数时,Flask 会将动态部分作为参数传入函数中。

    路由中的动态部分默认使用字符串,不过也可以使用类型定义:int float path 类型。
    例如: /user/<int:id>

    path 类型也是字符串,但不把斜线视作分隔符。

    程序和请求上下文

    flask 从客户端收到请求时, 要让视图函数能访问一些对象, 这样才能处理请求。 request 就是一个很好的例子, 它封装了客户端发送的 HTTP 请求。

    要想让视图函数能够访问请求对象, 一个显而易见的方式是将其作为参数传入视图函数,不过这会导致程序中的每个视图函数都增加一个参数。除了访问请求对象, 如果视图函数在处理请求时还要访问其他对象,情况会变得更糟。

    为了避免大量可有可无的参数把视图函数弄得一团糟, flask 使用 上下文 临时把某些对象变为全局可访问。

    from flask import request
    
    @app.route('/')
    def index():
        user_agent = request.header.get('User-Agent')
        return '<p> Your browser is %s </p>' % user_agent
    

    注意这个视图函数中我们如何把 request 当作全局变量使用。事实上, request 不可能是全局变量。在多线程服务器中,多个线程同时处理不同客户端发送的不同请求时,每个线程看到的 request 对象必然不同。flask 使用上下文让特定变量在一个线程中全局可访问, 与此同时却不会干扰其他线程。

    flask 中有两种上下文: 程序上下文、请求上下文

    变量名 上下文 说明
    current_app 程序上下文 当前激活程序的程序实例
    g 程序上下文 处理请求时用作临时存储的对象,每次请求都会重设这个变量
    request 请求上下文 请求对象,封装了客户端发出的HTTP请求中的内容
    session 请求上下文 用户会话,用于存储请求之间需要“记住”的值的词典

    flask 在分发请求之前激活(或推送)程序和请求上下文,请求处理完成后再将其删除。程序上下文被推送后,就可以在线程中使用 current_appg 变量。类似的,请求上下文被推送后,就可以使用 requestsession 变量。如果使用这些变量时我们没有激活程序上下文或请求上下文,就会导致错误。

    请求调度

    程序收到客户端发来的请求时, 要找到处理该请求的视图函数。为了完成这个任务, flask 会在程序的 URL映射 中查找请求的 URL。 URL映射 是 URL 和 视图函数之间的对应关系。 flask 使用 app.route 装饰器或者非装饰器形式的 app.add_url_rule() 生成映射。

    可以使用 app.url_map 查看 URL 映射。

    >>> from hello import app
    >>> app.url_map
    Map([<Rule '/' (GET, HEAD, OPTIONS) -> index>,
     <Rule '/static/<filename>' (GET, HEAD, OPTIONS) -> static>,
     <Rule '/user/<name>' (GET, HEAD, OPTIONS) -> user>])
    

    //user/<name> 路由是在程序中使用 app.route 装饰器定义。 /static/<filename> 路由是 flask 添加的特殊路由,用于访问静态文件。

    URL 映射中 HEAD、Options、GET 是请求方法,由路由进行处理。flask 为每个路由都指定了请求方法,这样不同的请求方法发送到相同的 URL 上时,会使用不同的视图函数进行处理。 HEADOPTIONS 方法由 flask 自动处理。

    请求钩子

    有时在处理请求之前或之后执行代码会很有用。例如,在请求开始时,我们可能需要创建数据库连接或认证发起请求的用户。为了避免在每个视图函数中都使用重复的代码, flask 提供了注册通用函数的功能, 注册的函数可在请求被分发到视图函数之前或之后调用。

    请求钩子使用装饰器实现,flask 支持以下4中钩子

    • before_first_request : 注册一个函数,在处理第一个请求之前运行。
    • before_request: 注册一个函数,在每次请求之前运行。
    • after_request: 注册一个函数,如果没有未处理的异常抛出,在每次请求之后运行。
    • teardown_request: 注册一个函数,即使有未处理的异常抛出,也在每次请求之后运行。

    在请求钩子函数和视图函数之间共享数据一般使用上下文全局变量 g 。 例如, before_request 处理程序可以从数据库中加载已登录用户, 并将其保存到 g.user 中。随后调用视图函数时, 视图函数再使用 g.user 获取用户。

    响应

    flask 调用视图函数后,会将其返回值作为响应的内容。大多数情况下,响应就是一个简单的字符串,作为 HTML 页面回送客户端。

    但 HTTP 协议还需要返回 状态码, flask 默认设为 200, 这个代码表明请求已经被成功处理。如果视图函数返回的响应需要使用不同的状态码, 那么可以把数字代码作为第二个返回值, 添加到响应文本之后:

    @app.route('/')
    def index():
        return '<h1>Bad Request</h1>', 400
    

    flask 视图函数还可以返回Response对象。 make_response() 函数可以接收 1个、2个或3个参数,并返回一个 Response 对象。下例创建了一个响应对象,然后设置了 cookie:

    from flask import make_response
    
    @app.route('/')
    def index():
        response = make_response('<h1>Content</h1>')
        response.set_cookie('answer', '42')
        return response
    

    还有一种特殊响应类型:重定向。这种响应没有页面文档,只告诉浏览器一个新地址用以加载新页面。

    flask 提供了 redirect() 辅助函数,用以生成这种响应:

    from flask import redirect
    
    @app.route('/')
    def index():
        return redirect('http://www.example.com')
    

    还有一种处理错误的特殊响应,由 abort 函数生成,在下面例子中,如果 URL 中的动态参数 id 对应的用户不存在,就返回状态码 404

    from flask import abort
    
    @app.route('/user/<id>')
    def get_user(id):
        user = load_user(id)
        if not user:
            abort(404)
        return '<h1> Hello, %s</h1>' % user.name
    

    abort 不会把控制权交还给调用它的函数,而是抛出异常把控制权交给 Web服务器。

    模版

    模版是一个包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体指只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为 渲染 。为了渲染模版, Flask 使用了一个名为 Jinja2 的强大模版引擎。

    Jinja2 模版引擎

    形式最简单的Jinja2模版就是一个包含响应文本的文件。

    示例 1 templates/index.html

    <h1>Hello World!</h1>
    

    示例 2 templates/user.html

    <h1>Hello, {{ name }}!</h1>
    

    示例2 中包含一个使用变量表示的动态部分 {{ name }}

    渲染模版

    默认情况下, Flask 在程序文件夹中的 templates 子文件夹中寻找模版。我们将 示例1 和 示例2 分别命名为 index.htmluser.html 存放在 templates 文件夹下。

    视图函数对应为:

    from flask import Flask, render_template
    
    #...
    
    @app.route('/')
    def index():
        return render_template('index.html')
        
    @app.route('/user/<name>')
    def user(name):
        return render_template('user.html', name=name)
    
    

    Flask 提供的 render_template 函数把 Jinja2 模版引擎集成到程序中。 render_template 函数的第一个参数是模版的文件名。随后的参数都是键值对, 表示模版中变量对应的真实值。在这段代码中,第二个模版收到一个名为 name 的变量。

    视图函数中 name=name 是关键字参数,左边的 name 表示参数名,就是模版中的占位符;右边的 name 是当前作用域中的变量,表示同名参数的值。

    变量

    示例2 在模版中使用的 {{ name }} 结构表示一个变量,它是一种特殊的占位符, 告诉模版引擎这个位置的值从渲染模版时使用的数据中获取。

    Jinja2 能识别所有类型的变量,甚至 列表、字典和对象。在模版中使用变量的一些示例如下:

    <p>A vakue from a dictionary: {{ mydict['key'] }}.</p>
    <p>A vakue from a list: {{ mylist[3] }}.</p>
    <p>A vakue from a list, with a variable index: {{ mylist[myintvar] }}.</p>
    <p>A vakue from a object's method: {{ myobj.somemethod() }}.</p>
    

    可以使用 过滤器 修改变量, 过滤器名添加在变量名之后, 中间使用竖线分隔。例如,下述模版以首字母大写形式显示变量 name 值:

    Hello, {{ name|capitalize }}
    

    常用过滤器:

    过滤器名 说明
    safe 渲染值时不转义
    capitalize 把值的首字母转换成大写,其他字母转换成小写
    lower 把值转换成小写形式
    upper 把值转换成大写形式
    title 把值中的每个单词的首字母都转成大写
    trim 把值的首尾空格去掉
    scriptags 渲染之前把值中所有的 HTML 标签都删掉

    注意:千万别在不可信的值上使用 safe 过滤器,例如用户在表单中输入的文本。
    默认情况下,出于安全考虑, Jinja2 会转移所有变量。例如, 如果一个变量的值为 '<h1>Hello</h1>'Jinja2 会将其渲染成 '&lt;h1&gt;Hello&lt;/h1&gt;',浏览器能显示 h1 元素,但不会进行解释。

    控制结构

    Jinja2 提供了多种控制结构,可用来改变模版的渲染流程。

    条件控制语句

    {% if user %}
        Hello, {{ user }}
    {% else %}
        Hello, Stranger!
    {% endif %}
    

    for 循环

    <ul>
        {% for comment in comments %}
            <li>{{ comment }}</li>
        {% endfor %}
    </ul>
    

    宏类似 python 中的函数

    {% macro render_comment(comment) %}
        <li>{{ comment }}</li>
    {% endmacro %}
    
    <ul>
        {% for comment in comments %}
            {{ render_comment(comment) }}
        {% endfor %}
    </ul>
    

    包含

    需要在多出重复使用的模版代码片段可以写入单独的文件,再包含在所有模块中,以避免重复:

    {% include 'common.html' %}
    

    继承

    另一种重复使用代码的强大方式是模版集成,它类似与 Python 代码中的类继承。首先, 创建一个名为 base.html 的基模版:

    <html>
    <head>
        {% block head %}
        <title>{% block title%}{% endblock %} - My Application<title>
        {% endblock %}
    </head>
    <body>
        {% block body %}
        {% endblock %}
    </body>
    </head>
    

    block 标签定义的元素可在衍生模版中修改。在 base.html 中,我们定义了名为 headtitlebody 的块。注意, title 包含在 head 中。 下面这个示例是基模版的衍生模版:

    {% extends "base.html" %}
    {% block title %}Index{% endblock %}
    {% block head %}
        {{ supper() }}
        <style>
        </style>
    {% endblock %}
    {% block body %}
    <h1>Hello, World!</h1>
    {% endblock %}
    

    extends 指令声明这个模版衍生自 base.html。在 extends 指令后, 基模版中的 3 个块被重新定义, 模版引擎会将其插入适当的位置。注意新定义的 head 块, 在基模版中其内容不是空的, 所以使用 super() 获取原来的内容。

    链接

    任何具有多个路由的程序都需要可以连接不同页面的链接,例如导航条。

    在模板中直接编写简单路由的 URL 链接不难,但对于包含可变部分的动态路由,在模板
    中构建正确的 URL 就很困难。而且,直接编写 URL 会对代码中定义的路由产生不必要的
    依赖关系。如果重新定义路由,模板中的链接可能会失效。

    为了避免这些问题,Flask 提供了 url_for() 辅助函数,它可以使用程序URL 映射中保存
    的信息生成 URL

    url_for() 函数最简单的用法是以视图函数名(或者app.add_url_route() 定义路由时使用
    的端点名)作为参数,返回对应的URL。

    例如:程序中调用 url_for('index') 得到的结果是 / 。调用 url_for('index', _external=True) 返回的则是绝对地址,比如 http://localhost:5000/

    使用url_for() 生成动态地址时, 将动态部分作为关键字参数传入。例如,url_for('user', name='john', _external=True) 的返回结果是 http://localhost:5000/user/john。传入 url_for() 的关键字参数不仅限于动态路由中的参数。函数能将任何额外参数添加到查询字符串中。例如,url_for('index', page=2) 的返回结果是 /?page=2

    静态文件

    Web 程序不是仅由 Python 代码和模板组成。大多数程序还会使用静态文件,例如 HTML 代码中引用的图片、JavaScript 源码文件和 CSS

    对静态文件的引用被当成一个特殊的路由,即 /static/<filename>。例如,调用 url_for('static', filename='css/styles.css', _external=True) 得到的结果是 http://localhost:5000/static/css/styles.css

    默认设置下,Flask 在程序根目录中名为 static 的子目录中寻找静态文件。如果需要,可在 static 文件夹中使用子文件夹存放文件。服务器收到前面那个URL 后,会生成一个响应,包含文件系统中static/css/styles.css 文件的内容。

    示例1 展示了如何在程序的基模板中放置 favicon.ico 图标。这个图标会显示在浏览器的地址栏中。

    示例1 templates/base.html 定义收藏夹图标

    {% block head %}
    {{ super() }}
    <link rel="shortcut icon" href="{{ url_for('static', filename = 'favicon.ico') }}"
    	type="image/x-icon">
    <link rel="icon" href="{{ url_for('static', filename = 'favicon.ico') }}"
    	type="image/x-icon">
    {% endblock %}
    

    图标的声明会插入 head 块的末尾。注意如何使用 super() 保留基模板中定义的块的原始内容。

  • 相关阅读:
    自动发送邮件功能
    工作中常用的Android系统ADB命令收集
    商城系统必须知道的【订单、优惠金额、退货、实际营收】解释
    商城系统项目必须知道的专业数据指标
    接口加密思路
    Selenium使用Chrome模拟手机浏览器方法解析
    PHP上传图片基本代码示例
    iframe子页面获取父页面的点击事件
    javascript实现网页倒计时效果
    Crontab常用命令总结
  • 原文地址:https://www.cnblogs.com/ash975/p/15209386.html
Copyright © 2011-2022 走看看