flask1 未整理

flask 扩展组件地址: flask.pocoo.org/extensions/
flask最牛逼的地方 有别于其他框架的是 他做了一个上下文管理机制

django的wsgi是web服务网关接口 wsgi是一个协议 实现这个协议的模块叫wsgiref,本质是创建socket服务,帮我们收发请求,我们就不用关注收发请求,而专注于业务处理. 我们写的程序是站在2个"巨人"的肩膀上,一个是wsgiref,;一个是web框架,一个写好socket,一个写好框架.
jango和flask都依赖wsgi. tonardo不依赖wsgi.
flask本身没有实现socket,flask也依赖wsgi, flask依赖一个第三方的wsgi模块werkzurg
安装flask的时候会自动装上它依赖的werkzury

一个最简单的flask程序:
from flask import Flask

app= Flask(__name__) #生成一个flask对象

@app.route("/index") #创建路由
def index():
return "hello index"

app.run() #app.run实际上就是启动socket


response三剑客 return "xxx"
return render_template('xx.html')
return redirect('/xx')

拿请求相关的数据,需要导入request
from flask import request
request.method # 请求方式
request.form # 对应 request.post 存放FormData中的数据 前端表单类的数据都是formdata to_dict将formdata序列化成字典
request.args # 对应request.get 获取URL中的数据 to_dict 序列化成字典
request.url # 访问的完整路径
request.path # 路由地址
request.host # 主机地址
request.values # 获取 FormData 和 URL中的数据 不要用to_dict可能会有坑,因为2个类型的数据的key有重复会覆盖
request.json # 如果提交时请求头的Content-Type:是application/json,就将数据序列化放在request.json中字典操作
request.data # 如果提交时请求头中的Content-Type无法被识别 放的是请求体中的原始数据 是bytes类型的原始数据
request.cookies # 获取Cookie中的数据
request.headers # 获取请求头
request.files # 前端提交文件用request.files获取文件 序列化文件存储 save(路径) 将文件保存到本地

给模板传值的2种方式:
return render_template('login.html',error = '账号密码不正确')
return render_template('login.html',**{'error' : '账号密码不正确'})

session:
django的session放在数据库中,flask的session放在加密的客户端, session的value是加密的.
给session的加密的加盐 app.secret_key='dingyunfeng' #使用session就必须加盐,不加盐报错

导入session: from flask import Flask,session
session['username']=username #写入session
user=session.get('username') #获取session

昨天回顾:
1.谈谈你对django和flask的认识。
djaong是个大而全的框架, 内部提供了很多组件比如admin,auth,orm,form, modelform,分页缓存信号等方便的组件,只要在配置文件中修改就可以用. 而flask是一个轻量级的小而精的框架,是可扩展性很强的框架,flask常用于开发小型网站,但是开发大型网站也可以,因为它内部提供了很多很多第三方组件,flask和第三方组件结合起来也可以开发和djaong类似的集成了很多功能的框架,可定制性很强.

2.目前你看到flask和django最大的不同点:request 和 session
dj中session依附在reqeust中. flask中直接导入
dj中request通过参数传递,flask直接导入


3.昨天学的flask知识点

-- 模板+静态文件,app= Flask(__name__,static_folder='static111') #在实例化flask对象的时候配置模板和静态文件目录

-- 路由 用装饰器
@app.route('/index',methods=["GET"])

-- 请求相关
request.form 类似dj中request.post
request.args 类似dj中request.get
request.method

-- 响应
"字符串"
render
redirect

-- session
session['username'] = 'alex' #设置session 用secret_key加密跟着response的cookie一起存到客户端,请求的时候带上cokie, flask收到cookie中的session通过secret_key反序列化.
session.get('name') #取值 不要用[]取,防止keyError

4. 路飞总共有几个项目
- 管理后台
- 导师后台
- 主站--我们写的是主站 基于前后端分离来做的

5. 路飞主站业务 #要能把如何实现都说出来
-- 课程
- 课程列表
- 课程详细
- 大纲、导师、推荐课程
- 价格策略
- 章节和课时
- 常见问题
-- 深科技
- 文章列表
- 文章详细
- 收藏
- 评论
- 点赞
-- 支付
- 购物车(4)
- 结算中心(3)
- 立即支付(1)
知识点:
- redis 持久化方法1.aof 2.rdb 为什么要把数据放在redis中1.频繁操作/修改/删除 .2.提高速度
- 支付宝
- 消息推送
- 构建数据结构
- 优惠券+贝里+支付宝
- 个人中心
- 课程中心

