DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • Django

  • 第一次学drf

  • 第二次学drf

  • 温故知新

  • flask

    • flask使用

    • flask源码

      • 面试题
      • 快速使用
        • Flask与Django
        • Flask的安装
        • Hello World!
        • Werkzeug
        • Flask四把斧
        • 用户登陆&用户管理
        • ★ 小结
        • Flask - Session
          • ※ Token回顾
          • ※ 装饰器回顾
          • Session示例
        • 小蓝图(Blue Print)
      • 数据库链接池
      • flask的使用
      • flask上下文管理
      • 使用简记
  • 后端
  • flask
  • flask源码
DC
2024-09-19
目录

快速使用

该篇博客简单介绍下Flask的快速使用!

image-20240920152202170


# Flask与Django

Q: Flask与Django有何区别?

我们最直观的感受是, Django很大,依赖很多,迁移后会生成一大堆的表; Flask一开始很简单,但项目越来越大,东西也会越来越多!

1. Django是一个大而全的框架,Flask是一个轻量级的框架.
2. Django的内部为我们提供了非常多的组件:
   ORM、Session、Cookie、admin、form、modelform、路由、视图、模版、中间价、分页、auth、contenttype、缓存、信号、数据库连接
3. Flask框架本身没有太多的功能: 路由、视图、session、中间件
   - Flask本身没有模版,用的是三方的jinja2
   - Flask的Session 不会像Django一样, 不会将 随机字符串:用户相关信息 放在数据库中
   - Flask有非常齐全的第三方组件!!
