Flask框架的基础知识有哪些?

2026-05-22 11:141阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计4578个文字,预计阅读时间需要19分钟。

Flask框架的基础知识有哪些?

目录 + Flask 框架 + 一、简介 + 框架简介 + 架构模式 + 环境搭建 + 二、第一个应用 + 三、框架语法 + 框架配置 + 路由 + 添加路由 + 反向生成 + 路由系统 + 路由参数

目录
  • Flask 框架
    • 一、 简介
      • 1、 框架介绍
      • 2、 架构模式
      • 3、 环境搭建
    • 二、 第一个应用
    • 三、 框架语法
      • 1、 框架之配置
      • 2、 框架之路由
        • 2.1 添加路由
        • 2.2 反向生成
        • 2.3 路由系统
        • 2.4 路由参数
        • 2.5 添加装饰器
          • 2.5.1 FBV
          • 2.5.2 CBV
      • 3、 请求与响应
      • 4、 模板引擎
        • 1、 变量
        • 2、 继承
      • 5、 session
        • 5.1 源码分析
        • 5.2 基本使用
        • 5.3 过期时间
      • 6、 请求拓展
      • 7、 框架之闪现
      • 8、 中间件
      • 9、 蓝图
        • 9.1 分区式架构
          • 9.1.1 目录结构
          • 9.1.2 代码实现
          • 9.1.3 访问
        • 9.2 功能式架构
          • 9.2.1 目录结构
          • 9.2.2 代码实现
      • 10、 文件上传
    • 四、 上下文管理
      • 1、 Local对象
        • 1.1 threading.local
        • 1.2 基于函数
        • 1.3 基于对象
      • 2、 上下文管理阶段
      • 3、 g

Flask 框架 一、 简介 1、 框架介绍

Flask是一个基于Python并且依赖于Jinja2模板引擎和Werkzeug WSGI 服务的一个微型框架
WSGI :Web Server Gateway Interface(WEB服务网关接口),定义了使用python编写的web app与web server之间接口格式

其他类型框架:

  1. Django:比较“重”的框架,同时也是最出名的Python框架。包含了web开发中常用的功能、组件的框架(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType....),Django是走大而全的方向,最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。

  2. Tornado:大特性就是异步非阻塞、原生支持WebSocket协议;

  3. Flask: 一个轻量级的基于 Python 的 Web 框架

  4. Bottle:是一个简单高效的遵循WSGI的微型python Web框架。说微型,是因为它只有一个文件,除Python标准库外,它不依赖于任何第三方模块。

2、 架构模式

Flask的架构模式-MTV

  1. 经典三层结构 :MVC模式
    • M :Models ,模型层,负责数据库建模
    • V :Views,视图层,用于处理用户显示的内容,如 :html
    • C :Controller,控制器,处理与用户交互的部分内容。处理用户的请求并给出响应
  2. python常用:MTV模式
    • M :Models ,模型层,负责数据库建模
    • T :Templates ,模板层,用于处理用户显示的内容,如:html
    • V :Views ,视图层,处理与用户交互的部分内容。处理用户的请求并给出响应
3、 环境搭建
  1. 安装

    pip install flask

  2. 创建工作目录

    mkdir first_dir # 创建工作目录 mkdir first_dir/static # 创建存放图片、css等不需要动态生成的静态文件 mkdir first_dir/templates # 创建存放响应文本的模板文件夹 touch first_dir/app.py # 主程序

  3. app.py中添加

    from flask import Flask app = Flask(__name__) @app.route('/') # Flask路由 def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run() # 运行网站

    主程序会默认访问templatesstatic文件夹,如果,存放web文件的文件夹名称不是这两个,那么要在实例化Flask路由时,声明

flask中文网:flask.net.cn/

如果对一些语法有疑问,可以自行访问官网去查看

二、 第一个应用

主程序代码

