AssertionError: Die Zuordnung der Ansichtsfunktionen überschreibt eine vorhandene Endpunktfunktion: main

86

Weiß jemand, warum ich eine vorhandene Endpunktfunktion nicht überschreiben kann, wenn ich zwei URL-Regeln wie diese habe?

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

Zurück verfolgen:

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
Kimmy
quelle
Fragen Sie, wie Sie können oder warum Sie können?
Michael Davis
5
warum es nicht funktioniert Ich folge einem Tutorial
Kimmy
1
Wenn jemand neugierig ist, warum Flask diese Begrenzung eindeutiger Ansichtsnamen hat, siehe meine Antwort auf eine ähnliche Frage: stackoverflow.com/a/47558985/4440675 Diese Antwort erklärt, welche Logik dahinter steckt, für jede Methode einen eindeutigen Namen zu haben.
Amit Tripathi

Antworten:

67

Ihre Ansichtsnamen müssen eindeutig sein, auch wenn sie auf dieselbe Ansichtsmethode verweisen.

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'])
Michael Davis
quelle
Mit anderen Worten, der Methodenaufruf $ VIEW_NAME in .as_view($VIEW_NAME)sollte als eindeutiger Zeichenfolgenname übergeben werden.
Devy
111

Das gleiche Problem trat mir auf, als ich mehr als eine API-Funktion im Modul hatte und versuchte, jede Funktion mit zwei Dekoratoren zu verpacken:

  1. @ app.route ()
  2. Mein benutzerdefinierter @exception_handler Dekorateur

Ich habe dieselbe Ausnahme erhalten, weil ich versucht habe, mehr als eine Funktion mit diesen beiden Dekorateuren zu versehen:

@app.route("/path1")
@exception_handler
def func1():
    pass

@app.route("/path2")
@exception_handler
def func2():
    pass

Insbesondere wird verursacht , indem Sie versuchen einige Funktionen mit dem Namen registrieren Wrapper :

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

Das Ändern des Namens der Funktion hat es für mich gelöst ( 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

Dann funktionierte das Dekorieren von mehr als einem Endpunkt.

Roei Bahumi
quelle
27
Sie können auch verwenden functools.wraps, um die Funktion umzubenennen.
Ryannjohnson
4
Ich musste wrapper.__name__stattdessen verwenden wrapper.func_name. Vielleicht ist das ein Unterschied zwischen Python2 und Python3?
Resonanz
2
Das war das Problem in meiner Flasche Restful API mit Dekoratoren. wrapper.__name__ = func.__name__vor dem Aufruf von Wrapper löste das Problem.
Tom Wojcik
28

Für Anwender , dass die Verwendung @ app.route ist es besser , das Schlüssel-Argument zu verwenden , endpointanstatt den Wert von chaning __name__wie Roei Bahumi angegeben. Sein Beispiel wird sein:

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

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

Bei Flask müssen Sie einem Endpunkt eine einzelne Ansichtsfunktion zuordnen. Sie rufen Main.as_view('main')zweimal auf, wodurch zwei verschiedene Funktionen erstellt werden (genau die gleiche Funktionalität, jedoch unterschiedliche Speichersignaturen). Kurzgeschichte, sollten Sie einfach tun

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

Ich möchte nur eine Lösung vom Typ "Vorlage" hinzufügen.

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

Ich möchte nur einen wirklich interessanten Artikel "Demystifying Decorators" hinzufügen, den ich kürzlich gefunden habe: https://sumit-ghosh.com/articles/demystifying-decorators-python/

ich bin Batman
quelle
4

Dies kann auch passieren, wenn Sie auf verschiedenen Routen identische Funktionsnamen haben.

Joseph
quelle
2

Wenn Sie der Meinung sind, dass Sie eindeutige Endpunktnamen haben und dieser Fehler dennoch angezeigt wird, liegt wahrscheinlich ein Problem vor . Gleiches war bei mir der Fall.

Dieses Problem tritt bei Flasche 0.10 auf, falls Sie dieselbe Version haben, gehen Sie wie folgt vor, um dies zu beseitigen:

sudo pip uninstall flask
sudo pip install flask=0.9
Shrishinde
quelle
1

Es gibt eine Korrektur für das kürzlich eingeführte Flask-Problem Nr. 570 (Flask 0.10), das dazu führt, dass diese Ausnahme ausgelöst wird.

Siehe https://github.com/mitsuhiko/flask/issues/796

Wenn Sie also zu flask / app.py gehen und die 4 Zeilen 948..951 auskommentieren, kann dies hilfreich sein, bis das Problem in einer neuen Version vollständig behoben ist.

Der Unterschied dieser Änderung ist hier: http://github.com/mitsuhiko/flask/commit/661ee54bc2bc1ea0763ac9c226f8e14bb0beb5b1

yassen
quelle
3
Betreff: "Bis das Problem in einer neuen Version vollständig behoben ist": Es ist kein "Problem" zu lösen. Wie die Problemdiskussion gezeigt hat, ist die Auslösung einer Ausnahme im Fall des Codes in der Frage das erwartete Ergebnis. Wie in der akzeptierten Antwort erläutert, stehen die Endpunkte in Konflikt. Dies ist ein Fehler im Code des Benutzers von Flask, NICHT in Flask selbst.
Mark Hildreth
0

Verwenden Sie stattdessen Kolben 0.9, und verwenden Sie die folgenden Befehle sudo pip uninstall flask

sudo pip install flask==0.9
Joshua Johns
quelle
0

Das Hinzufügen @wraps(f)über der Wrapper-Funktion löste mein Problem.

def list_ownership(f):
    @wraps(f)
    def decorator(*args,**kwargs):
        return f(args,kwargs)
    return decorator
Matija Žiberna
quelle