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
Кимми
источник
Вы спрашиваете, как можно или почему?
Майкл Дэвис
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)вызове метода должен быть передан как уникальное имя строки.
Деви,
109

Та же проблема случилась со мной, когда у меня было более одной функции 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

Для меня это решило изменение имени функции ( 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?
Resonance
2
Это была проблема в моем успокаивающем API фляги с использованием декораторов. wrapper.__name__ = func.__name__перед вызовом обертки решил проблему.
Tom Wojcik
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
Shrishinde
источник
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.
Марк Хилдрет
0

Имена ваших представлений должны быть уникальными, даже если они указывают на один и тот же метод представления, или вы можете добавить обертки импорта из functools и использовать @wraps https://docs.python.org/2/library/functools.html

Андрей Щудло
источник
0

используйте flask 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
Матия Жиберна
источник