from flask import (Flask, render_template , request, redirect, session) app = Flask(__name__) # 创建一个服务器 app.secret_key = "ashdjhfcasjcvbgjs" # 设置盐,对session信息进行加密,随机字符串 app.debug = True # 当文件保存时,flask服务就重启 USER_DICT = { "1": {"name": "李华", "age": 12}, "2": {"name": "李虎", "age": 13}, } # 假设这个为用户数据,其为从数据库中读取出来的 @app.route('/login', methods=["GET", "POST"]) def hello_world(): if request.method == "GET": # 如果请求方式为get请求 return render_template("login.html") # 对静态文件中的文件进行渲染 user = request.form.get("user") # 得到表单数据 pwd = request.form.get("pwd") if user == "kun" and pwd == "123": # 进行判断 # 用户信息放入session中,默认放入浏览器的cookie中 session["user_info"] = user return redirect("/index") # 进行重定向 return render_template("login.html", msg="账号或密码错误,登录失败") # 如果登录失败,将失败信息传入前端页面中 @app.route("/detail") def detail(): user_info = session.get("user_info") if not user_info: # 判断是否登录 return redirect("/login") # 如果没有登录,重定向到登录界面 uid = request.args.get("uid") # 获取传入的参数 info = USER_DICT.get(uid) # 获取人员信息 return render_template("detail.html", info=info) # 进行页面的渲染 @app.route("/index") def index(): user_info = session.get("user_info") if not user_info: # 如果没有用户信息,则返回登录页面 return redirect("/login") return render_template("index.html", user_dict=USER_DICT) @app.route("/loginout") def loginout(): del session["user_info"] # 删除cookies信息,进行注销操作 return redirect("/login") # 重定向到登录页面 @app.route("/") def red(): # 如果直接访问的话,默认跳转到登录界面 return redirect("/index") # 进行url的跳转 if __name__ == '__main__': app.run()

代码详情在:

三、 框架语法

参考文档:

1、 框架之配置

# flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为: { 'DEBUG': get_debug_flag(default=False), # 是否开启Debug模式 'TESTING': False, # 是否开启测试模式 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), 'USE_X_SENDFILE': False, 'LOGGER_NAME': None, 'LOGGER_HANDLER_POLICY': 'always', 'SERVER_NAME': None, 'APPLICATION_ROOT': None, 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), 'TRAP_BAD_REQUEST_ERRORS': False, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': ':memory:' class ProductionConfig(Config): DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): DEBUG = True class TestingConfig(Config): TESTING = True PS: 从sys.path中已经存在路径开始写 PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录 """

具体的配置参数请通过官方文档获取

2、 框架之路由 2.1 添加路由

# 第一种 @app.route('/') def hello_world(): return 'Hello World!' # 第二种 def index(): return "index" app.add_url_rule("/index", None, index) 2.2 反向生成

from flask import Flask, url_for, redirect app = Flask(__name__) @app.route('/') def hello_world(): index_ = url_for("i") # 返回i对应的路由 print(index_) # 可以进行重定向 return redirect(index_) # 进行重定向 @app.route("/index/asdhjaskdg/sad", endpoint="i") # endpoint默认为函数名 def index(): return "index" if __name__ == '__main__': app.run() 2.3 路由系统

  • @app.route('/user/<username>'):传递字符串类型的数据
  • @app.route('/post/<int:post_id>'):传递整型数据
  • @app.route('/post/<float:post_id>'):传递浮点类型数据
  • @app.route('/post/<path:path>'):传递路径
  • @app.route('/<object:object>'):传递自定义数据类型

from flask import Flask, url_for from werkzeug.routing import BaseConverter app = Flask(import_name=__name__) # 1.定义自己的转换器 class RegexConverter(BaseConverter): # map是固定的参数,将整个列表进行带入,regex是写入的参数,添加进新的转换器类型 def __init__(self, map, regex): # 调用父类的初始化方法 super(RegexConverter, self).__init__(map) self.regex = regex def to_python(self, value): # 路由匹配时,匹配成功后传递给视图函数中参数的值 return int(value) def to_url(self, value): # 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 val = super(RegexConverter, self).to_url(value) print(val) return val # 2.将自定义的转换器添加到flask的应用中 app.url_map.converters['regex'] = RegexConverter @app.route('/index/<regex("\d+"):nid>') def index(nid): print(url_for('index', nid='888')) return 'Index' if __name__ == '__main__': print(app.url_map) # 查看路由信息 app.run() 2.4 路由参数

  1. rule

    • url规则
  2. voew_func

    • 视图名称
  3. defaults=None

    • 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
  4. endpoint=None

    • 名称,用于反向生成URL,即: url_for('名称')
  5. methods=None

    • 允许请求的方式,默认为GET,可以是可迭代对象,如methods=["GET", "POST"]
  6. strict_slashed=None

    • url最后的\是否有严格的要求,如

      @app.route('/index',strict_slashes=False) # 访问 www.xx.com/index/ 或 www.xx.com/index均可 @app.route('/index',strict_slashes=True) # 仅访问 www.xx.com/index

  7. redirect_to=None

    • 重定向到指定地址

      from flask import Flask app = Flask(import_name=__name__) @app.route('/index', redirect_to='/home') # 或 redirect_to=home def func(): return "index" @app.route('/home') def home(): return "home" if __name__ == '__main__': app.run()

  8. subdomain=None

    • 匹配子域名

      from flask import Flask app = Flask(import_name=__name__) @app.route("/", subdomain="<username>") # 注意,这里要使用域名才能使用 def main(username): print(username) return "hello" if __name__ == '__main__': app.run()

