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
чому це не працює Я
слідую

1
Якщо комусь цікаво дізнатися, чому Flask має таке обмеження унікальних імен подання, перегляньте мою відповідь на подібне запитання: stackoverflow.com/a/47558985/4440675 Ця відповідь пояснює, яка логіка полягає в наявності унікальної назви для кожного методу.
Аміт Трипаті

Відповіді:


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

Іншими словами, $ VIEW_NAME у .as_view($VIEW_NAME)виклику методу слід передавати як унікальну назву рядка.
Деві

110

Така сама проблема трапилася зі мною, коли у мене було більше однієї функції API в модулі і я намагався обернути кожну функцію двома декораторами:

  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

Зміна назви функції вирішила це для мене ( обгортка .__ 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
Це була проблема в моєму спокійному API колби з використанням декораторів. wrapper.__name__ = func.__name__перед викликом обгортки вирішив проблему.
Том Войцік,

28

Для користувачів, які використовують @ app.route, краще використовувати аргумент ключ, endpointа не повторювати значення, __name__подібне заявленому Роей Бахумі . Беремо його приклад:

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

7

Я просто хотів би додати до цього рішення типу "шаблон".

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/


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 і прокоментуєте 4 рядки 948..951, це може допомогти, поки проблему не буде повністю вирішено в новій версії.

Різниця цієї зміни знаходиться тут: http://github.com/mitsuhiko/flask/commit/661ee54bc2bc1ea0763ac9c226f8e14bb0beb5b1


3
Re: "доки проблема не буде повністю вирішена в новій версії": Не існує "проблеми", яку потрібно вирішити. Як показало обговорення питання, виняток у випадку коду у питанні є очікуваним результатом. Як пояснюється у прийнятій відповіді, кінцеві точки суперечать. Це помилка в коді користувача Flask, НЕ в самій Flask.
Mark Hildreth


0

використовуйте колбу 0.9 замість цього використовуйте наступні команди sudo pip uninstall flask

sudo pip install flask==0.9

0

Додавання @wraps(f)вище функції обгортки вирішило мою проблему.

def list_ownership(f):
    @wraps(f)
    def decorator(*args,**kwargs):
        return f(args,kwargs)
    return decorator
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.