配置文件

配置文件导入原理

import importlib


path = "settings.DevelopmentConfig"

p, c = path.rsplit('.', maxsplit=1)
m = importlib.import_module(p)
cls = getattr(m, c)


# 如何根据cls这个类获取到类中的静态字段

for key in dir(cls):
    if key.isupper():
        print(key, getattr(cls, key))
import datetime


class Config(object):
    TESTING = False
    PROPAGATE_EXCEPTIONS = None
    PRESERVE_CONTEXT_ON_EXCEPTION = None
    SECRET_KEY = None
    PERMANENT_SESSION_LIFETIME = datetime.timedelta(days=31)
    USE_X_SENDFILE = False
    SERVER_NAME = None
    APPLICATION_ROOT = '/'
    SESSION_COOKIE_NAME = 'session'
    SESSION_COOKIE_DOMAIN = None
    SESSION_COOKIE_PATH = None
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SECURE = False
    SESSION_COOKIE_SAMESITE = None
    SESSION_REFRESH_EACH_REQUEST = True
    MAX_CONTENT_LENGTH = None
    SEND_FILE_MAX_AGE_DEFAULT = datetime.timedelta(seconds=43200)
    TRAP_BAD_REQUEST_ERRORS = None
    TRAP_HTTP_EXCEPTIONS = False
    EXPLAIN_TEMPLATE_LOADING = False
    PREFERRED_URL_SCHEME = 'http'
    JSON_AS_ASCII = True
    JSON_SORT_KEYS = True
    JSONIFY_PRETTYPRINT_REGULAR = False
    JSONIFY_MIMETYPE = 'application/json'
    TEMPLATES_AUTO_RELOAD = None
    MAX_COOKIE_SIZE = 4093


class ProductionConfig(Config):
    DEBUG = False


class DevelopmentConfig(Config):
    DEBUG = True

app.config.from_object 导入配置信息

app.py 中可以使用按需修改后settings.py 中的配置信息

from flask import Flask

app = Flask(__name__)

app.config.from_object("settings.DevelopmentConfig")

路由系统

  • endpoint="n1" 相当于 django 路由系统 url 中的 name 起别名进行反向解析
  • 如果不写 endpoint="..." 则默认为:url_for("index") 视图函数名称 index
  • flask 路由反向解析用的是 url_for("n1")
  • 动态路由
    • /<int:nid> 动态接收 id 值(int类型),可以传参
    • /<nid> 未定义类型则默认接收 string 字符串类型
from flask import Flask
from flask import url_for


@app.route('/index/<int:nid>', methods=["GET", "POST"], endpoint="n1")
# endpoint="n1" 相当于 django 路由系统 url 中的 name 起别名进行反向解析
# 如果不写 endpoint="..." 则默认为:url_for("index") 视图函数名称 index
# flask 路由反向解析用的是 url_for("n1")

# 动态路由
# '/<int:nid>' 动态接收 id 值(int类型),可以传参
# '/<nid>' 未定义类型则默认接收 string 字符串类型
def index(nid):
    print(url_for("n1", nid=1))
    # /index/1
    return "Index"

视图

FBV 模式

import functools
from flask import Flask
from flask import render_template
from flask import request
from flask import redirect
from flask import session
from flask import url_for
from flask import Markup
from flask import flash
from flask import get_flashed_messages

app = Flask(__name__)
app.config.from_object("settings.DevelopmentConfig")

# 模拟数据库中存储的用户
STUDENT_DICT = {
    1: {'name': '小明', 'age': 18, 'gender': '男'},
    2: {'name': '小李', 'age': 19, 'gender': '男'},
    3: {'name': '小花', 'age': 17, 'gender': '女'},
}


# def auth(func):
#     # '@functools.wraps(func)' 加上这个装饰器,可以避免被装饰的函数名变为'inner'
#     @functools.wraps(func)
#     def inner(*args, **kwargs):
#         if not session.get('user'):
#             return redirect(url_for('login'))
#         ret = func(*args, **kwargs)
#         return ret
#     return inner


# 被'@app.before_request' 此装饰器装饰的业务逻辑会在所有视图函数执行之前执行
# 跟 'django' 的 'process_request' 极为相似
# 当被此装饰器装饰的业务逻辑有返回值时,整个flask框架中的所有视图函数都不会被执行
# 直接显示 "被此装饰器装饰的业务逻辑的返回值"
@app.before_request
def auth():
    if request.path == '/login':
        return None
    if session.get('user'):
        return None
    return redirect(url_for('login'))


# 被此全局模板函数装饰器所装饰的业务逻辑,不需要借助任何视图函数传递此方法给模板,
# 此方法会自动传递到需要应用此方法的模板中!
# 模板只需要调用即可 {{global_template_func(1, 2)}} 即可在页面相应的位置显示出 3
@app.template_global()
def global_template_func(a, b):
    return a + b


# {{ 1|filter_template_func(2, 3) }}
# 页面显示 6
@app.template_filter()
def filter_template_func(a, b, c):
    return a + b + c


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        user = request.form.get('user')
        password = request.form.get('password')
        if user == 'aliang' and password == '007':
            session['user'] = user
            return redirect(url_for('index'))
        return render_template('login.html', error='用户名或密码错误!')
    return render_template('login.html')


@app.route('/index')
# @auth
def index():
    return render_template('index.html', stu_dic=STUDENT_DICT)


@app.route('/delete/<int:nid>')
# @auth
def delete(nid):
    del STUDENT_DICT[nid]
    return redirect(url_for('index'))


@app.route('/detail/<int:nid>')
# @auth
def detail(nid):
    info = STUDENT_DICT[nid]
    return render_template('detail.html', info=info)


def func(arg):
    return arg + 1


@app.route('/tpl')
def tpl():
    context = {
        'users': ['小明', '小李', '小花'],
        # 'txt': "<input type='text' />",
        'txt': Markup("<input type='text' />"),
        'func': func
    }
    return render_template('tpl.html', **context)


@app.route('/page1')
def page1():
    flash('存储临时数据')

    return "Session"


@app.route('/page2')
def page2():
    flash_msg = get_flashed_messages()

    return flash_msg


class Middleware(object):
    def __init__(self, origin_wsgi_app):
        self.origin_wsgi_app = origin_wsgi_app

    def __call__(self, *args, **kwargs):
        # 在请求之前做相应的业务逻辑

        ret = self.origin_wsgi_app(*args, **kwargs)

        # 在请求之后做相应的业务逻辑

        return ret


if __name__ == '__main__':
    app.wsgi_app = Middleware(app.wsgi_app)
    app.run()

请求相关

request

request.method

requestd.args

request.form

request.values

requesdt.cookies

request.headers

request.path

request.full_path

request.script_root

request.url

request.base_url

request.url_root

request.host_url

request.host

request.files

obj = request.files['the_file_name']
obj.save('/var/www/uploads/' + secure_filename(f.filename))

响应相关

return

from flask import render_template
from flask import redirect
from flask import jsonify


# 以下4种返回的数据都是请求体,能不能将请求头也返回?可以封装!

dic = {'k1': 'v1'}

# return json.dumps(dic)
# 相当于"django"中的JsonResponse
return jsonify(dic)

return "Index"

return render_template("index.html")

return redirect("/index")

封装<响应头>&<响应体>后再返回

from flask import make_response

# 将要返回的字符串"Index"封装到"make_response"中
# 设置了响应体
obj = make_response("Index")

# 设置了响应头
obj.headers['xxxx'] = 'oooo'

# 设置cookie信息
obj.set_cookie('key', 'value')

return obj

模板渲染

视图传参——>模板渲染

# app.py 文件中
from flask import Markup


def func(arg):
    return arg + 1


@app.route('/tpl')
def tpl():
    context = {
        'users': ['小明', '小李', '小花'],
        # 'txt': "<input type='text' />",
        'txt': Markup("<input type='text' />"),
        'func': func
    }
    return render_template('tpl.html', **context)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{{users.0}}
{{users[0]}}
{{txt}}
{{txt|safe}}
{{func(6)}}

</body>
</html>

@app.template_global() 全局模板函数装饰器之一

# app.py 文件中

@app.template_global()
def global_template_func(a, b):
    return (a + b)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{{global_template_func(1, 2)}}

</body>
</html>

@app.template_filter() 全局模板函数装饰器之二

# app.py 文件中

@app.template_filter()
def filter_template_func(a, b, c):
    return a + b + c
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{{1|filter_template_func(2, 3)}}

{% if 1|filter_template_func(2, 3) %}
    <div>返回值为6</div>
{% else %}
    <div>没有返回值</div>
{% endif %}

</body>
</html>

模板继承——> extends "layout.html"

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% block content%}

    {% endblock %}
</body>
</html>
{% extends "layout.html"%}

{% block content%}
    {{users.0}}
	{{users[0]}}
	{{txt}}
	{{txt|safe}}
	{{func(6)}}
{% endblock %}

模板插件导入——> include "nav.html"