2.5 添加装饰器 2.5.1 FBV

from flask import Flask from functools import wraps def outer(func): @wraps(func) # 使得内层函数的函数名为传入的函数的函数名,反正重名 def inner(*args, **kwargs): print("装饰器运行") return func(*args, **kwargs) return inner app = Flask(import_name=__name__) @app.route('/') @outer # 这个装饰器可以进行登录验证 def main(): return "hello" if __name__ == '__main__': app.run()

如果要给框架另增加装饰器,一定要在路由装饰器的下面添加

2.5.2 CBV

from flask import Flask, views from functools import wraps def decorator(func): @wraps(func) def inner(*args, **kwargs): print("装饰器运行") return func(*args, **kwargs) return inner app = Flask(import_name=__name__) # CBV 一 class IndexView(views.View): methods = ["GET", "POST"] # 请求方式 decorators = [decorator, ] # 添加装饰器,可以添加多个 # dispatch_request这个名字是固定的 def dispatch_request(self): return "index" app.add_url_rule("/index_cbv", view_func=IndexView.as_view(name="index_c")) # 这里的name相当于endpoint # CBV 二 class IndexView2(views.MethodView): ''' 在views.MethodView中,相较于views.View,函数dispatch_request,已经在代码中写好了,反射getattr ''' methods = ["GET", "POST"] decorators = [decorator, ] def get(self): return "get" # get请求返回的值 def post(self): return "post" # post请求返回的值 app.add_url_rule("/index_cbv2", view_func=IndexView2.as_view(name="index_c2")) # 这里的name相当于endpoint if __name__ == '__main__': app.run() 3、 请求与响应

from flask import Flask, request, render_template, redirect, jsonify\ , make_response # 返回响应头 app = Flask(__name__) @app.route('/') def index(): """请求相关信息""" # request.method # request.args # request.form # request.values # request.cookies # request.headers # request.path # request.files # obj = request.files['the_file_name'] # obj.save('/var/www/uploads/' + secure_filename(f.filename)) """以上的是常用的""" # request.full_path # request.script_root # request.url # request.base_url # request.url_root # request.host_url # request.host """响应相关""" """ 响应头的使用 response = make_response(render_template('index.html')) # 创建响应数据 print(type(response)) response.delete_cookie('key') # 删除cookie response.set_cookie('key', 'value') # 设置cookie response.headers['X-Something'] = 'A value' return response """ return "hello world" # 可以使用json.dumps({}) / jsonify({}) 返回JSON数据 # return render_template("index.html", n1=123) # 渲染静态文件,第二个参数可以是字典解包,或者等号传参,传递给前端页面 # return redirect("/index") # 重定向 if __name__ == '__main__': app.run() 4、 模板引擎 1、 变量

index.html里面的内容

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h5>{{ k1 }}</h5> <!--可以接收字符串--> <h4>{{ k2[0] }} {{ k2[1] }}</h4> <!--可以接收可迭代对象,和字典等--> <h5>匿名函数运行的结果为:{{ k3("pwd") | safe }}</h5> <!--接收函数对象 |safe 表示该取消对文本的转义,可以渲染出来--> </body> </html>

app.py 里面的内容

from flask import Flask, render_template, Markup app = Flask(__name__) def input_(value): # 生成input标签 return Markup("<input type='text' value='%s'/>" % value) # Markup 的功能和|safe一样,使得html内容可以渲染出来,关闭对文本信息的转义,其为过滤器 @app.route('/') def index(): context = { "k1": 123, "k2": [11, 12, 13], "k3": lambda x: input_(x), } return render_template("index.html", **context) if __name__ == '__main__': app.run() 2、 继承

parent.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>父类</title> </head> <body> <div>头部</div> <div> {% block content %} <!--里面放入子类继承的内容--> {% endblock %} </div> <div>尾部</div> </body> </html>

son.html

{% extends "parent.html" %} <!--继承父类文件--> {% block content %} <!--放入要放入的内容,如果放在外部,则不会被渲染--> <h5>{{ k1 }}</h5> <h4>{{ k2[0] }} {{ k2[1] }}</h4> <h5>匿名函数运行的结果为:{{ k3("pwd") | safe }}</h5> {% endblock %}

支持多继承

更多的模板编程语法:

5、 session

除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥

字典中拥有的方法,session就拥有

5.1 源码分析

app.run()运行前,会运行app.__call__,然后返回app.wsgi_app(environ, start_response),然后通过ctx = Request_Context(app, environ)创建一个对象,在这时,使用ctx.push()方法,传入session,当请求结束后,将session序列化以后,返回到cookie里面,并且调用ctx.auto_pop(error)方法,删除ctx


"""当发起请求时""" session = session_interface.open_session(self.app, self.request) # 给session赋值 session = SecureCookieSessionInterface().open_session(self.app, self.request) session = CallbackDict() # 其为一个自定义字典对象 ---------------------------------------------------------------- """当请求结束时""" self.session_interface.save_session(self, ctx.session, response) # 将session保存到response中 SecureCookieSessionInterface().save_session(self, ctx.session, response) # 最后在SecureCookieSessionInterface()中 val = self.get_signing_serializer(app).dumps(dict(session)) # 将session序列化 response.set_cookie( name, # self.get_cookie_name(app) val, # type: ignore expires=expires, # self.get_expiration_time(app, session) localhost:5000/uploader" method="POST" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" value="提交" /> </form> </body> </html>

在主程序中

from flask import Flask, render_template, request, url_for, redirect from werkzeug.utils import secure_filename # 过滤文件的名称,反正被攻击 import os app = Flask(__name__) app.config['UPLOAD_FOLDER'] = 'upload/' # 设置上传的文件目录 @app.route('/upload') def upload_file(): return render_template('upload.html') # 对文本信息进行渲染 @app.route('/uploader', methods=['GET', 'POST']) def uploader(): if request.method == 'POST': # 如果为post请求,则为发送文件 f = request.files['file'] # 获取传递过来的文件 print(f.filename) # 打印文件 f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename))) return 'file uploaded successfully' else: return redirect(url_for("upload_file")) # 对GET请求进行重定向 if __name__ == '__main__': app.run(debug=True) 四、 上下文管理

详细介绍:

1、 Local对象 1.1 threading.local

from threading import local, Thread from time import sleep local_ = local() def task(i): # 字典,键为线程的ident作为唯一标识 local_.val = i sleep(2) print(local_.val) for i in range(10): t = Thread(target=task, args=(i,)) t.start()

作用:

  • 为每一个线程开辟一块空间进行数据存储

问题:

  • 我们自己通过字典创建一个类似于threading.local的东西
1.2 基于函数

from threading import Thread, get_ident from time import sleep storage = {} def set(k, v): ident = get_ident() if ident in storage.keys(): storage[ident][k] = v # 给ident对应的值设置为{k, v} else: storage[ident] = {k: v} # 创建ident键,并将值设置为{k, v} def get(k): ident = get_ident() try: # 如果键不存在,则返回None val = storage[ident][k] return val except KeyError: return None def task(arg): set("val", arg) sleep(2) print(get("val")) for i in range(10): t = Thread(target=task, args=(i,)) t.start() 1.3 基于对象

from threading import Thread from time import sleep try: from greenlet import getcurrent as get_ident # 获取当前协程的唯一标识 except ImportError: from threading import get_ident # 如果无法使用协程,那么继续使用线程的唯一标识 # 使其为每一个协程(线程)开辟一块空间进行数据存储 class MyLocal: def __init__(self): # data存储一个字典 # self.data = {} # 会触发__setattr__方法 object.__setattr__(self, "data", {}) # 调用父类中的__setattr__方法,避免重复调用 def __getattr__(self, k): # 实现local.key方法 ident = get_ident() try: # 如果键不存在,则返回None val = self.data[ident][k] return val except KeyError: return None def __setattr__(self, key, value): # 实现local.key = value ident = get_ident() if ident in self.data: self.data[ident][key] = value else: self.data[ident] = {key: value} local = MyLocal() def task(arg): local.val = arg # __setattr__ sleep(2) print(local.val) # __getattr__ for i in range(10): t = Thread(target=task, args=(i,)) t.start() print(local.data) 2、 上下文管理阶段

1. 第一阶段:将ctx(request, session)放到Local对象里面 - ctx = RequestContext() 2. 第二阶段:视图函数导入: - request/session 3. 第三阶段:请求处理完毕 - 获取session并保存到cookie - 将ctx删除 3、 g

与请求上下文类似,当请求进来时,先实例化一个AppContext对象app_ctx,在实例化的过程中,提供了两个有用的属性,一个是app,一个是gself.app就是传入的全局的app对象,self.g是一个全局的存储值的对象。接着将这个app_ctx存放到LocalStack()

Flask框架的基础知识有哪些?

像数据库配置这样重要的信息挂载在app对象上,一些用户相关的数据,就可以挂载在g对象上,这样就不需要在函数里一层层传递

from flask import Flask, g app = Flask(__name__) @app.before_request def auth_demo(): g.val = 123 @app.route('/') def index(): print(g.val) return "Hello World" if __name__ == '__main__': app.run(debug=True)

g对象的生命周期和当前的请求对应,当请求结束时,g对象被销毁

