Flask之endpoint错误View function mapping is o…
2018-12-17 10:50:49来源:博客园 阅读 ()
最近在学习Flask, 其中遇到了一个错误, 发现这个问题和Flask, 路由有关系, 所以就记了下来
错误代码:
from flask import Flask, render_template, request, redirect, session app = Flask(__name__) app.secret_key = "wang" def confirm(func): # 负责确认用户有没有登陆的装饰器 def inner(*args, **kwargs): if session.get("auth"): # 判断用户的session中没有user return func(*args, **kwargs) # 通过 else: # 跳转登陆页面, 并携带当前访问的url next_url = request.path return redirect(f'/login?next={next_url}') return inner @app.route('/') @confirm def index(): return "index" @app.route('/login', methods=["GET", "POST"]) def login(): msg = '' if request.method == "POST": auth = request.form.get('auth') if auth == 'wang': # 简单认证 session['auth'] = auth # 设置session next_url = request.args.get('next_url', "/") # 获取用户之前访问的url, 进行跳转 return redirect(next_url) else: msg = "口令错误" return render_template("login.html", msg=msg) @app.route('/shopping') @confirm def shopping(): return "购物" if __name__ == '__main__': app.run(debug=True)
报错:
诡异的是, 我不启动flask, 只是解释一遍, 也会报错
报错分析
分析报错提示
根据报错的提示, 说我的代码存在重复的函数, 然后就开始检查我的函数, 发现函数名并没有重复, 难道就这样排除函数名的嫌疑吗? NONONO
可能是我对装饰器的理解还不够, 找了好半天才发现这个问题, 原来是装饰器的原因, 为什么呢?
为什么说是因为装饰器, 才会出现函数覆盖的问题?
再来温习一下装饰器
def test(func): # 装饰器 """ test :param func: 其实就是要装饰的函数 :return: """ def inner(*args, **kwargs): start = time.time() func(*args, **kwargs) end = time.time() return end - start return inner def outer(a, b): # 被装饰的函数 for n in range(a): for j in range(b): a = n + j outer = test(outer) # 这里因为使用语法糖, 这种方式更能表示出问题 # 在这一步可以说对outer进行了重新的赋值, # 现在outer就等于test这个函数的返回值, 并且将原本的outer传了进去 # test函数的返回值是一个inner # 在inner函数中就包括了原本的outer, 并且这个outer在inner函数中是加了括号的 # 也就是说, 当inner被调用的时候, 原本的outer也会被调用 # 刚刚说test函数返回的是inner函数 # 当outer = test(outer)执行完之后, 新的outer就等于inner了 # 到这只需要知道现在的outer一样不是原来的outer了, 而是指向了inner, 在inner内部调用原来的outer print(outer(100000, 200)) # 这是调用函数, 不能改变这个调用方式
再来看flask中app.route中的源码
flask使用装饰器来绑定一个url和视图的关系, 带着遇到的问题来看看源码中做了些什么
@app.route('/shopping') ① @confirm def shopping(): return "购物" def route(self, rule, **options): def decorator(f): endpoint = options.pop('endpoint', None) # ② 从参数中弹出endpoint, 没有的话就是None self.add_url_rule(rule, endpoint, f, **options) # ③ return f @setupmethod def add_url_rule(self, rule, endpoint=None, view_func=None, provide_automatic_options=None, **options): if endpoint is None: # ④ endpoint如果为None endpoint = _endpoint_from_view_func(view_func) # ⑤ 将试图视图函数传了进去, 返回视图函数的__name__ def _endpoint_from_view_func(view_func): assert view_func is not None, 'expected view func if endpoint is not provided.' ~~~~ 其实执行的就是 inner.__name__, 因为此时的shopping, 已经不是原来的shopping, 而是装饰器内部返回的函数 return view_func.__name__ # ⑥ 因为没有定义endpoint, 所以在返回视图函数的名字
看上面的代码应该就知道是哪里重复了, 原因就是, 都是调用了inner.__name__, 所以拿到的endpoint值都是一样的才会提示重复了函数名
就是源码中的这一段抛出的异常
if view_func is not None: old_func = self.view_functions.get(endpoint) if old_func is not None and old_func != view_func: raise AssertionError('View function mapping is overwriting an ' 'existing endpoint function: %s' % endpoint) self.view_functions[endpoint] = view_func
如何解决这个问题
方法一
根据源码可以看看出是因为, endpoint重复才导致的, 当endpoint为None时, 就会调用inner.__name__, 就会导致重复, 那么我们不让endpoint为空, 那就不会调用inner.__name__了
也就不会出现重复的问题了.
现在来看看在哪里可以定义这个endpoint.
还记得源码中是从哪里去endpoint的吗, 是不是下面这里
endpoint = options.pop('endpoint', None)
是从option中pop出去的, option就是route(self, rule, **options)的一个形参, 也就是说你在使用app.route的时候可以传一个endpoint的键值对
只需要对两个视图的route装饰器添加一个参数即可, 看代码吧, 红色部分是新添加的
@app.route('/', endpoint="index") @confirm def index(): return "index" @app.route('/shopping', endpoint="shopping") @confirm def shopping(): return "购物"
这样既可以了, 不信你试试
方法二
使用functools.wraps
不太推荐这种方法, 因为flask本身的不稳定性, 所以要尽可能的少用第三方的模块, 下面只提供了代码
def confirm(func, *args, **kwargs): @wraps(func) def inner(): if session.get('user'): return func(*args, **kwargs) else: next_url= request.path return redirect('/login?next=%s' % (next_url,)) return inner
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Flask request接口获取参数 2019-08-13
- faster-rcnn错误信息 : tensorflow.python.framework.error 2019-07-24
- [Python学习]错误篇二:切换当前工作目录时出错——FileNotF 2019-07-24
- mysql-python 安装错误: Cannot open include file:  2019-07-24
- 读文件时出现这个错误 'utf-8' codec can&a 2019-07-24
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash