今日内容概要
- 登陆认证装饰器
- 配置文件
- 路由系统
今日内容详细
登陆认证装饰器
1.flask路由下加装饰器,一定要加endpoint
1.如果不指定endpoint,反向解析的名字都是函数名,不加装饰器没有问题,就是正常函数index,detail
2.如果加了装饰器--->index,detail都变成了inner--->反向解析的名字都是函数名inner,报错了
3.wrapper装饰器---->把它包的更像--->函数名变成了原来函数的函数名
2.装饰器使用位置,顺序:紧挨着函数,路由匹配成功了,才会执行该装饰器
代码
from flask import Flask,render_template,request,session,redirect
from functools import wraps
app = Flask(__name__,template_folder='templates')
app.debug = True
app.secret_key = 'sdfsdfsdfsdf' # 等同于django的 配置文件有个很长的秘钥
USERS = {
1:{'name':'张三','age':18,'gender':'男','text':"道路千万条"},
2:{'name':'李四','age':28,'gender':'男','text':"安全第一条"},
3:{'name':'王五','age':18,'gender':'女','text':"行车不规范"},
}
def login_outer(func_name):
def inner(*args,**kwargs):
if session.get('username'):
res = func_name(*args, **kwargs)
return res
else:
return redirect('/login')
return inner
@app.route('/login',methods = ['GET','POST'],endpoint='login')
def login():
if request.method == "GET":
return render_template('login.html')
else:
# post请求校验用户名,密码
username = request.form.get('username')
password = request.form.get('password')
if username == 'nana' and password =='123':
# 登陆成功,存session
session['username']=username
return redirect('/index')
else:
return render_template('login.html',error='用户名密码错误')
@app.route('/index',endpoint='index')
@login_outer # index= login_outer(index)
def index():
# 登陆才能访问
return render_template('index.html',users=USERS)
# /detail/{{k}}
@app.route('/detail/<int:pk>',endpoint='detail')
@login_outer # detail= login_outer(detail)
def detail(pk):
info = USERS.get(pk)
return render_template('detail.html',info=info)
if __name__ == '__main__':
app.run()
装饰器
1.装饰器的本质:在不改变被装饰对象原来的'调用方式'和'内部代码'的情况下给被装饰对象添加新的功能
2.装饰器的原则:对修改封闭,对扩展开放
3.演示
def outer(func):
def inner(*args,**kwargs):
res= func(*args,**kwargs)
return res
return inner
@outer # index = outer(index) -->将语法糖下面紧挨着的函数名当作outer的参数传进去,返回inner,当函数被调用(index()),执行inner()--->真正执行被调用函数
def index():
print('index')
return 123
print(index())
4.还有类装饰器: 1.装饰类的装饰器 2. 类作为装饰器
1.装饰类的装饰器
def outer(func):
def inner(*args,**kwargs):
res= func(*args,**kwargs)
res.name = 'nana'
return res
return inner
@outer # Foo = outer(Foo) # 其返回值inner,当类被实力话产生对象的时候(f = Foo())--->inner()-->类实例化得到对象,返回,以后f就是Foo的对象,但是可以里面多了属性或方法
class Foo:
pass
f= Foo()
print(f.name) # nana
2.类作为装饰器
class Person:
def __call__(self,func,*args, **kwargs):
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
p = Person()
@p # test = p(test) ==>对象加括号,自动调用__call__方法返回inner,以后test就是inner--->test(参数)--》执行的是inner
def test():
print(test) # <function Person.__call__.<locals>.inner at 0x1044c1900>
print('ok')
配置文件
配置方式一:
from flask import Flask
app = Flask(__name__)
# 1.配置方式一:
app.debug=True # Debug mode: on
app.secret_key='dsvfsvgfbfdbgfbdgbf'
@app.route('/')
def index():
print(app.debug) # True
print(app.secret_key) # dsvfsvgfbfdbgfbdgbf
return "it's ok"
if __name__ == '__main__':
app.run()
配置方式二
from flask import Flask
app = Flask(__name__)
# 配置方式二:
app.config['DEBUG'] =True
app.config['SECRET_KEY']='dcfssdvtgvb'
@app.route('/')
def index():
print(app.debug) # True
print(app.secret_key) # dcfssdvtgvb
# print(app.config) # <Config {'ENV': 'production', 'DEBUG': False,N_COOKIE_NAME': 'session',....}>
return "it's ok"
if __name__ == '__main__':
app.run()
配置方式三
from flask import Flask
app = Flask(__name__)
# 配置方式三:通过py文件配置
# app.config.from_pyfile("python文件名称")
app.config.from_pyfile("settings.py")
@app.route('/')
def index():
print(app.debug) # True
print(app.secret_key) # asdfasdfasdfasd333
return "it's ok"
if __name__ == '__main__':
app.run()
settings.py
DEBUG=True
SECRET_KEY="asdfasdfasdfasd333"
其他
1.通过环境变量配置
app.config.from_envvar("环境变量名称")
#app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
环境变量的值为python文件名称名称,内部调用from_pyfile方法
2.JSON文件
app.config.from_json("json文件名称")
JSON文件名称,必须是json格式,因为内部会执行json.loads
3.
app.config.from_mapping({'DEBUG': True})
字典格式
4.
app.config.from_object("python类或类的路径")
app.config.from_object('pro_flask.settings.TestingConfig')
# settings.py
class Config(object):
DEBUG = False
TESTING = False
DATABASE_URI = 'sqlite://:memory:'
class ProductionConfig(Config):
DATABASE_URI = 'mysql://user@localhost/foo'
class DevelopmentConfig(Config):
DEBUG = True # # 开发环境,debug 是true的,连数据库连的是sqlite
class TestingConfig(Config):
TESTING = True
PS: 从sys.path中已经存在路径开始写
PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录(Flask对象init方法的参数)
5.配置中心
路由系统
1.典型写法
@app.route('/detail/<int:nid>',methods=['GET'],endpoint='detail')
"""
rule:路径
methods :请求方式,列表
endpoint: 路径别名
"""
2.转换器
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
# 最常使用:string int path
ps:@app.route('/<path:aa>', methods=['GET'])
路由系统本质-->读源码
1.入口:@app.route('/',methods=['GET'])的route
2.点进去,发现是一个装饰器
@setupmethod
def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
def decorator(f: T_route) -> T_route:
endpoint = options.pop("endpoint", None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
"""
@app.route('/',methods=['GET']) # index = app.route('/',methods=['GET'])(index) -->其返回值是decorator--->index = decorator(index)
def index():
return "it's ok"
"""
3.分析decorator
def decorator(f: T_route) -> T_route:
endpoint = options.pop("endpoint", None) # 从options弹出,如果没有,就是None --->@app.route(传了就有,不传就是None)
self.add_url_rule(rule, endpoint, f, **options) # self就是app对象
return f
4.核心:self.add_url_rule(rule, endpoint, f, **options)--->self就是app对象
app.add_url_rule('路由地址', '路由别名', 视图函数, **options)--->跟django很像
"""
也就是说可以不用@app.route(.....),而使用app.add_url_rule('路由地址', '路由别名', 视图函数, **options)
eg:
def index():
return "it's ok"
app.add_url_rule('/', 'index', index)
"""
5.add_url_rule的参数详解
"""
rule, URL规则,路径地址
view_func, 视图函数名称
defaults = None, 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}
为函数提供参数
endpoint = None, 名称,用于反向生成URL,即: url_for('名称')
methods = None, 允许的请求方式,如:["GET", "POST"]
#对URL最后的 / 符号是否严格要求
strict_slashes = None
#重定向到指定地址
redirect_to = None,
"""
def index(name):
print(name)
return "it's ok"
def home():
return 'home'
app.add_url_rule('/', 'index', index,defaults={'name':'nana'})
app.add_url_rule('/home', 'home', home,strict_slashes=True)
6.endpoint 不传会怎么样?
不传会以视图函数的名字作为值,但是如果加了装饰器,所有视图函数名字都是inner,就会出错,使用wrapper装饰器再装饰装饰器