本文共计4578个文字,预计阅读时间需要19分钟。

Flask框架的基础知识有哪些?

目录 + Flask 框架 + 一、简介 + 框架简介 + 架构模式 + 环境搭建 + 二、第一个应用 + 三、框架语法 + 框架配置 + 路由 + 添加路由 + 反向生成 + 路由系统 + 路由参数

目录
  • Flask 框架
    • 一、 简介
      • 1、 框架介绍
      • 2、 架构模式
      • 3、 环境搭建
    • 二、 第一个应用
    • 三、 框架语法
      • 1、 框架之配置
      • 2、 框架之路由
        • 2.1 添加路由
        • 2.2 反向生成
        • 2.3 路由系统
        • 2.4 路由参数
        • 2.5 添加装饰器
          • 2.5.1 FBV
          • 2.5.2 CBV
      • 3、 请求与响应
      • 4、 模板引擎
        • 1、 变量
        • 2、 继承
      • 5、 session
        • 5.1 源码分析
        • 5.2 基本使用
        • 5.3 过期时间
      • 6、 请求拓展
      • 7、 框架之闪现
      • 8、 中间件
      • 9、 蓝图
        • 9.1 分区式架构
          • 9.1.1 目录结构
          • 9.1.2 代码实现
          • 9.1.3 访问
        • 9.2 功能式架构
          • 9.2.1 目录结构
          • 9.2.2 代码实现
      • 10、 文件上传
    • 四、 上下文管理
      • 1、 Local对象
        • 1.1 threading.local
        • 1.2 基于函数
        • 1.3 基于对象
      • 2、 上下文管理阶段
      • 3、 g

Flask 框架 一、 简介 1、 框架介绍

Flask是一个基于Python并且依赖于Jinja2模板引擎和Werkzeug WSGI 服务的一个微型框架
WSGI :Web Server Gateway Interface(WEB服务网关接口),定义了使用python编写的web app与web server之间接口格式

其他类型框架:

  1. Django:比较“重”的框架,同时也是最出名的Python框架。包含了web开发中常用的功能、组件的框架(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType....),Django是走大而全的方向,最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。

  2. Tornado:大特性就是异步非阻塞、原生支持WebSocket协议;

  3. Flask: 一个轻量级的基于 Python 的 Web 框架

  4. Bottle:是一个简单高效的遵循WSGI的微型python Web框架。说微型,是因为它只有一个文件,除Python标准库外,它不依赖于任何第三方模块。

2、 架构模式

Flask的架构模式-MTV

  1. 经典三层结构 :MVC模式
    • M :Models ,模型层,负责数据库建模
    • V :Views,视图层,用于处理用户显示的内容,如 :html
    • C :Controller,控制器,处理与用户交互的部分内容。处理用户的请求并给出响应
  2. python常用:MTV模式
    • M :Models ,模型层,负责数据库建模
    • T :Templates ,模板层,用于处理用户显示的内容,如:html
    • V :Views ,视图层,处理与用户交互的部分内容。处理用户的请求并给出响应
3、 环境搭建
  1. 安装

    pip install flask

  2. 创建工作目录

    mkdir first_dir # 创建工作目录 mkdir first_dir/static # 创建存放图片、css等不需要动态生成的静态文件 mkdir first_dir/templates # 创建存放响应文本的模板文件夹 touch first_dir/app.py # 主程序

  3. app.py中添加

    from flask import Flask app = Flask(__name__) @app.route('/') # Flask路由 def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run() # 运行网站

    主程序会默认访问templatesstatic文件夹,如果,存放web文件的文件夹名称不是这两个,那么要在实例化Flask路由时,声明

flask中文网:flask.net.cn/

如果对一些语法有疑问,可以自行访问官网去查看

二、 第一个应用

主程序代码

