AssertionError:视图函数映射正在覆盖现有的端点函数:main


86

有谁知道如果我有两个这样的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

您是在问如何才能或为什么可以吗?
Michael Davis

5
为什么它不起作用我正在关注一个教程
Kimmy 2013年

1
如果有人想知道为什么Flask具有这种唯一视图名称的界限,请参阅我对类似问题的回答:stackoverflow.com/a/47558985/4440675该答案解释了每种方法使用唯一名称的逻辑背后的原因。
阿米特·特里帕蒂

Answers:


67

您的视图名称即使指向相同的视图方法,也必须是唯一的。

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'])

换句话说,.as_view($VIEW_NAME)方法调用中的$ VIEW_NAME应该作为唯一的字符串名称传入。
Devy

109

当我在模块中有多个API函数并尝试用2个装饰器包装每个函数时,我也遇到了同样的问题:

  1. @ app.route()
  2. 我的自定义@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

然后,装饰多个端点起作用。


27
您也可以使用functools.wraps实现功能的重命名。
ryannjohnson

4
我不得不使用wrapper.__name__代替wrapper.func_name。也许这是python2和python3之间的区别?
共鸣

2
这就是我的使用装饰器的烧瓶restful API中的问题。wrapper.__name__ = func.__name__在调用包装器之前,解决了该问题。
Tom Wojcik '18

28

对于使用@ app.route的用户,最好使用键参数endpoint而不是__name__Roei Bahumi所说的那样更改值。以他为例:

@app.route("/path1", endpoint='func1')
@exception_handler
def func1():
    pass

@app.route("/path2", endpoint='func2')
@exception_handler
def func2():
    pass

8

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"])


4

当您在不同的路由上具有相同的函数名称时,也会发生这种情况。


2

如果您认为自己具有唯一的终结点名称,并且仍然给出此错误,则可能是您遇到了问题。我也是一样。

如果您使用的是相同版本,则烧瓶0.10会出现此问题,然后执行以下操作来消除此问题:

sudo pip uninstall flask
sudo pip install flask=0.9

1

最近有一个针对Flask问题#570的修复(烧瓶0.10),该问题导致引发此异常。

参见https://github.com/mitsuhiko/flask/issues/796

因此,如果转到flask / app.py并注释掉4行948..951,这可能会有所帮助,直到在新版本中完全解决该问题为止。

这种变化的区别在这里:http : //github.com/mitsuhiko/flask/commit/661ee54bc2bc1ea0763ac9c226f8e14bb0beb5b1


3
回复:“直到在新版本中完全解决问题为止”:没有要解决的“问题”。正如问题讨论所显示的,在问题代码中引发异常是预期的结果。如接受答案中所述,端点存在冲突。这是Flask用户代码的错误,不是Flask本身的错误。
Mark Hildreth 2014年



0

@wraps(f)在包装函数之上添加解决了我的问题。

def list_ownership(f):
    @wraps(f)
    def decorator(*args,**kwargs):
        return f(args,kwargs)
    return decorator
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.