Flask框架的基础知识有哪些?
- 内容介绍
- 文章标签
- 相关推荐
本文共计4578个文字,预计阅读时间需要19分钟。
目录 + 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 代码实现
- 9.1 分区式架构
- 10、 文件上传
- 四、 上下文管理
- 1、 Local对象
- 1.1
threading.local - 1.2 基于函数
- 1.3 基于对象
- 1.1
- 2、 上下文管理阶段
- 3、 g
- 1、 Local对象
- 一、 简介
Flask是一个基于Python并且依赖于Jinja2模板引擎和Werkzeug WSGI 服务的一个微型框架
WSGI :Web Server Gateway Interface(WEB服务网关接口),定义了使用python编写的web app与web server之间接口格式
其他类型框架:
-
Django:比较“重”的框架,同时也是最出名的Python框架。包含了web开发中常用的功能、组件的框架(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType....),Django是走大而全的方向,最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。 -
Tornado:大特性就是异步非阻塞、原生支持WebSocket协议; -
Flask: 一个轻量级的基于 Python 的 Web 框架 -
Bottle:是一个简单高效的遵循WSGI的微型python Web框架。说微型,是因为它只有一个文件,除Python标准库外,它不依赖于任何第三方模块。
Flask的架构模式-MTV
- 经典三层结构 :MVC模式
- M :Models ,模型层,负责数据库建模
- V :Views,视图层,用于处理用户显示的内容,如 :html
- C :Controller,控制器,处理与用户交互的部分内容。处理用户的请求并给出响应
- python常用:MTV模式
- M :Models ,模型层,负责数据库建模
- T :Templates ,模板层,用于处理用户显示的内容,如:html
- V :Views ,视图层,处理与用户交互的部分内容。处理用户的请求并给出响应
-
安装
pip install flask -
创建工作目录
mkdir first_dir # 创建工作目录 mkdir first_dir/static # 创建存放图片、css等不需要动态生成的静态文件 mkdir first_dir/templates # 创建存放响应文本的模板文件夹 touch first_dir/app.py # 主程序 -
在
app.py中添加from flask import Flask app = Flask(__name__) @app.route('/') # Flask路由 def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run() # 运行网站主程序会默认访问
templates和static文件夹,如果,存放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 路由参数
-
ruleurl规则
-
voew_func- 视图名称
-
defaults=None- 默认值,当URL中无参数,函数需要参数时,使用
defaults={'k':'v'}为函数提供参数
- 默认值,当URL中无参数,函数需要参数时,使用
-
endpoint=None- 名称,用于反向生成URL,即:
url_for('名称')
- 名称,用于反向生成URL,即:
-
methods=None- 允许请求的方式,默认为
GET,可以是可迭代对象,如methods=["GET", "POST"]
- 允许请求的方式,默认为
-
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
-
-
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()
-
-
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()
-
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就拥有
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.1threading.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的东西
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,一个是g。self.app就是传入的全局的app对象,self.g是一个全局的存储值的对象。接着将这个app_ctx存放到LocalStack()
像数据库配置这样重要的信息挂载在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 框架
- 一、 简介
- 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 代码实现
- 9.1 分区式架构
- 10、 文件上传
- 四、 上下文管理
- 1、 Local对象
- 1.1
threading.local - 1.2 基于函数
- 1.3 基于对象
- 1.1
- 2、 上下文管理阶段
- 3、 g
- 1、 Local对象
- 一、 简介
Flask是一个基于Python并且依赖于Jinja2模板引擎和Werkzeug WSGI 服务的一个微型框架
WSGI :Web Server Gateway Interface(WEB服务网关接口),定义了使用python编写的web app与web server之间接口格式
其他类型框架:
-
Django:比较“重”的框架,同时也是最出名的Python框架。包含了web开发中常用的功能、组件的框架(ORM、Session、Form、Admin、分页、中间件、信号、缓存、ContenType....),Django是走大而全的方向,最出名的是其全自动化的管理后台:只需要使用起ORM,做简单的对象定义,它就能自动生成数据库结构、以及全功能的管理后台。 -
Tornado:大特性就是异步非阻塞、原生支持WebSocket协议; -
Flask: 一个轻量级的基于 Python 的 Web 框架 -
Bottle:是一个简单高效的遵循WSGI的微型python Web框架。说微型,是因为它只有一个文件,除Python标准库外,它不依赖于任何第三方模块。
Flask的架构模式-MTV
- 经典三层结构 :MVC模式
- M :Models ,模型层,负责数据库建模
- V :Views,视图层,用于处理用户显示的内容,如 :html
- C :Controller,控制器,处理与用户交互的部分内容。处理用户的请求并给出响应
- python常用:MTV模式
- M :Models ,模型层,负责数据库建模
- T :Templates ,模板层,用于处理用户显示的内容,如:html
- V :Views ,视图层,处理与用户交互的部分内容。处理用户的请求并给出响应
-
安装
pip install flask -
创建工作目录
mkdir first_dir # 创建工作目录 mkdir first_dir/static # 创建存放图片、css等不需要动态生成的静态文件 mkdir first_dir/templates # 创建存放响应文本的模板文件夹 touch first_dir/app.py # 主程序 -
在
app.py中添加from flask import Flask app = Flask(__name__) @app.route('/') # Flask路由 def hello_world(): return 'Hello World!' if __name__ == '__main__': app.run() # 运行网站主程序会默认访问
templates和static文件夹,如果,存放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 路由参数
-
ruleurl规则
-
voew_func- 视图名称
-
defaults=None- 默认值,当URL中无参数,函数需要参数时,使用
defaults={'k':'v'}为函数提供参数
- 默认值,当URL中无参数,函数需要参数时,使用
-
endpoint=None- 名称,用于反向生成URL,即:
url_for('名称')
- 名称,用于反向生成URL,即:
-
methods=None- 允许请求的方式,默认为
GET,可以是可迭代对象,如methods=["GET", "POST"]
- 允许请求的方式,默认为
-
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
-
-
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()
-
-
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()
-
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就拥有
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.1threading.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的东西
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,一个是g。self.app就是传入的全局的app对象,self.g是一个全局的存储值的对象。接着将这个app_ctx存放到LocalStack()
像数据库配置这样重要的信息挂载在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对象被销毁

