1、Flask框架简介

  • Django:1个重武器,包含了web开发中常用的功能、组件的框架;(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType....);
  • Tornado(知乎):2大特性就是异步非阻塞、原生支持WebSocket协议;
  • Flask:功能和性能虽然不及Django和Tornado,但是Flask的第三方开源组件比丰富:http://flask.pocoo.org/extensions/
  • Bottle:比较简单;
  • web.py、web2py、Quixote(豆瓣)……

总结:小型web应用设计的功能点不多使用Flask; 大型web应用设计的功能点比较多使用的组件也会比较多,使用Django(自带功能多不用去找插件); 如果追求性能可以考虑Tornado;

2、安装Python

官网下载地址:https://www.python.org/downloads/
特别要注意选上pipAdd python.exe to Path,然后一路点“Next”即可完成安装

3、安装Flask

Flask的socket是基于Werkzeug 实现的,模板语言依赖jinja2模板,在使用Flask之前需要安装一下:

pip install flask  //建议用 PyCharm 编写代码`  

如果要安装python3可用的flask,通过pip3 install flask

4、程序的基本结构

  • 一个完整的flask程序(index.py)

    <!-- 引入Flask类,Flask类实现了一个WSGI应用-->
    from flask import Flask
    
    <!--app是Flask的实例,它接收程序主模块或包的名字作为参数,但一般都是传递__name__。-->
    app = Flask(__name__)
     
    <!--路由:使用app.route装饰器处理URL和视图函数-->
    @app.route('/')
    def index():
      return '<h1>Hello World!</h1>'
     
     <!--确保直接执行这个脚本时才启动开发Web服务器,其他文件引用该文件时(如"from hello import app"”")不会执行执行app.run函数-->
    if __name__ == '__main__':
      <!--执行app.run就可以启动服务了。默认监听127.0.0.1:5000-->
      app.run(debug=True)
      
      <!--可配置端口, 0.0.0.0表示监听所有地址,可在外部访问-->
      # app.run(debug=True, port=5001, host='0.0.0.0')
  • Flask中有两种上下文:程序上下文和请求上下文
变量名上下文说明
current_app程序上下文当前激活程序的程序实例
g程序上下文处理请求时用作临时存储对象,每次请求都会重设这个变量
request请求上下文请求对象,封装了客户端发出的HTTP请求中的内容
session请求上下文用户会话,用于存储请求之间需要“记住”的值的词典
# 一个request例子
from flask import request,Flask

app = Flask(__name__)
 
@app.route('/')
def index():
    user_agent = request.headers.get('User-Agent')
    return '<p>Your browser is %s</p>' % user_agent
    <!--Your browser is Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36-->
    
    <!--request.headers:-->
    <!--Your browser is Host: 127.0.0.1:5000 -->
    <!--Connection: keep-alive -->
    <!--Pragma: no-cache -->
    <!--Cache-Control: no-cache -->
    <!--Upgrade-Insecure-Requests: 1 -->
    <!--User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36 -->
    <!--Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 -->
    <!--Accept-Encoding: gzip, deflate, br -->
    <!--Accept-Language: zh-CN,zh;q=0.9-->
 
if __name__ == '__main__':
    app.run(debug=True)

5、模板

5.1 render_template

  • 为了渲染模板,Flask 使用了一个名为Jinja2 的强大模板引擎。
  • 默认情况下,Flask 在程序文件夹中的templates 子文件夹中寻找模板。
  • Flask 提供的render_template 函数把Jinja2 模板引擎集成到了程序中。render_template 函数的第一个参数是模板的文件名。随后的参数都是键值对,表示模板中变量对应的真实值.

    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)
      
    @app.route('/compare')
    def show_compare():
      uid_list = ['1', '2', '3', '4']
      return render_template('compare.html', uid_list=uid_list)
      
    if __name__ == '__main__':
      app.run(debug=True)

5.2 引用模板

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

{% include 'common.html' %}

5.3 定义宏