from flask import (Flask, render_template , request, redirect, session) app = Flask(__name__) # 创建一个服务器 app.secret_key = "ashdjhfcasjcvbgjs" # 设置盐,对session信息进行加密,随机字符串 app.debug = True # 当文件保存时,flask服务就重启 USER_DICT = { "1": {"name": "李华", "age": 12}, "2": {"name": "李虎", "age": 13}, } # 假设这个为用户数据,其为从数据库中读取出来的 @app.route('/login', methods=["GET", "POST"]) def hello_world(): if request.method == "GET": # 如果请求方式为get请求 return render_template("login.html") # 对静态文件中的文件进行渲染 user = request.form.get("user") # 得到表单数据 pwd = request.form.get("pwd") if user == "kun" and pwd == "123": # 进行判断 # 用户信息放入session中,默认放入浏览器的cookie中 session["user_info"] = user return redirect("/index") # 进行重定向 return render_template("login.html", msg="账号或密码错误,登录失败") # 如果登录失败,将失败信息传入前端页面中 @app.route("/detail") def detail(): user_info = session.get("user_info") if not user_info: # 判断是否登录 return redirect("/login") # 如果没有登录,重定向到登录界面 uid = request.args.get("uid") # 获取传入的参数 info = USER_DICT.get(uid) # 获取人员信息 return render_template("detail.html", info=info) # 进行页面的渲染 @app.route("/index") def index(): user_info = session.get("user_info") if not user_info: # 如果没有用户信息,则返回登录页面 return redirect("/login") return render_template("index.html", user_dict=USER_DICT) @app.route("/loginout") def loginout(): del session["user_info"] # 删除cookies信息,进行注销操作 return redirect("/login") # 重定向到登录页面 @app.route("/") def red(): # 如果直接访问的话,默认跳转到登录界面 return redirect("/index") # 进行url的跳转 if __name__ == '__main__': app.run()

代码详情在:

三、 框架语法

参考文档:

1、 框架之配置

# flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为: { 'DEBUG': get_debug_flag(default=False), # 是否开启Debug模式 'TESTING': False, # 是否开启测试模式 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), 'USE_X_SENDFILE': False, 'LOGGER_NAME': None, 'LOGGER_HANDLER_POLICY': 'always', 'SERVER_NAME': None, 'APPLICATION_ROOT': None, 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), 'TRAP_BAD_REQUEST_ERRORS': False, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': ':memory:' class ProductionConfig(Config): DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config): DEBUG = True class TestingConfig(Config): TESTING = True PS: 从sys.path中已经存在路径开始写 PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录 """

具体的配置参数请通过官方文档获取

2、 框架之路由 2.1 添加路由

# 第一种 @app.route('/') def hello_world(): return 'Hello World!' # 第二种 def index(): return "index" app.add_url_rule("/index", None, index) 2.2 反向生成

from flask import Flask, url_for, redirect app = Flask(__name__) @app.route('/') def hello_world(): index_ = url_for("i") # 返回i对应的路由 print(index_) # 可以进行重定向 return redirect(index_) # 进行重定向 @app.route("/index/asdhjaskdg/sad", endpoint="i") # endpoint默认为函数名 def index(): return "index" if __name__ == '__main__': app.run() 2.3 路由系统

  • @app.route('/user/<username>'):传递字符串类型的数据
  • @app.route('/post/<int:post_id>'):传递整型数据
  • @app.route('/post/<float:post_id>'):传递浮点类型数据
  • @app.route('/post/<path:path>'):传递路径
  • @app.route('/<object:object>'):传递自定义数据类型

from flask import Flask, url_for from werkzeug.routing import BaseConverter app = Flask(import_name=__name__) # 1.定义自己的转换器 class RegexConverter(BaseConverter): # map是固定的参数,将整个列表进行带入,regex是写入的参数,添加进新的转换器类型 def __init__(self, map, regex): # 调用父类的初始化方法 super(RegexConverter, self).__init__(map) self.regex = regex def to_python(self, value): # 路由匹配时,匹配成功后传递给视图函数中参数的值 return int(value) def to_url(self, value): # 使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数 val = super(RegexConverter, self).to_url(value) print(val) return val # 2.将自定义的转换器添加到flask的应用中 app.url_map.converters['regex'] = RegexConverter @app.route('/index/<regex("\d+"):nid>') def index(nid): print(url_for('index', nid='888')) return 'Index' if __name__ == '__main__': print(app.url_map) # 查看路由信息 app.run() 2.4 路由参数

  1. rule

    • url规则
  2. voew_func

    • 视图名称
  3. defaults=None

    • 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
  4. endpoint=None

    • 名称,用于反向生成URL,即: url_for('名称')
  5. methods=None

    • 允许请求的方式,默认为GET,可以是可迭代对象,如methods=["GET", "POST"]
  6. strict_slashed=None

    • url最后的\是否有严格的要求,如

      @app.route('/index',strict_slashes=False) # 访问 www.xx.com/index/ 或 www.xx.com/index均可 @app.route('/index',strict_slashes=True) # 仅访问 www.xx.com/index

  7. redirect_to=None

    • 重定向到指定地址

      from flask import Flask app = Flask(import_name=__name__) @app.route('/index', redirect_to='/home') # 或 redirect_to=home def func(): return "index" @app.route('/home') def home(): return "home" if __name__ == '__main__': app.run()

  8. subdomain=None

    • 匹配子域名

      from flask import Flask app = Flask(import_name=__name__) @app.route("/", subdomain="<username>") # 注意,这里要使用域名才能使用 def main(username): print(username) return "hello" if __name__ == '__main__': app.run()

