AssertionError:ビュー関数のマッピングが既存のエンドポイント関数を上書きしています:main


86

このような2つの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
なぜそれが機能しないのか私はチュートリアルに従っています
キミー2013年

1
誰かがFlaskにこの一意のビュー名の境界がある理由を知りたい場合は、同様の質問に対する私の回答を参照してください:stackoverflow.com/a/47558985/4440675この回答は、各メソッドに一意の名前を付けることの背後にあるロジックを説明しています。
Amit Tripathi 2017年

回答:


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

112

これと同じ問題は、モジュールに複数のAPI関数があり、各関数を2つのデコレータでラップしようとしたときに発生しました。

  1. @ app.route()
  2. 私のカスタム@exception_handlerデコレータ

これらの2つのデコレータで複数の関数をラップしようとしたため、これと同じ例外が発生しました。

@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

次に、複数のエンドポイントの装飾が機能しました。


28
functools.wraps関数の名前変更を実現するために使用することもできます。
ryannjohnson 2017

4
wrapper.__name__代わりに使用する必要がありましたwrapper.func_name。おそらくこれはpython2とpython3の違いですか?
レゾナンス

2
これが、デコレータを使用したフラスコのRESTfulAPIの問題でした。wrapper.__name__ = func.__name__ラッパーを呼び出す前に問題を解決しました。
Tom Wojcik 2018

29

@ 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

9

Flaskでは、単一の「ビュー関数」を「エンドポイント」に関連付ける必要があります。Main.as_view('main')2回呼び出しているため、2つの異なる関数が作成されます(まったく同じ機能ですが、メモリシグネチャが異なります)。短編小説、あなたは単にするべきです

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(flask 0.10)の修正があり、この例外が発生します。

https://github.com/mitsuhiko/flask/issues/796を参照してください

したがって、flask / app.pyにアクセスして、948..951の4行をコメントアウトすると、問題が新しいバージョンで完全に解決されるまで、これが役立つ場合があります。

その変更の相違はここにあります:http//github.com/mitsuhiko/flask/commit/661ee54bc2bc1ea0763ac9c226f8e14bb0beb5b1


3
Re:「新しいバージョンで問題が完全に解決されるまで」:解決すべき「問題」はありません。問題の議論が示したように、問題のコードの場合に例外が発生することは期待される結果です。受け入れられた回答で説明されているように、エンドポイントは競合しています。これは、Flask自体ではなく、Flaskのユーザーのコードの障害です。
マークヒルドレス2014年



0

@wraps(f)上記のラッパー関数を追加すると、問題が解決しました。

def list_ownership(f):
    @wraps(f)
    def decorator(*args,**kwargs):
        return f(args,kwargs)
    return decorator
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.