Flask学习笔记

Flask学习笔记

Flask是目前最流行的Python Web框架之一

初识Flask

搭建开发环境

安装pip和Pipenv

1
2
3
$ pip --version //检查pip是否安装
$ pip install pipenv //使用pip安装Pipenv
$ pipenv install //为当前项目创建虚拟环境

如果pip install过程中下载很慢,则修改Pifile中的源为url = "https://pypi.tuna.tsinghua.edu.cn/simple/"

安装Flask

1
2
$ pipenv install flask  //安装flask
$ pipenv update flask //更新flask

Hello,Flask!

切换到当前目录

1
$ cd demos/hello

创建程序实例

1
2
from flask import Flask
app = Flask(__name__)

注册路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 简单注册路由
@app.route('/')
def index():
return '<h1>Hello, World!</h1>'


# 为视图绑定多个URL
@app.route('/hi')
@app.route('/hello')
def say_hello():
return '<h1>Hello, Flask!</h1>'


# 动态URL
@app.route('/greet', defaults={'name': 'Programmer'}) # 设置默认值
@app.route('/greet/<name>')
def greet(name):
return '<h1>Hello, %s!</h1>' % name

启动开发服务器

  1. 通过命令行
    1
    $ flask run
  2. PyCharm配置
    1. Target type:Module name(必选)
    2. Target:(必填)
    3. Additional options:–host=127.0.0.1 –port=5000(可填)
    4. FLASK_ENV:development(必填)
    5. Working directory:<工作目录>(必填)

URL与端点

  1. 使用http://127.0.0.1:1234/test/addi进行访问
  2. 如果动态路由没有设置默认值
    1
    2
    3
    4
    5
    @app.route('/test/<additional>')
    def test(additional):
    # 第一个additional是test的形参,第二个additional是URL传入进来的
    part_url = url_for('test', additional=additional) # /test/addi
    all_url = url_for('test', additional=additional, _external=True) # http://127.0.0.1:1234/test/addi
  3. 如果动态路由设置了默认值
    1
    2
    3
    4
    5
    @app.route('/test', defaults={'additional': 'default'})
    @app.route('/test/<additional>')
    def test(additional):
    part_url = url_for('test') # /test
    all_url = url_for('test', _external=True) # http://127.0.0.1:1234/test
  4. url_for是用来获取要使用某一方法的最简洁URL

模板

模板基本用法

三种定界符

  1. 语句
    1
    {% ... %}
  2. 表达式
    1
    {{ ... }}
  3. 注释
    1
    {# ... #}

语句结束标签

  1. if-else
    1
    2
    3
    4
    5
    {% if ... %}
    //if 语句
    {% else ... %}
    //else 语句
    {% endif %}
  2. for
    1
    2
    3
    {% for i in ... %}
    //for语句
    {% endfor %}

模板语法

变量名 说明
loop.index 当前迭代数(从1开始计数)
loop.index0 当前迭代数(从0开始计数)
loop.revindex 当前反向迭代数(从1开始计数)
loop.revindex0 当前反向迭代数(从0开始计数)
loop.first 如果是第一个元素,则为True
loop.last 如果是最后一个元素,则为True
loop.previtem 上一个迭代的条目
loop.nextitem 下一个迭代的条目
loop.length 序列包含的元素数量

渲染模板

使用Flask提供的渲染函数render_template()

1
2
3
4
from flask import Flask, render_template
@app.route('/watchlist')
def watchlist():
return render_template('watchlist.html', user=user, movies=movies)

模板辅助工具

上下文

  1. 自定义上下文变量

    1
    2
    3
    4
    5
    6
    {% set navigation = [{'/', 'Home'}, {'/about', 'About'}] %}

    {% set navigation %}
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
    {% endset %}
  2. 内置上下文变量

    变量 说明
    config 当前的配置对象
    request 当前的请求对象,在已激活的请求环境下可用
    session 当前的会话对象,在已激活的请求环境下可用
    g 与请求绑定的全局变量,在已激活的请求环境下可用
  3. 自定义上下文

    设置模板全局变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 1. 注册模板上下文处理函数
    @app.context_processor
    def inject_foo():
    foo = 'I am foo.'
    return dict(foo=foo)

    # 2. 添加现有函数
    app.context_processor(inject_foo)

    # 3.使用lambda简化
    app.context_processor(lambda: dict(foo='I am foo.'))

全局对象

  1. 内置全局函数
    函数 说明
    range([start, ]stop[, step]) 和Python中的range()用法相同
    lipsum(n = 5, html = True, min = 20, max = 100 生成随机文本
    dict(**item) 和Python中的dict()用法相同
    url_for() 用于生成URL的函数
    get_flashed_message() 用于获取flash消息的函数
  2. 自定义全局函数
    1
    2
    3
    4
    5
    6
    7
    # 1. 注册全局函数
    @app.template_global()
    def bar():
    return 'I am bar.'

    # 2. 添加全局函数
    @app.add_template_global(bar)

过滤器

  1. 用法
    1
    2
    3
    4
    5
    6
    7
    # 1. 对变量进行过滤
    {{ name|title }}

    # 2. 对模板进行过滤
    {% filter upper %}
    This text becomes uppercase.
    {% endfilter %}
  2. 内置过滤器
    过滤器 说明
    default(value, default_value=u”, boolean=False) 设置默认值,默认值作为参数传入,别名为d
    escape(s) 转义HTML文本,别名为e
    first(seq) 返回序列的第一个元素
    last(seq) 返回序列的最后一个元素
    length(object) 返回变量的长度
    random(seq) 返回序列中的随机元素
    safe(value) 将变量值标记为安全,避免转义
    trim(value) 清除变量值前后的空格
    max(value, case_sensitive = False, attribute = None 返回序列中的最大值
    min(value, case_sensitive = False, attribute = None 返回序列中的最小值
    unique(value, case_sensitive = False, attribute = None 返回序列中的不重复的值
    striptags(value) 清除变量值内的HTML标签
    urlize(value, trim_url_limit = None, nofollow = False, target = None, rel = None 将URL文本转换成可单击的HTML链接
    wordcount(s) 计算单词数量
    tojson(value, indent = None) 将变量值转换为JSON格式
    truncate(s, length = 255, killwords = False, end=’…’, leeway=None 截断字符串,常用于显示文章摘要,length参数设置截断的长度,killwords参数设置是否截断单词,end参数设置结尾的符号
  3. 自定义过滤器
    1
    2
    3
    4
    5
    6
    7
    8
    # 1. 注册自定义过滤器
    from flask import Markup
    @app.template_filter()
    def musical(s):
    return s + Markup(' &#9835;')

    # 2. 添加方式注册
    app.add_template_filter(musical)
  4. 在使用过滤器时,竖线符号左边的值,是过滤器函数的第一个值,其他参数可以通过添加括号传入

测试器

  1. 用法
    1
    2
    3
    4
    5
    {% if age is number %}
    {{ age * 365 }}
    {% else %}
    无效数字
    {% endif %}
  2. 内置测试器
    测试器 说明
    callable(object) 判断对象是否可被调用
    defined(value) 判断变量是否已定义
    undefined(value) 判断变量是否未定义
    none(value) 判断变量是否为None
    number(value) 判断变量是否是数字
    string(value) 判断变量是否是字符串
    sequence(value) 判断变量是否是序列,比如字符串、列表、元组
    iterable(value) 判断变量是否可迭代
    mapping(value) 判断变量是否是匹配对象,比如字典
    sameas(value, other) 判断变量与other是否指向相同的内存地址
  3. 自定义测试器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 1. 注册自定义测试器
    @app.template_test()
    def baz(n):
    if n == 'baz':
    return True
    return False

    # 2. 添加注册自定义测试器
    app.add_template_test(baz)
  4. 在使用测试器时,is的左侧是测试器函数的第一个参数(value),其他参数可以添加括号传入,也可以在右侧使用空格连接,以sameas为例:
    1
    2
    3
    {% if foo is sameas(bar) %}
    # 等同于
    {% if foo is sameas bar %}

模板环境对象

  1. 添加自定义全局对象
    1
    app.jinja_env.globals['bar'] = bar
  2. 添加自定义过滤器
    1
    app.jinja_env.filters['smiling'] = smiling
  3. 添加自定义测试器
    1
    app.jinja_env.tests['baz'] = baz

模板结构组织

局部模板

  1. 提示:为了和普通模板区分开,局部模板的命名通常以一个下划线开始
  2. 用法
    1
    2
    # 在任意位置,使用以下代码插入局部模板
    {% include '_xxx.html' %}

  1. 简单示例
    1
    2
    3
    4
    5
    6
    7
    {% macro qux(amount=1) %}
    {% if amount == 1 -%}
    I am qux.
    {%- elif amount > 1 -%}
    We are quxs.
    {%- endif %}
    {% endmacro %}
  2. 用法
    1
    2
    3
    {% from 'macros.html' import qux %}
    # ...
    {{ qux(amount = 5) }}
  3. 默认情况下,包含(include)一个局部模板会传递当前上下文到局部模板中,但是导入(import)不会。如果想要导入(import)也传递当前上下文,则需要显式地使用with context
    1
    {% from 'macros.html' import qux with context  %}

模板继承

  1. 编写基模板,通常命名为base.html或layout.html
    1
    2
    {% block head %}
    {% endblock %}
  2. 编写子模板
    1. 覆盖内容
      1
      2
      3
      4
      {% extend 'base.html' %}
      {% block head %}
      {# ... #}
      {% endblock %}
    2. 追加内容
      1
      2
      3
      4
      {% extend 'base.html' %}
      {{ super() }}
      {# ... #}
      {% endblock %}

模板进阶实践

空白控制

  1. 渲染时自动去除右边空格
    1
    {%  -%}
  2. 渲染时自动去除左边空格
    1
    {%-  %}
  3. 利用环境对象
    1
    2
    3
    4
    # 删除Jinja2语句后的第一个空行
    app.jinja_env.trim_blocks = True
    # 删除Jinja2语句所在行之前的空格和制表符
    app.jinja_env.lstrip_block = True
  4. 需要注意:宏内的空白控制行为不受trim_blockslstrip_blocks属性控制,需要手动控制

加载静态文件

  1. 默认将静态文件存储在与主脚本同级目录的static文件夹中
  2. 通过url_for('static', filename='avatar.jpg')获取到/static/avatar.jpg
  3. 添加Favicon
    1. 添加文件favicon.icostatic目录下
    2. <head>部分添加一个<link>元素
      1
      <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}">
  4. 使用宏加载静态资源
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {% macro static_file(type, filename_or_url, local=True) %}
    {% if local -%}
    {% set filename_or_url = url_for('static', filename=filename_or_url) %}
    {%- endif %}
    {% if type == 'css' -%}
    <link rel="stylesheet" href="{{ filename_or_url }}" type="text/css">
    {%- elif type == 'js' -%}
    <script type="text/javascript" src="{{ filename_or_url }}"></script>
    {%- elif type == 'icon' -%}
    <link rel="icon" href="{{ filename_or_url }}">
    {%- endif %}
    {% endmacro %}
    1
    2
    3
    4
    # 1. 加载静态资源
    static_file('css', '/css/bootstrap.min.css')
    # 2. 从CDN加载资源
    static_file('css', 'https://.../css/bootstrap.min.css', local=False)

消息闪现

  1. 使用flash()函数闪现
    1
    flash('flash message.')
  2. 使用get_flashed_messages()在模板中获取消息
    1
    2
    3
    {% for message in get_flashed_messages() %}
    <div class="alert">{{ message }}</div>
    {% endfor %}

自定义错误页面

1
2
3
4
from flask import Flask, render_template
@app.errorhandler(404)
def page_not_found(e):
return render_template('errors/404.html'), 404

JavaScript和CSS中的Jinja2

  1. 定义为JavaScript变量
    1. 定义
      1
      <span data-id="{{ user.id }}" data-username="{{ user.username }}">{{ user.username }}</span>
    2. 使用
      1
      2
      3
      element.dataset.username
      element.getAttribute('data-username')
      $element.data('username')
  2. 定义为CSS变量
    1. 定义
      1
      2
      3
      4
      5
      6
      <style>
      :root {
      --theme-color: {{ theme_color }};
      --background-url: {{ url_for('static', filename='background.jpg') }}
      }
      </style>
    2. 使用
      1
      2
      3
      4
      5
      6
      7
      #foo {
      color: var(--theme-color);
      }

      #bar {
      background: var(--background-url);
      }

评论