4. ★ Django和Flask两者最大的不同在于:
   > 请求一来,Django对请求是逐一封装和传递的;在代码中体现为每个视图函数都有一个request参数;
   > 请求一来,Flask的请求是利用上下文的管理来实现的!!(简单来说,就是将请求放在某个特殊的地方,想用时自己去那里拿就行..
1
2
3
4
5
6
7
8
9
10

# Flask的安装

pip install flask

Flask        1.1.1
Click        7.0
itsdangerous 1.1.0
Jinja2       2.10.3   # - 模版
MarkupSafe   1.1.1
Werkzeug     0.16.0   # - wsgi,本质就是soket套接字层

"""
为了方便学习,我安装的是Flask1.1.1版本,安装时 它会配套安装一些依赖,默认安装的依赖版本是最新的.
这导致了这些依赖版本跟Flask1.1.1版本不匹配,运行程序时会报错.
需要按照上方的版本号重新安装这些依赖!!

pip install Flask==1.1.1
pip install Click==7.0
pip install itsdangerous==1.1.0
pip install Jinja2==2.10.3
pip install MarkupSafe==1.1.1
pip install Werkzeug==0.16.0
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# Hello World!

from flask import Flask

app = Flask(__name__)  # - 创建flask对象,里面随便写个字符串也可以,但通常会写__name__代表模块


# - 路由匹配和视图函数 (Django的路由匹配和视图函数是分开的
@app.route('/index')  # http://127.0.0.1:5000/index 能访问的; http://127.0.0.1:5000/index/ 访问不到!
def index():  # ★视图函数为啥没有request参数?因为flask的请求不像Django的请求是传递过来的,它请求是放在某地,自取
    return "hello world"  # 返回一个字符串,相当于Django里的HttpResponse


if __name__ == '__main__':
    app.run()
1
2
3
4
5
6
7
8
9
10
11
12
13

# Werkzeug

探究下 Werkzeug 这个wsgi (web服务网关接口)在flask中的作用.. <flask的源码流程也是这样的!>.
下方截图的Werkzeug程序, 仅是一个socket套接字层(完成传输层及以下的功能)
网站没有依赖flask, 但是却执行起来了, 无路由匹配, 无视图函数的处理.. 就是简单的接收请求,返回请求..

image-20240919105014988

看下Flask源码, 它就是像上面这样构造的.

image-20240920124337761

# - t1.py
from werkzeug.serving import run_simple


def func(environ, start_response):
    start_response('200 ok', [('Content-Type', 'text/html')])
    return [b'<h6>hello world!</h6>']


if __name__ == "__main__":
    run_simple('localhost', 5001, func)
    
    
# - t2.py
from werkzeug.serving import run_simple


class Flask:
    def __call__(self, environ, start_response):
        # To do:执行flask源码里的功能.
        start_response('200 ok', [('Content-Type', 'text/html')])
        return [b'<h6>hello world!</h6>']


app = Flask()

if __name__ == "__main__":
    run_simple('localhost', 5002, app)


# - t3.py
from werkzeug.serving import run_simple


class Flask:
    def __call__(self, environ, start_response):
        # To do:执行flask源码里的功能.
        start_response('200 ok', [('Content-Type', 'text/html')])
        return [b'<h6>hello world!</h6>']

    def run(self):
        run_simple('localhost', 5003, self)


app = Flask()

if __name__ == "__main__":
    app.run()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

★ So, 注意两点:
-1- flask框架是基于Werkzeug这个wsgi实现的, flask本身跟Django一样是没有wsgi的.
-2- 用户请求一来, 就会执行 flask对象所在的Flask类中的 __call__ 方法, 该方法中会进行 路由匹配、运行视图函数等步骤..


# Flask四把斧

image-20240919120957036

from flask import Flask, render_template, jsonify, redirect

# template_folder默认值就是templates,意味着jinja2默认会去templates目录下找对应的html文件,当然你可以自定义
app = Flask(__name__, template_folder="templates")


@app.route('/test1')
def test1():
    return "hello world"  # 返回一个字符串,相当于Django里的HttpResponse


@app.route('/test2')
def test2():
    return render_template('login.html')  # 返回一个模版,相当于Django里的render


@app.route('/test3')
def test3():
    return jsonify({'code': 200, 'data': [1, 2, 3]})  # 返回一个json字符串,相当于Django里的JsonResponse


@app.route('/test4')
def test4():
    return redirect('/test2')  # 重定向,相当于Django里的redirect


if __name__ == '__main__':
    app.run()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 用户登陆&用户管理

这是个最最最简单的程序,工作中不会遇到比这个还要简单的需求了..emmm

需求:

-1- GET请求访问登陆页面, 填写表单信息后, POST请求到当前路由/url, 对用户名密码进行验证.
若正确, 则登陆成功, 重定向跳转到首页; 若不正确, 携带错误信息重新访问登陆页面!!
-2- GET请求首页循环展示出所有用户信息
-3- 点击编辑按钮, GET请求携带 当前编辑的用户信息 访问修改页面 并将信息呈现在页面上..
在页面上修改后, 点击提交, POST请求到当前路由/url(依旧是这个视图函数), 视图执行修改逻辑, 重定向到首页..
-4- 点击删除按钮, 直接删除, 重定向到首页..

PS: 该示例没有用数据库, 用data_dict字典充当数据库了..

image-20240919151013301

☆注意点:

- @app.route() 若不写methods参数,那么装饰的视图函数仅支持GET请求!当post请求时会报错: Method Not Allowed
- command+B点进去看render_template函数
  >> def render_template(template_name_or_list, **context):...
  你可以发现有个参数是 **context , 因而 我们传递错误信息时,若以字典形式传递则需要拆包!!还可以用关键字参数的形式传递 error=error
- 在模版中
  字典取键值对, Django的模版 data_dict.items 不加括号; flask模版中 data_dict.items() 需要加括号
  字典取值, Django的模版 v.name ; flask模版中 v.name、v["name"]、v.get('name',"未知") 皆可
- 编辑和删除时,构建a标签跳转的url,需传递nid表明编辑修改的是哪一条数据,有两种方式
  1> ?params  视图函数中通过 request.args 取到的nid的值是 str 类型!(因为是通过网络传过来的嘛
  2> 路由传参  <int:nid> 表明接收一个值,内部会转换成int类型
- request.form 对标 request.POST
  request.args 对标 request.GET
- flask也有name反向解析 endpoint + url_for 搭配使用, endpoint参数默认值就是视图函数名,注意endpoint不要重名!!
- 在form标签里没有写action,表明向 当前页面/当前url 提交!
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# ★ 小结

至此, 我们学到了哪些flask知识点?

◎ flask路由

@app.route('/login', methods=['GET', 'POST'], endpoint='login')
def login():pass

- ★ flask的路由是装饰器
- 三个参数 url methods endpoint
  注意,endpoint不写,其默认值就是视图函数名; ★ endpoint不要重名!!
1
2
3
4
5
6

◎ 动态路由

@app.route('/delete/<nid>')  # nid值的类型是str  <a href="/delete/{{ k }}">删除</a>
def delete(nid):pass

@app.route('/delete/<int:nid>')  # nid值的类型是int  <a href="/delete/{{ k }}">删除</a>
def delete(nid):pass
1
2
3
4
5

◎ 获取用户传递的数据 - 两类: url传递 + 请求体传递

from flask import request

@app.route('/login')
def login():
    request.args  # GET形式传递的数据 - ?params  <a href="/delete?nid={{ k }}">删除</a>
    request.form  # POST形式传递的数据 - 请求体数据
1
2
3
4
5
6

◎ 视图返回数据

from flask import Flask, render_template, jsonify, redirect, url_for

@app.route('/login')
def login():
    return "hello world"
    return render_template('login.html')
    return redirect('/index')  #  return redirect(url_for('index'))
    return jsonify({'code': 200, 'data': [1, 2, 3]})
1
2
3
4
5
6
7
8

◎ 模版处理

{{ x }}

{% for item in data_list %}
    {{ item }}
{% endfor %}

flask的模版中的注释
<!-- <td>{{  key  }}</td> --> 不生效!!
{# <td>{{  key  }}</td> #} 生效!!
1
2
3
4
5
6
7
8
9

# Flask - Session

# ※ Token回顾

☆ 简单回顾下 Django的cookie、session、jwt

Http请求是无状态的短链接,一问一答. 
需求:有些页面登录成功后才能访问,服务端怎么知道你是否已经登录呢?/怎么知道你是谁呢?
  
★ 首先明确一点:Token是一种思想,实现用户会话信息保存的技术都可叫作Token.
  Token大抵分为两类,一类是将用户信息保存在浏览器里的cookie技术;一类是将用户信息保存在服务端里的Session技术!!
 (jwt token可划分到cookie这一类中
  
- cookie
  登陆,用户名密码匹配成功,将用户信息后返回给浏览器,浏览器将其保存在cookies中 >>  name:dc
  浏览器访问其他页面时,会携带cookies信息,服务端拿到cookies信息后,取出里面的用户信息就知道是谁登陆了.
  - 缺点: cookie最多支持4k;用户信息在客户端,与session比相对不安全;
    注意: 
         上述是最最简单的cookie流程,这么做我们很容易伪造其它人登陆,为了增加安全性,我们通常可以这么做:
         1. 服务端 sha256(用户信息 + 盐) 生成 签名, base64(用户信息)和签名组成cookie给浏览器.
         2. 服务端 取出cookie中的 用户信息解密后, 用同样的方式 生成一个签名 与 cookie中的签名进行比对!
         >> 通过验证签名来确保 Cookie 的完整性和有效性!!!
    PS:加盐 - 在密码任意固定位置插入特定字符串,有效防止黑客暴力破解用户ID和密码!!

- session
  登陆,用户名密码匹配成功,执行语句 request.session['username'] = "dc" 
  该语句底层会让 服务端生成一个随机字符串 并保存到数据库中 >> 随机字符串:该用户的信息(会加密)
  这个随机字符串还会一并返回给浏览器,浏览器会将其保存在cookies中 "session_id":随机字符串
  浏览器访问其他页面时,会携带cookies信息; 服务端取到随机字符串,去数据库对比,将保存的对应用户信息解密并赋值给request.session
  - 优点: 用户信息在服务端,相对更安全
  - 缺点: 占有服务器存储空间

- jwt
  简单来说, jwt有三段 base64(header)--base64(payload)--SHA256(header + "." + payload , 盐)
  然后验证 拿到第一段和第二段后以同样的方式加盐加密,与第三段进行比较!!
  - 优点: 计算换资源嘛 而且就算被截获了,黑客改了payload里的用户信息,验证时肯定也是通过不了的,安全性高!!
  - 缺点: 不到期jwtToken不失效
    
    
- 前后端分离,前端存数据的三个地方
  1. sessionStorage - 临时存储, 浏览器关闭或关闭标签页 就没啦!  
  2. localStorage   - 永久存储, 除非手动清理/浏览器存储空间满了!  
  3. cookie         - 有个过期时间, 过期时间一到就没啦! + 发送请求时会自动携带它.
  

思考:首先要清楚session也是基于cookie来使用的,浏览器的cookie何时失效? 
    - 若没有设置过期时间,即为会话cookie,关闭浏览器,浏览器上的cookie消失; 会话cookie一般保存在内存里.
    - 若设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再打开浏览器,这些cookie依然有效直到超过设定的过期时间.
    
思考:用户的浏览器禁用cookie,如何实现Token呢? 
    浏览器拿到后端给的Token,有三个地方可以存. 若禁用cookie,浏览器将Token传递给后端的方式有两种:
    - 将Token放到url地址后面, 以参数的形式传递过去
    - 将Token放到请求头里传递过去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# ※ 装饰器回顾

改变func.__name__的值; 多个装饰器的执行顺序..

image-20240920103930291

清楚上面截图中的两点后, 代入Flask装饰器里!

from flask import Flask

app = Flask(__name__)

# ★ 示例代码从上往下执行,运行到@app.route('/index')
#   1. 会先取路由'/index' 2.再取装饰器装饰的函数 > 这两者作一个对应关系,路由匹配成功后,执行对应的函数
#   3. 获得被装饰函数的 __name__ 值作为反向解析的name 
@app.route('/index')
def index():
    return "hello world"


if __name__ == '__main__':
    app.run()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

若index有多个装饰器呢? 如何操作呢? 其实注意两点即可:
-1- @functools.wraps(func) -2- 新增的装饰器写在 @app.route 下面

from flask import Flask
import functools

app = Flask(__name__)


def auth(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        return func(*args, **kwargs)

    return inner


@app.route('/index')
@auth
def index():
    return "hello world"


@app.route('/order')
@auth
def order():
    return "wa o~"


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

"""
若auth装饰器不加@functools.wraps(func),运行Flask程序,会报错
AssertionError: View function mapping is overwriting an existing endpoint function: inner

两个装饰器,先auth,后app.route, [可以理解app.route装饰的是auth里的inner函数] !
若auth装饰器不加@functools.wraps(func)  
那么@app.route('/order')和@app.route('/index')的反向解析的name值皆为 inner !! 就会报错!
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Session示例

★ 首先要知道, Flask的session不同于Django的Session:
-1- Django的session, 服务端 - 数据库中随机字符串:某个用户相关信息 ; 浏览器 - Cookie中 session_id:随机字符串
-2- Flask的session, 服务端没有; 浏览器Cookie中 session:用户信息+用户信息通过secret_key加盐加密后的签名 组成的随机字符串

一句话: flask的session信息在服务端不存储, 而是通过加密的方式放在浏览器端进行存储

接下来, 简单实现一下Flask的session功能..
需求: 未登陆不能访问首页和订单页面,会自动重定向登陆页面; 登陆后跳转首页. / 即访问首页和订单页面都需要session的状态.

image-20240920134210194

from flask import Flask, render_template, redirect, request, url_for, session
import functools

app = Flask(__name__)
app.secret_key = "abcdefghijklmnop"  # ★ flask使用session,必须设置secret_key这个盐


def auth(func):
   @functools.wraps(func)
   def inner(*args, **kwargs):
       # print(session)  # <SecureCookieSession {'username': 'dc'}>
       username = session.get("username")
       if not username:
           return redirect(url_for('login'))
       return func(*args, **kwargs)

   return inner


@app.route('/order')
@auth
def order():
   return "wa o~"


@app.route('/index')
@auth
def index():
   return "Hello World!(*≧ω≦)"


@app.route('/login', methods=['GET', 'POST'])
def login():
   if request.method == 'GET':
       return render_template('login.html')
   user = request.form.get('user')
   pwd = request.form.get('pwd')
   if user == 'dc' and pwd == '123':
       session['username'] = 'dc'
       return redirect(url_for('index'))
   error = "用户名或密码错误!"
   return render_template('login.html', **{'error': error})


if __name__ == '__main__':
   app.run()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

# 小蓝图(Blue Print)

如果视图很多, 怎么搞? 都写在一个py文件中? No. 用蓝图来解决.. (下面是小蓝图,用来写中小项目绰绰有余)
(*≧ω≦) 蓝图帮我们构建业务功能可以拆分的目录结构!!

  • demo 在pycharm中创建一个python项目
    • demo 创建一个目录,与项目同名
      • __init__.py
      • static
      • templates
      • views 里面创建py文件,一个py文件就是一个小蓝图
        • one.py
        • two.py
    • manage.py

这样构建目录, 有助于我们使用flask的第三方组件!!

image-20240920141021014

# ■ manage.py
from demo import create_app

app = create_app()

if __name__ == '__main__':
    app.run()
    
    
# ■ __init__.py
from flask import Flask
from .views.one import one
from .views.two import two

def create_app():
    app = Flask(__name__)
    app.secret_key = "abcdefghijklmnop"

    @app.route('/index')  # http://127.0.0.1:5000/index
    def index():
        return 'index'

    # 注册蓝图,还可加前缀
    app.register_blueprint(one, url_prefix='/one')
    app.register_blueprint(two, url_prefix='/two')

    return app
    

# ■ one.py
from flask import Blueprint

one = Blueprint('one', __name__)

@one.route('/f1')  # http://127.0.0.1:5000/one/f1
def f1():
    return 'one-f1'

@one.route('/f2')  # http://127.0.0.1:5000/one/f2
def f2():
    return 'one-f2'

  
# ■ two.py
from flask import Blueprint

two = Blueprint('two', __name__)

@two.route('/f3')  # http://127.0.0.1:5000/two/f3
def f3():
    return 'two-f3'

@two.route('/f4')  # http://127.0.0.1:5000/two/f4
def f4():
    return 'two-f4'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

To do:
1. 使用蓝图,登陆保存会话,且用户表应放在mysql表中 - 创建数据库用pymysql连接.
2. 对数据库中的某张表进行CURD - eg:book表
3. 上传excel文件,将excel中的文件内容导入到数据库中 - 大概6行代码就可实现
4. 探究werkzeug这个wsgi的返回值,去源码中找,从Flask来的__call__开始找.
1
2
3
4
5

面试题
数据库链接池

← 面试题 数据库链接池→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式