......
{% extends "layout.html"%}

{% block content%}
	{% include "nav.html" %}
    {{users.0}}
	{{users[0]}}
	{{txt}}
	{{txt|safe}}
	{{func(6)}}
{% endblock %}

模板宏定义——>{% macro ...%} ... {% endmacro %}

{% macro tag(name, type='text', value='') %}
	<h1>宏定义input标签</h1>
	<input type="{{ type }}" name="{{ name }}" value="{{ value }}">
	<input type="submit" value="提交">
{% endmacro %}

{{tag("user")}}

Session

  • django 中的session信息放在数据库中

  • flask 中的session信息经过加密之后保存在用户浏览器的cookie中

利用session保存用户的登录状态

可以做权限管理

  • 方法一:每个需要登录后才可以访问的页面所对应的视图函数中都查询一次是否有session信息

  • 方法二:利用装饰器,在每个需要登录后才可以访问的页面所对应的视图函数上加装饰器,在走相应的视图函数之前先走装饰器中定义好的判断是否存在session信息的业务逻辑

    • 装饰器(应用于被装饰的视图函数较少时

      import functools
      
      
      def auth(func):
          @functools.wraps(func)  # 加上这个装饰器,可以避免被装饰的函数名变为'inner'
          def inner(*args, **kwargs):
              if not session.get('user'):
                  return redirect(url_for('login'))
              ret = func(*args, **kwargs)
              return ret
          return inner
      
      
  • 方法三:使用 '@app.before_request' 装饰器
    被'@app.before_request' 此装饰器装饰的业务逻辑会在所有视图函数执行之前执行,跟 'django' 的 'process_request' 极为相似

@app.before_request
def auth():
    if request.path == '/login':
        return None
    if session.get('user'):
        return None
    return redirect(url_for('login'))

闪现——>flash

基于session信息的设置原理封装好方法:<临时存>&<临时取>

  • flask中的session 信息是经过加密后保存在cookie中的,可以一直取,只要不过期,不手动删除,则session信息一直存在!

  • 借助 flash 存储某一临时数据 & get_flashed_messages 获取临时数据,取一次即失效

    • 临时存,临时取
    • 取出来的是列表类型的数据,第二次取得就是空列表
from flask import flash
from flask import get_flashed_messages


@app.route('/page1')
def page1():
    flash('存储临时数据')

    return "Session"


@app.route('/page2')
def page2():
    flash_msg = get_flashed_messages()

    return flash_msg

# ['存储临时数据']

分类临时存,按分类临时取

from flask import flash
from flask import get_flashed_messages


@app.route('/page1')
def page1():
    flash('存储临时数据1', '类别1')
    flash('存储临时数据2', '类别1')
    flash('存储临时数据3', '类别2')

    return "Session"


@app.route('/page2')
def page2():
    flash_msg = get_flashed_messages(category_filter=['类别1'])

    return flash_msg


# ['存储临时数据1', '存储临时数据2']

中间件

flask 框架开始执行流程

定义中间件

class Middleware(object):
    def __init__(self, origin_wsgi_app):
        self.origin_wsgi_app = origin_wsgi_app

    def __call__(self, *args, **kwargs):
        # 在请求之前做相应的业务逻辑

        ret = self.origin_wsgi_app(*args, **kwargs)

        # 在请求之后做相应的业务逻辑

        return ret


if __name__ == '__main__':
    app.wsgi_app = Middleware(app.wsgi_app)
    app.run()

特殊的装饰器

@app.before_first_request

@app.before_first_request
def excute_first():
    print("项目启动之后第一次请求到来时,会在@app.before_request装饰的业务逻辑之前仅仅执行一次")

@app.before_request

@app.before_request
def auth():
    print('请先登录!')

@app.after_request

@app.after_request
def after(response):
    print('请求已经得到响应!')
    return response

@app.template_global() 全局模板函数装饰器之一

# app.py 文件中

@app.template_global()
def global_template_func(a, b):
    return (a + b)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{{global_template_func(1, 2)}}

</body>
</html>

@app.template_filter() 全局模板函数装饰器之二

# app.py 文件中

@app.template_filter()
def filter_template_func(a, b, c):
    return a + b + c
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{{1|filter_template_func(2, 3)}}

{% if 1|filter_template_func(2, 3) %}
    <div>返回值为6</div>
{% else %}
    <div>没有返回值</div>
{% endif %}

</body>
</html>

@app.errorhandler

@app.errorhandler(404)
def not_found(error_msg):
    print(error_msg)
    return "访问的页面不存在!"
08-06 14:14