6. 播放视频:用CC视频 本质上视频是从cc来的
- 加密
- 非加密


今日内容:
flask基础中所有的基础有下面11个内容:
1.配置文件.
2.路由系统.
3.视图 fbv cbv
4.请求相关
5.响应相关
6.模板渲染
7.session 以加密的形式放在客户端的cookie中
8.flash闪现 闪一下就没有了 数据只要有1个人取就没了
9.中间件
10.蓝图blueprint 对flask程序做一个目录的划分
11.特殊装饰器 类似django的中间件

内容详细:
知识点:
- 给你一个路径字符串 “settings.Foo”,如何找到类并获取其中的大写的静态字段。 为了后面app.config.from_object("settings.DevelopmentConfig")做铺垫
e.g有个文件settings.py 里面有:
class Foo:
DEBUG = True
TEST = True

test.py
import importlib

path = "settings.Foo"

p,c = path.rsplit('.',maxsplit=1)
m = importlib.import_module(p)
cls = getattr(m,c) #反射找到类cls

# 如果找到这个类? dir(类名)拿到类中所有的字典,
for key in dir(cls): #dir()列出一个模块所定义的所有属性。这些属性是函数名、类名、变量名。
if key.isupper():
print(key,getattr(cls,key))
1. 配置文件
#flask的配置信息
用app.config配置
print('app.config')的结果为:
<Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(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(0, 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}>

#修改配置信息
e.g 可以用 app.config['DEGBU']=True 来修改 如果修改的信息比较多,很多行看着麻烦,所以可以用app.config.from_object("settings.DevelopmentConfig")
然后写一个settings.py,里面写class DevelopmentConfig,在class DevelopmentConfig里面写所有要配置的信息,
e.g class DevelopmentConfig: #写开发环境的配置
DEGUG=true

class Config(object):
DEBUG = False
TESTING = False
DATABASE_URI = 'sqlite://:memory:'

class ProductionConfig(Config): #写生产环境的config
DATABASE_URI = 'mysql://user@localhost/foo'

class DevelopmentConfig(Config):
DEBUG = True

class TestingConfig(Config): # 写测试环境的config
TESTING = True

2. 路由系统 endpoint url_for
- endpoint,反向生成URL类似dgngo路由中的name,#不写endpoint默认是函数名
- url_for('endpoint') / url_for("index",nid=777)

url_for对应django中的reverse
endpoint对应django中的name 用于反向解析

举例:
@app.route('/index',methods=["GET","POST"],endpoint='indexxx')#不写endpoint默认是函数名
def index():
print('访问的路径是:',url_for('indexxx'))
return '欢迎登录index'

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


- 动态路由:路由的参数传给函数的参数
@app.route('/index/<int:nid>',methods=['GET','POST']) # 不写参数类型默认是string类型
def index(nid):
print(nid)
return "Index"

#有参数的路由反向解析的时候 url_for('index',nid=999) 那么解析出的路由是/index/999

3. FBV


4. 请求相关
# 请求相关信息 所有请求的信息都能获取到
# request.method
# request.args
# request.form
# request.values
# request.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))

5. 响应:
响应体:#下面这4种只是返回响应体
return “asdf”
return jsonify({'k1':'v1'}) #返回json格式的数据 返回的contentype就是json
return render_template('xxx.html')
return redirect()

定制响应头:#*****
obj = make_response("aaa") # 用make_response封装一个响应对象,响应体是aaa
obj.headers['xxx'] = '123' #设置响应头 xxx: 123456
obj.set_cookie('islogin', 'yes') #设置cookie islogin yes
return obj


举例:学生管理


版本一:没加认证的学生信息管理
@app.route('/index')
def index():
if not session.get('user'):
return redirect(url_for('login'))
return render_template('index.html',stu_dic=STUDENT_DICT)

版本二:加了认证的学生信息管理
import functools
def auth(func):
@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.route('/index')
@auth
def index():
return render_template('index.html',stu_dic=STUDENT_DICT)

应用场景:比较少的函数中需要额外添加功能。

完整版加了认证的学生信息查看:
from flask import Flask, render_template, request, session, redirect, url_for, make_response
import functools

app = Flask(__name__, static_folder='static111')
app.secret_key = 'dingyunfeng'

@app.route('/login',methods=["GET", "POST"])
def login():
if request.method == "GET":
return render_template("login.html")

username = request.form.get('username')
pwd = request.form.get('pwd')

if username == 'alex' and pwd == '123':
session['username'] = username # 登录成功 把用户名写入session
return redirect(url_for('index'))

return render_template('login.html', error='账号密码不正确')

def auth(func):
@functools.wraps(func) #用functools.warps()装饰,使装饰了的函数保留原来的函数名,
# 否则所有装饰这个函数的函数名都是inner,
#而endpoint没指定的时候默认是函数名,所有函数的endpoint都是inner会报错
def inner(*args,**kwargs):
if not session.get('username'): #如果没取到用户名表示没有登录,重定向到login页面
return redirect(url_for('login'))
ret = func(*args,**kwargs)
return ret
return inner

STU_INFO = {
1: {'name': 'alex', 'age': 18, 'hobby': 'women'},
2: {'name': '丁云凤', 'age': 20, 'hobby': 'club'},
3: {'name': 'max', 'age': 30, 'hobby': '唱歌'},
4: {'name': '令狐冲', 'age': 40, 'hobby': '喝酒'}
}
@app.route('/index', methods=["GET", "POST"],endpoint='index')
@auth
def index(): #inex页面加上认证装饰器 先认证 通过认证再进入index
return render_template('index.html', stu_info=STU_INFO)

@app.route('/detail/<int:pid>')
@auth
def detail(pid):
return render_template('detail.html', stu_info=STU_INFO[pid])

@app.route('/delete/<int:pid>')
@auth
def delete(pid):
del STU_INFO[pid]
return redirect(url_for('index')) #删除后重定向到index页面,用反向路由重定向

if __name__ == "__main__":
app.run(debug=True)


版本三:基于before_request的认证
每个函数都要加认证装饰器 比较麻烦,加装饰器适用给某单个函数加功能, 如果要给大量函数加功能,用before_request
before_request类似djanog中process_reqeust 在视图函数之前执行,如果before_request无返回值,就继续执行视图函数,有返回值就直接返回不执行视图函数

@app.before_request
def br():
if request.path == '/login':
return None #return None就表示继续执行视图函数 如果是login页面 要继续执行login

if session.get('user'): #如果sesison中取到了user 表示认证通过 return None,继续执行视图函数
return None

return redirect('/login') #return 有返回值,就直接返回不执行视图函数


6. 模板渲染
- 基本数据类型:可以执行python的语法,如:dict.get() list['xx'] 或用句点符 dict.name

- 传入函数
- django会自动执行
- flask不自动执行 要func()执行才会执行

- 全局定义函数 @app.template_global()
有些函数100个页面都要用 那么100个页面中传模板的时候都要带上这个函数,就可以将它定义成全局函数,所有页面直接引用
@app.template_global()
def sb(a1, a2): # 前端使用: {{sb(1,9)}}
return a1 + a2

@app.template_filter()
def db(a1, a2, a3): # 前端使用 {{ 1|db(2,3) }} 可以用在if后面当条件e.g {%if 1|db(2,3) %}...
return a1 + a2 + a3

- 模板继承 和django中一样 extends/include/macro
layout.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>模板</h1>
{% block content %}{% endblock %}
</body>
</html>

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


{% block content %}
{{users.0}}

{% endblock %}

- include 包含一个小的html页面

{% include "form.html" %}


form.html
<form>
asdfasdf
asdfasdf
asdf
asdf
</form>
- 宏 相当于执行一个函数 模板可以多次执行
{% macro input1(name, type='text', value='') %} # macro相当于def, marco定义一个代码块 定义完不显示, 调用的时候显示
<h1>宏</h1>
<input type="{{ type }}" name="{{ name }}" value="{{ value }}">
<input type="submit" value="提交">
{% endmacro %}

{{ input1('n1',type='password',111) }} #执行宏

{{ input1('n2',222) }} #执行宏

- 安全 模板渲染的时候默认加上了防xss攻击,
如果要让文本用html形式渲染,
- 前端: {{u|safe}}
- 后端: MarkUp("asdf")


7. session

当请求一进来:flask读取cookie中session对应的值:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95,将该值解密并反序列化成字典,放入内存以便视图函数使用
当请求结束时,flask会读取内存中字典的值,进行序列化+加密,写入到用户cookie中。

操作session的时候当做字典操作 session类似字典但不是字典
操作是序列化再加密给客户端发过去例如:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95. 获取后解密再反序列化使用.

#和session有关的配置:在app.config中:
'PERMANENT_SESSION_LIFETIME': timedelta(days=31), #session有效期
'USE_X_SENDFILE': False,
'SERVER_NAME': None,
'APPLICATION_ROOT': '/',
'SESSION_COOKIE_NAME': 'session', #在cookie中session显示的名字
'SESSION_COOKIE_PATH': None,
'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False,
'SESSION_COOKIE_SAMESITE': None,
'SESSION_REFRESH_EACH_REQUEST': True, # session时效在每次访问的基础上开始算,也就是有效期从最后一次访问开始算,如果为false就从第一次设置session开始算. 一般都是true,就像淘宝在你最后一次请求开始算session的有效时间.-

#e.g app.config["PERMANENT_SESSION_LIFETIME"]=timedelta(seconds=600) #设置session有效期为10分钟

举例:

@app.route('/ses')
def ses():
session['user'] = 'alex' #设置值 在浏览器中可以看见cookie中有
print(session.get('user') #取值

del session['k1'] #删session

return "Session"




8. flash闪现,在session中存数据,取一次就没有了,原理就是在session中存储数据读取后就pop将数据移除。放什么值都行,最后都会序列化
# vs session中的数据只要不超时就一直在 无论取多少次
设置数据flash('name','alex')
取数据 get_flashed_messages(category_filter=['name'])


from flask import Flask,flash,get_flashed_messages
@app.route('/page1')
def page1():

flash('登录失败','error') # 将这个数据分类到error类中 取的时候get_flashed_messages(category_filter=['error']) 拿到所有error类下的数据,是个列表 e.g ['登录失败','没有这个用户']
flash('没有这个用户','error')
flash('登录成功','info') # 将这个数据分类到info类中
flash('注册成功','info')

return "Session"

@app.route('/page2')
def page2():
print(get_flashed_messages(category_filter=['error']))
return "Session"

源码:
def flash(message, category='message')
#第二个参数是分类,可以数据进行分类, e.g flash('没有这个用户','error')给这个错误分类到error中
......

取的时候get_flashed_messages(category_filter=['error']) 拿到所有error类下的数据,是个列表 e.g ['登录失败','没有这个用户']

9. 中间件
- 前提知识: call方法什么时候触发?
- 有请求进来时,才执行__call__方法

- 要实现: 在执行call方法之前,做一个操作,call方法执行之后做一个操作。
方法1. 改源码,在源码的__call__方法中加代码.
但是导致所有请求都会执行这个call方法

方法2:类继承 重写call方法
class Middleware(object):
def __init__(self,old):
self.old = old

def __call__(self, *args, **kwargs):
ret = self.old(*args, **kwargs)
return ret

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


10. 特殊装饰器 , #before_request/after_request就类似djaong的中间件

1. before_request #来任何请求先执行before_request

2. after_request #必须要有参数 必须要有返回值 类似djanog的process_response
示例:
from flask import Flask

app = Flask(__name__)

@app.before_request
def b2():
print('b2')

@app.before_request
def b1():
print('b1')

@app.after_request
def a1(requset):
print('a2')
return requset

@app.after_request
def a1(requset):
print('a1')
return requset

@app.route('/index')
def index():
print('index....')
return 'helloworld'

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

#访问index结果: before_request谁先定义谁先执行 after_request谁后定义谁先执行.
#总结 正序执行before_request--->执行视图函数--->倒序执行after_request
b2
b1
index....
a1
a2

有多个before_request,某个before_request有返回值,那么剩下的before_request不执行,倒序执行所有的after_request.
vs 和django不一样 django的process_request有返回值的时候,从当前中间件的process_response开始倒序执行.(#djaong的1.10之前是和flask一样执行所有的respone, djaong的1.10后就从当前中间件的response开始倒序执行response)


3. before_first_request # 只有第一次请求执行, 之后请求就不再执行

from flask import Flask
app = Flask(__name__)

@app.before_first_request
def x1():
print('123123')


@app.route('/index')
def index():
print('index')
return "Index"


@app.route('/order')
def order():
print('order')
return "order"


if __name__ == '__main__':

app.run()


4. template_global 给模板用的

5. template_filter 给模板用的

6. errorhandler # 自定制报错页面

@app.errorhandler(404)
def not_found(err_msg): #必须要有参数 这个参数用来接收真实404错误的报错信息
print(err_msg)
return "404错误 您要的页面没找到"

总结:
- 配置文件 # app.config.from_object("settings.DevelopmentConfig") 原理是字符串形式导入模块,反射找到里面内容,只有大写才能找到,因为源码中判断了isupper
- 路由 route #url_for/ methods/ endpoint #记住加装饰器加载route下面,且写wraps装饰器为了避免endpoint都重名为inner,在写装饰器的inner的时候要@functools.wrapper
- 视图:FBV
- 请求相关数据 request和djaong不一样, 不是参数传入而是直接导入的
- 响应
- 响应体 return 'xx'/render_template /redirect
- 自定制响应头
obj = make_response("adfasdf")
obj.headers['x'] = asdfasdf
return obj
- 模板
template_global
template_filter

- session
session内容会被序列化并加密存在客户端的cookie中
原理是请求一进来就当请求一进来:flask读取cookie中session对应的值解密并反序列化成字典,放入内存以便视图函数使用
当请求结束时,flask会读取内存中字典的值,进行序列化+加密,写入到用户cookie中。
默认超时时间是31天
- flash
数据取一次就没有了
原理是在session取数据后将数据pop

- 中间件
flask请求入口是__call__方法

- 特殊装饰器
before_request
after_response
before_first_request
template_global
template_filter
errhander


#=======================

s9day116

内容回顾:
1. django和flask区别?
部分回答:
不同点 最大的不同点是 django中request和session通过参数传递 flask中通过上下文管理
相同点 都是基于wsgi协议 (提供的socket服务)
2.什么是wsgi?
是web服务网关接口,wsgi是一个协议,实现该协议的模块有:
- wsgiref模块 #djanog中用的
- werkzeug模块 #flask中用的
实现wsgi协议的模块本质上就是socket server用于接收用户请求并处理,只专注于处理请求,对业务的处理交给框架,
一般的web框架都是基于wsgi实现,这样实现关注点分离。web框架只专注于处理业务.目前的web框架除了tonardo其他都是基于wsgi来做.

wsgiref示例:
from wsgiref.simple_server import make_server

def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]


if __name__ == '__main__':
httpd = make_server('127.0.0.1', 8000, run_server) #表示请求进来会对第三个参数加括号,run_server()就执行run_server
httpd.serve_forever()

werkzeug示例:
from werkzeug.wrappers import Response
from werkzeug.serving import run_simple

def run_server(environ, start_response):
response = Response('hello')
return response(environ, start_response)

if __name__ == '__main__':
run_simple('127.0.0.1', 8000, run_server)

Flask源码入口:
from werkzeug.wrappers import Response
from werkzeug.serving import run_simple

class Flask(object):
def __call__(self,environ, start_response):
response = Response('hello')
return response(environ, start_response)

def run(self):
run_simple('127.0.0.1', 8000, self)#请求一进来,对第三个参数加括号,self()执行__call__方法

app = Flask()

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

3. Flask提供功能
- 1.配置文件
- 所有配置都在app.config中
- app.config["DEBUG"] = True
- app.config.from_object("类的路径") #使用指定配置文件
- 使用到了importlib、getattr,还有哪些功能是这样实现的?: django中间件和rest framework的全局配置

- 2.session
- 使用必须加盐app.secret_key
- 序列化加密后放在浏览器的cookie中。
- 流程:
- 请求到来
- 视图函数
- 请求结束
- 配置文件
- 3.flash闪现
- 基于session实现
- 4.路由
- 通过带参数的装饰器来实现
- 自定义装饰器放下面
- 参数
- url_for
- 5.视图
- FBV
- 6.请求和响应
- 请求:request
- 响应: 4种
- 7.模板
- ...
- 8.特殊装饰器
- before_first_request
- before_request
- after_request
- template_global()
- template_filter()
- errorhandler(404)
- 中间件

今日内容:
1. 路由+视图
2. session实现原理(源码)
3. 蓝图
4. threading.local
5. 上下文管理(第一次)

内容详细:
1. 路由+视图

#route的源码:
def route(self, rule, **options): #rule是xxx
def decorator(f): # f是index
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options) #当@app.route('/xxx') def index():的时候,最终执行的是app.add_url_rule(xxx, None,index. **options) 路由系统的本质就是执行了add_url_rule
return f
return decorator

#通过源码可以看出路由的本质就是执行了add_url_rule,所以@app.route('/xxx') def index()也可以不加app.route装饰器写成app.add_url_rule('/xxx',None,index)
所以routers=[('/xxx',index),]
for item in routers:app.add_url_rule(item[0],None,item[1]) 也可以实现路由功能
=====================================================
1. 路由设置的两种方式:
方式1:
@app.route('/xxx')
def index():
return "123"

方式2:
def index():
return "123"
app.add_url_rule("/xxx",None,index)

注意事项:
- 不用让endpoint重名
- 如果重名函数也一定要相同。

2. app.route的参数
rule, URL规则
view_func, 视图函数名称
endpoint=None, 名称,用于反向生成URL,即: url_for('名称')
methods=None, 允许的请求方式,如:["GET","POST"] 不写默认为get
strict_slashes=None, 对URL最后的 / 符号是否严格要求,
redirect_to=None, 重定向到指定地址 #例如开发了新系统地址不一样了,用户还用旧地址,我们就可以重定向到新地址
defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
subdomain=None, 子域名访问 e.g mall.authhome.com 或 sell.authhome.com
e.g
有 app.config['SERVER_NAME'] = 'oldboy.com'
@app.route('/',subdomain='admin') #那么当访问 admin/oldboy.com的时候执行这个函数
def xxx()....

3. CBV
import functools
from flask import Flask,views
app = Flask(__name__)

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

#cbv 的url和视图对应关系不能用装饰器 只能用add_url_rule
#和django一样,请求进来,as_view()中中执行view, view中return self.dispathch_request(*args,**kwargs)然后反射执行get/post
#flask中cbv不多,一般都用fbv
class UserView(views.MethodView):
methods = ['GET'] #只允许GET请求
decorators = [wrapper,] #给cbv中所有函数加上装饰器wrapper,也可以单独给每个函数加装饰器@wrapper

def get(self,*args,**kwargs):
return 'GET...'

def post(self,*args,**kwargs):
return 'POST...'

app.add_url_rule('/user',None,UserView.as_view('uuuu'))

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


4. 路由中自定义正则 默认不支持自定义正则,我们可以让他支持
from flask import Flask,url_for

app = Flask(__name__)

# 步骤一:定制类 继承BaseConverter
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
"""
自定义URL匹配正则表达式
"""

def __init__(self, map, regex):
super(RegexConverter, self).__init__(map)
self.regex = regex

def to_python(self, value): #to_pthon方法将url字符串变成int
"""
路由匹配时,匹配成功后传递给视图函数中参数的值
:param value:
:return:
"""
return int(value) #将url的字符串变成int

def to_url(self, value): #反向生成URL时触发to_url
"""
使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
:param value:
:return:
"""
val = super(RegexConverter, self).to_url(value)
return val

# 步骤二:将自定制类添加到转换器converters
app.url_map.converters['reg'] = RegexConverter #reg就代指RegexConverter

"""
1. 用户发送请求
2. init的self.regex = regex flask内部进行正则匹配
3. 匹配成功后调用当前转换器的to_python(正则匹配的结果)方法,to_python()的返回值给视图函数的参数index(nid)
"""

# 步骤三:使用自定义正则
@app.route('/index/<reg("\d+"):nid>') #reg就代指RegexConverter 类后加括号就是实例化执行构造方法init,
def index(nid):
print(nid,type(nid))

print(url_for('index',nid=123))
return "index"

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

posted @ 2020-05-11 01:44  yunfengding  阅读(175)  评论(0编辑  收藏  举报