宏是Jinja2特有的,像Django则没有这个。

  • 定义宏:

    {% macro 名称() %}
    代码块
    {% endmacro %}
  • 调用:{{ 宏名称() }}

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>宏</title>
      {% macro input(type='text', name='', placeholder='', value='') %}
          <input type="{{ type }}", name="{{ name }}", placeholder="{{ placeholder }}", value="{{ value }}">
      {% endmacro %}
    </head>
    <body>
      <!--若给了默认值,传参时必须用关键字参数进行传值-->
      <div>账号{{ input(placeholder="请输入账号") }}</div>
      <div>密码{{ input(placeholder="请输入密码") }}</div>
      <div>{{ input(type="submit", value="提交") }}</div>
    </body>
    </html>
  • 也可以将宏封装成一个包的形式,在需要使用的时候通过导入进行调用:

    {% import 'macros/forms.html' as forms %}
    …………
    <div>账号{{ forms.input(placeholder="请输入账号")}</div>
    <div>密码{{ forms.input(placeholder="请输入密码") }}</div>
    <div>{{ forms.input(type="submit", value="提交") }}</div>
  • 若forms.html文件有多个宏定义时:

    {% from 'macros/forms.html' import input %}
    <!--或者-->
    {% from 'macros/forms.html' import input as input_field%}

5.4 模版的继承

  • 定义基模板:如base.html,block标签定义的元素可在衍生模板中修改。在本例中,我们定义了名为head、title 和body 的块。注意,title 包含在head 中。

    <html>
    <head>
      {% block head %}
          <title>{% block title %}{% endblock %} - My Application</title>
      {% endblock %}
      
      {% block style %}{% endblock %}
    </head>
    <body>
      {% block body %}{% endblock %}
      {% block content %}{% endblock %}
    </body>
    </html>
  • 定义衍生模板:extends指令声明这个模板衍生自base.html。在extends 指令之后,基模板中的3个块被重新定义,模板引擎会将其插入适当的位置。注意新定义的head块,在基模板中其内容不是空的,所以使用super() 获取原来的内容。

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

5.5 过滤器

Jinja2 提供的部分常用过滤器,例: Hello, {{ name|capitalize }}

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

6、Flask语法

6.1 条件控制语句

{% set a = true %}
{% set b = false %}
{% if user or a %} 
    Hello, {{ user }}!  
{% elif not a and not b%}
    Hello, Stranger!
{% else %}
    Hello, Stranger2!
{% endif %}

<li {% if caption == active_page %} class="active" {% endif  %}>
    <a href={{ href }}>{{ icon|safe }} {{ caption }}</a>
</li>

6.2 for循环语句

页面上,每个元素之间会有空格,如果你不希望有空格,就要在for语句的最后,和endfor语句的最前面各加上一个-号。

<!--example1-->
{% set digits=[1,2,3,4,5] %}
{% for digit in digits -%}
    {{ digit }}
{%- endfor %}

<!--example2-->
{% set compare_list = [
    ('112121;23232323', {'112121':'施耐德1', '32432432':'施耐德2', '1wewew':'施耐德3'}, '2012'),
    ('22232323;232323232', {'112121':'施耐德1', '1wewew':'施耐德2'}, '2013'),
    ('32323223;2323232', {'112121':'施耐德1', '32432432':'施耐德2', '1wewew':'施耐德3'}, '2014'),
    ('423232323;232323323', {'112121':'施耐德1', '1wewew':'施耐德2'}, '2015')
] -%}
{% for id, hids, submission_date in compare_list %}
{% set outer_loop = loop %}
    <tbody>
    {% for uid in hids %}
    <tr>
        {% if loop.first %}
            <td style="vertical-align:middle" rowspan="{{ hids | length + 1 }}">{{ outer_loop.index }}</td>
            <td style="vertical-align:middle" rowspan="{{ hids | length + 1 }}">{{ submission_date }}</td>
        {% endif %}
        <td>NOE77102</td>
        <td class="{% if loop.first %}active{% endif %}">PLC</td>
        <td>{{ hids[uid] }}</td>
        <td>kernel</td>
        <td>1.1.0</td>
        <td><font face="courier" style="font-size:12px">{{uid}}</font></td>
        {% if loop.first %}
            <td style="vertical-align:middle" rowspan="{{ hids | length + 1 }}">
                <a href="/compare/{{ id }}" class="glyphicon glyphicon-search text-info">查看</a>
            </td>
        {% endif %}
    {% endfor %}
    </tr>
{% else %}
    <h2>数据库中没有比较结果!</h2>
    </tbody>
{% endfor %}

Jinja2的循环内置变量主要有以下几个:

变量内容
loop.index循环迭代计数(从1开始)
loop.index0循环迭代计数(从0开始)
loop.revindex循环迭代倒序计数(从len开始,到1结束)
loop.revindex0循环迭代倒序计数(从len-1开始,到0结束)
loop.first是否为循环的第一个元素
loop.last是否为循环的最后一个元素
loop.length循环序列中元素的个数
loop.cycle在给定的序列中轮循,如上例在”odd”和”even”两个值间轮循
loop.depth当前循环在递归中的层级(从1开始)
loop.depth0当前循环在递归中的层级(从0开始)
  • 如果你启用了"jinja2.ext.loopcontrols"扩展的话,你还可以在循环中使用{% break %}{% continue %}来控制循环执行。

6.3 路由规则

from flask import Flask,redirect,url_for
 
app = Flask(__name__)

# 变量规则
@app.route('/user/<username>')
def show_user_profile(username):
    return 'User %s' % username

@app.route('/post/<float:post_id>')
def show_post(post_id):
    return 'Post %d' % post_id

# 构造 URL
@app.route('/')
def index(): pass

@app.route('/login')
def login(): pass

@app.route('/user/<username>')
def profile(username): pass

with app.test_request_context():
    # /
    print(url_for('index'))
    # / login
    print(url_for('login'))
    # / login?next=%2
    print(url_for('login', next='/'))
    # /user/John%20Doe
    print(url_for('profile', username='John Doe')) 
    
if __name__ == '__main__':
app.run(debug=True)

6.4 重定向redirect和反向解析url_for

redirect()的参数location,表示具体的url路径;
url_for反向解析,可以让重定向直接定位到具体的视图函数,让代码不冗余,扩展性更强。

from flask import Flask,redirect,url_for
 
app = Flask(__name__)
 
@app.route('/')
def index():
    return redirect('http://www.double12.com')
 
# 反向解析:建议使用url_for实现页面重定向  
@app.route('/demo')
def demo_url_for():
    return redirect(url_for('index'))

if __name__ == '__main__':
    app.run(debug=True)

7、其他

7.1 定义错误页面

与视图函数类似,只不过使用不同的修饰器@app.errorhandler(error_code)

@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404
@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500

7.2 引用静态文件

  • 默认设置下,Flask 会在程序根目录中名为 static的子目录中寻找静态文件。

    <link rel="shortcut icon" href="{{ url_for('static', filename='logo_ico.png') }}">
    <link rel="stylesheet" type="text/css" href="{{ url_for('static',filename='bootstrap/css/bootstrap.css') }}">
    <script type="text/javascript" src="{{ url_for('static',filename='bootstrap/js/bootstrap.min.js') }}"></script>
    <img id="map_img" src="{{url_for('.static', filename='Pacman.gif')}}""/>

7.3 忽略模板语法

有时候,我们在页面上就是要显示”{{ }}”这样的符号怎么办?Jinja2提供了”raw”语句来忽略所有模板语法。

{% raw %}
    <ul>
    {% for item in items %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
{% endraw %}

7.4 赋值

使用set关键字给变量赋值:{% set items = [[1,2],[3,4,5]] %}

7.5 with语句

类似于Python中的with关键字,它可以限制with语句块内对象的作用域:

<!--使用with关键字前要启用`jinja2.ext.with_`扩展,在Flask框架中,这个扩展默认已启用-->
{% with foo = 1 %}
    {% set bar = 2 %}
    {{ foo + bar }}
{% endwith %}
{# foo and bar are not visible here #}


{% with arr = ['Sunny'] %}
  {{ arr.append('Rainy') }} <!--页面会输出”None”,换成”{% %}”来执行,程序会报错,因为这是个表达式,不是语句-->
  {{ arr }}
{% endwith %}


{% with arr = ['Sunny'] %}
  {% do arr.append('Rainy') %}  <!--启用”jinja2.ext.do”扩展。然后在模板中执行”do”语句即可-->
  {{ arr }}
{% endwith %}

7.6 pass语句

对函数不做任何处理,可通过pass关键字来进行占位,让代码不要报错先能正常运行

def userLogin(): pass
if(True): pass
for x in range(101): pass
print("程序正常执行");

风晴雪sheep
16 声望5 粉丝