有人知道如果我有两个类似的url规则,为什么我不能覆盖现有的端点函数吗
app.add_url_rule('/',
view_func=Main.as_view('main'),
methods=["GET"])
app.add_url_rule('/<page>/',
view_func=Main.as_view('main'),
methods=["GET"])
追溯:
Traceback (most recent call last):
File "demo.py", line 20, in <module> methods=["GET"])
File ".../python2.6/site-packages/flask/app.py",
line 62, in wrapper_func return f(self, *args, **kwargs)
File ".../python2.6/site-packages/flask/app.py",
line 984, in add_url_rule 'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint
function: main
当我在模块中有多个API函数,并试图用两个装饰器包装每个函数时,我也遇到了同样的问题:
- @app.route()
- 我的自定义@exception_handler装饰器
我得到了同样的异常,因为我试图用这两个装饰器包装多个函数:
@app.route("/path1")
@exception_handler
def func1():
pass
@app.route("/path2")
@exception_handler
def func2():
pass
具体来说,这是由于试图注册一些名为包装器的函数引起的:
def exception_handler(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
error_code = getattr(e, "code", 500)
logger.exception("Service exception: %s", e)
r = dict_to_json({"message": e.message, "matches": e.message, "error_code": error_code})
return Response(r, status=error_code, mimetype='application/json')
return wrapper
更改函数的名称为我解决了这个问题(wrapper.__name__=func.__name__):
def exception_handler(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
error_code = getattr(e, "code", 500)
logger.exception("Service exception: %s", e)
r = dict_to_json({"message": e.message, "matches": e.message, "error_code": error_code})
return Response(r, status=error_code, mimetype='application/json')
# Renaming the function name:
wrapper.__name__ = func.__name__
return wrapper
然后,装饰不止一个端点起了作用。
即使视图名称指向相同的视图方法,它们也必须是唯一的。
app.add_url_rule('/',
view_func=Main.as_view('main'),
methods = ['GET'])
app.add_url_rule('/<page>/',
view_func=Main.as_view('page'),
methods = ['GET'])
对于使用@app.route的用户,最好使用关键字参数endpoint
,而不是像Roei Bahumi所说的那样更改__name__
的值。他的例子是:
@app.route("/path1", endpoint='func1')
@exception_handler
def func1():
pass
@app.route("/path2", endpoint='func2')
@exception_handler
def func2():
pass
当您在不同的路由上具有相同的函数名时,也可能发生这种情况。
在包装函数之上添加@wraps(f)
解决了我的问题。
def list_ownership(f):
@wraps(f)
def decorator(*args,**kwargs):
return f(args,kwargs)
return decorator
Flask要求您将单个"视图函数"与一个"端点"关联起来。您调用Main.as_view('main')
两次,这将创建两个不同的函数(完全相同的功能,但内存中的签名不同)。短篇小说,你应该简单地做
main_view_func = Main.as_view('main')
app.add_url_rule('/',
view_func=main_view_func,
methods=["GET"])
app.add_url_rule('/<page>/',
view_func=main_view_func,
methods=["GET"])
我只想添加一个更"模板"类型的解决方案。
def func_name(f):
def wrap(*args, **kwargs):
if condition:
pass
else:
whatever you want
return f(*args, **kwargs)
wrap.__name__ = f.__name__
return wrap
我只想添加一篇我最近发现的非常有趣的文章"解密装饰师":https://sumit-ghosh.com/articles/demystifying-decorators-python/
这是我一年前编写的一个基本api中使用的对flask jwt extended(4.x.x及以上版本)的(突破性的)更新,现在正在合并到一个项目中。
@jwt_required到@jwt_rerequired()
最近引入的烧瓶问题#570(烧瓶0.10)有一个修复程序,导致引发此异常。
请参阅https://github.com/mitsuhiko/flask/issues/796
因此,如果您转到flak/app.py并注释掉4行948..951,这可能会有所帮助,直到在新版本中完全解决该问题。
这一变化的不同之处在于:http://github.com/mitsuhiko/flask/commit/661ee54bc2bc1ea0763ac9c226f8e14bb0beb5b1
如果您认为您有唯一的端点名称,但仍然出现此错误,那么您可能面临问题。我也是这样。
这个问题是关于烧瓶0.10的,如果你有相同的版本,那么请执行以下操作来消除这个问题:
sudo pip uninstall flask
sudo pip install flask=0.9
也许某些东西不包含差异
- 检查url
- 检查函数名称
我正在处理一个类似的问题,我通过返回包装器函数成功地解决了它,这是以前没有做过的:
def decorator_func(func_to_decorate):
def wrapper_func():
return func_to_decorate
return wrapper_func # I wasn't returning wrapper func!
即使视图名称指向相同的视图方法,它们也必须是唯一的,或者您可以从functools中添加import wrappes并使用@wrappeshttps://docs.python.org/2/library/functools.html
使用烧瓶0.9使用以下命令sudo pip uninstall flask
sudo pip install flask==0.9
如果您在python笔记本上使用flask,每次更改代码时都需要重新启动内核
我遇到了相同的AssertionError,但在这里没有看到解决方案。在我的例子中,我在Jupyter单元中运行了两次装饰函数,然后错误是由于运行了一个与现有运行的端点函数同名的端点函数引起的。
如果您将调试器选择为"Python:文件;而不是";Python:Flask";,使其成为";Python:烧瓶;帮我摆脱了上述错误。
对于稍后来到这里的人。
为了进一步阐述ryanjohnson对这个答案留下的评论。
当您使用functools库中的@wraps()函数时,据我所知,它本质上允许您获得与使用wrapper.__name__ = func.__name__
相同的结果,只是它更简洁,并且不需要您自己手动执行重命名。
我只是想在这里添加一个答案,让那些可能看不到评论并且更专注于提交的答案的人更容易找到这些信息。