2.5 添加装饰器 2.5.1 FBV

from flask import Flask from functools import wraps def outer(func): @wraps(func) # 使得内层函数的函数名为传入的函数的函数名,反正重名 def inner(*args, **kwargs): print("装饰器运行") return func(*args, **kwargs) return inner app = Flask(import_name=__name__) @app.route('/') @outer # 这个装饰器可以进行登录验证 def main(): return "hello" if __name__ == '__main__': app.run()

如果要给框架另增加装饰器,一定要在路由装饰器的下面添加

2.5.2 CBV

from flask import Flask, views from functools import wraps def decorator(func): @wraps(func) def inner(*args, **kwargs): print("装饰器运行") return func(*args, **kwargs) return inner app = Flask(import_name=__name__) # CBV 一 class IndexView(views.View): methods = ["GET", "POST"] # 请求方式 decorators = [decorator, ] # 添加装饰器,可以添加多个 # dispatch_request这个名字是固定的 def dispatch_request(self): return "index" app.add_url_rule("/index_cbv", view_func=IndexView.as_view(name="index_c")) # 这里的name相当于endpoint # CBV 二 class IndexView2(views.MethodView): ''' 在views.MethodView中,相较于views.View,函数dispatch_request,已经在代码中写好了,反射getattr ''' methods = ["GET", "POST"] decorators = [decorator, ] def get(self): return "get" # get请求返回的值 def post(self): return "post" # post请求返回的值 app.add_url_rule("/index_cbv2", view_func=IndexView2.as_view(name="index_c2")) # 这里的name相当于endpoint if __name__ == '__main__': app.run() 3、 请求与响应

from flask import Flask, request, render_template, redirect, jsonify\ , make_response # 返回响应头 app = Flask(__name__) @app.route('/') def index(): """请求相关信息""" # request.method # request.args # request.form # request.values # request.cookies # request.headers # request.path # request.files # obj = request.files['the_file_name'] # obj.save('/var/www/uploads/' + secure_filename(f.filename)) """以上的是常用的""" # request.full_path # request.script_root # request.url # request.base_url # request.url_root # request.host_url # request.host """响应相关""" """ 响应头的使用 response = make_response(render_template('index.html')) # 创建响应数据 print(type(response)) response.delete_cookie('key') # 删除cookie response.set_cookie('key', 'value') # 设置cookie response.headers['X-Something'] = 'A value' return response """ return "hello world" # 可以使用json.dumps({}) / jsonify({}) 返回JSON数据 # return render_template("index.html", n1=123) # 渲染静态文件,第二个参数可以是字典解包,或者等号传参,传递给前端页面 # return redirect("/index") # 重定向 if __name__ == '__main__': app.run() 4、 模板引擎 1、 变量

index.html里面的内容

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <h5>{{ k1 }}</h5> <!--可以接收字符串--> <h4>{{ k2[0] }} {{ k2[1] }}</h4> <!--可以接收可迭代对象,和字典等--> <h5>匿名函数运行的结果为:{{ k3("pwd") | safe }}</h5> <!--接收函数对象 |safe 表示该取消对文本的转义,可以渲染出来--> </body> </html>

app.py 里面的内容

from flask import Flask, render_template, Markup app = Flask(__name__) def input_(value): # 生成input标签 return Markup("<input type='text' value='%s'/>" % value) # Markup 的功能和|safe一样,使得html内容可以渲染出来,关闭对文本信息的转义,其为过滤器 @app.route('/') def index(): context = { "k1": 123, "k2": [11, 12, 13], "k3": lambda x: input_(x), } return render_template("index.html", **context) if __name__ == '__main__': app.run() 2、 继承

parent.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>父类</title> </head> <body> <div>头部</div> <div> {% block content %} <!--里面放入子类继承的内容--> {% endblock %} </div> <div>尾部</div> </body> </html>

son.html

{% extends "parent.html" %} <!--继承父类文件--> {% block content %} <!--放入要放入的内容,如果放在外部,则不会被渲染--> <h5>{{ k1 }}</h5> <h4>{{ k2[0] }} {{ k2[1] }}</h4> <h5>匿名函数运行的结果为:{{ k3("pwd") | safe }}</h5> {% endblock %}

支持多继承

更多的模板编程语法:

5、 session

除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥

字典中拥有的方法,session就拥有

5.1 源码分析

app.run()运行前,会运行app.__call__,然后返回app.wsgi_app(environ, start_response),然后通过ctx = Request_Context(app, environ)创建一个对象,在这时,使用ctx.push()方法,传入session,当请求结束后,将session序列化以后,返回到cookie里面,并且调用ctx.auto_pop(error)方法,删除ctx


"""当发起请求时""" session = session_interface.open_session(self.app, self.request) # 给session赋值 session = SecureCookieSessionInterface().open_session(self.app, self.request) session = CallbackDict() # 其为一个自定义字典对象 ---------------------------------------------------------------- """当请求结束时""" self.session_interface.save_session(self, ctx.session, response) # 将session保存到response中 SecureCookieSessionInterface().save_session(self, ctx.session, response) # 最后在SecureCookieSessionInterface()中 val = self.get_signing_serializer(app).dumps(dict(session)) # 将session序列化 response.set_cookie( name, # self.get_cookie_name(app) val, # type: ignore expires=expires, # self.get_expiration_time(app, session) localhost:5000/uploader" method="POST" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" value="提交" /> </form> </body> </html>

在主程序中

from flask import Flask, render_template, request, url_for, redirect from werkzeug.utils import secure_filename # 过滤文件的名称,反正被攻击 import os app = Flask(__name__) app.config['UPLOAD_FOLDER'] = 'upload/' # 设置上传的文件目录 @app.route('/upload') def upload_file(): return render_template('upload.html') # 对文本信息进行渲染 @app.route('/uploader', methods=['GET', 'POST']) def uploader(): if request.method == 'POST': # 如果为post请求,则为发送文件 f = request.files['file'] # 获取传递过来的文件 print(f.filename) # 打印文件 f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename))) return 'file uploaded successfully' else: return redirect(url_for("upload_file")) # 对GET请求进行重定向 if __name__ == '__main__': app.run(debug=True) 四、 上下文管理

详细介绍:

1、 Local对象 1.1 threading.local

from threading import local, Thread from time import sleep local_ = local() def task(i): # 字典,键为线程的ident作为唯一标识 local_.val = i sleep(2) print(local_.val) for i in range(10): t = Thread(target=task, args=(i,)) t.start()

作用:

  • 为每一个线程开辟一块空间进行数据存储

问题:

  • 我们自己通过字典创建一个类似于threading.local的东西
1.2 基于函数

from threading import Thread, get_ident from time import sleep storage = {} def set(k, v): ident = get_ident() if ident in storage.keys(): storage[ident][k] = v # 给ident对应的值设置为{k, v} else: storage[ident] = {k: v} # 创建ident键,并将值设置为{k, v} def get(k): ident = get_ident() try: # 如果键不存在,则返回None val = storage[ident][k] return val except KeyError: return None def task(arg): set("val", arg) sleep(2) print(get("val")) for i in range(10): t = Thread(target=task, args=(i,)) t.start() 1.3 基于对象

from threading import Thread from time import sleep try: from greenlet import getcurrent as get_ident # 获取当前协程的唯一标识 except ImportError: from threading import get_ident # 如果无法使用协程,那么继续使用线程的唯一标识 # 使其为每一个协程(线程)开辟一块空间进行数据存储 class MyLocal: def __init__(self): # data存储一个字典 # self.data = {} # 会触发__setattr__方法 object.__setattr__(self, "data", {}) # 调用父类中的__setattr__方法,避免重复调用 def __getattr__(self, k): # 实现local.key方法 ident = get_ident() try: # 如果键不存在,则返回None val = self.data[ident][k] return val except KeyError: return None def __setattr__(self, key, value): # 实现local.key = value ident = get_ident() if ident in self.data: self.data[ident][key] = value else: self.data[ident] = {key: value} local = MyLocal() def task(arg): local.val = arg # __setattr__ sleep(2) print(local.val) # __getattr__ for i in range(10): t = Thread(target=task, args=(i,)) t.start() print(local.data) 2、 上下文管理阶段

1. 第一阶段:将ctx(request, session)放到Local对象里面 - ctx = RequestContext() 2. 第二阶段:视图函数导入: - request/session 3. 第三阶段:请求处理完毕 - 获取session并保存到cookie - 将ctx删除 3、 g

与请求上下文类似,当请求进来时,先实例化一个AppContext对象app_ctx,在实例化的过程中,提供了两个有用的属性,一个是app,一个是gself.app就是传入的全局的app对象,self.g是一个全局的存储值的对象。接着将这个app_ctx存放到LocalStack()

Flask框架的基础知识有哪些?

像数据库配置这样重要的信息挂载在app对象上,一些用户相关的数据,就可以挂载在g对象上,这样就不需要在函数里一层层传递

from flask import Flask, g app = Flask(__name__) @app.before_request def auth_demo(): g.val = 123 @app.route('/') def index(): print(g.val) return "Hello World" if __name__ == '__main__': app.run(debug=True)

g对象的生命周期和当前的请求对应,当请求结束时,g对象被销毁