AssertionError: Xem ánh xạ chức năng đang ghi đè lên một chức năng điểm cuối hiện có: main


86

Có ai biết tại sao tôi không thể ghi đè lên một hàm điểm cuối hiện có nếu tôi có hai quy tắc url như thế này không

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

Tìm lại:

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

Bạn đang hỏi làm thế nào bạn có thể, hoặc tại sao bạn có thể?
Michael Davis

5
lý do tại sao nó không hoạt động Tôi đang theo một hướng dẫn
Kimmy

1
Nếu ai đó tò mò muốn biết tại sao Flask lại có giới hạn tên chế độ xem duy nhất này, hãy xem câu trả lời của tôi cho một câu hỏi tương tự: stackoverflow.com/a/47558985/4440675 Câu trả lời này giải thích logic đằng sau việc có một tên duy nhất cho mỗi phương thức.
Amit Tripathi

Câu trả lời:


67

Tên chế độ xem của bạn cần phải là duy nhất ngay cả khi chúng trỏ đến cùng một phương thức xem.

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

Nói cách khác, .as_view($VIEW_NAME)lệnh gọi phương thức $ VIEW_NAME phải được chuyển vào dưới dạng một tên chuỗi duy nhất.
Devy

110

Vấn đề tương tự cũng xảy ra với tôi khi tôi có nhiều hơn một hàm API trong mô-đun và cố gắng gói mỗi hàm bằng 2 trình trang trí:

  1. @ app.route ()
  2. Trình trang trí @exception_handler tùy chỉnh của tôi

Tôi nhận được cùng một ngoại lệ này vì tôi đã cố gắng kết hợp nhiều hơn một hàm với hai trình trang trí đó:

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

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

Cụ thể, nó là do cố gắng đăng ký một số chức năng với trình bao bọc tên :

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

Thay đổi tên của hàm đã giải quyết được vấn đề đó cho tôi ( 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

Sau đó, trang trí nhiều hơn một điểm cuối đã hoạt động.


27
Bạn cũng có thể sử dụng functools.wrapsđể đổi tên hàm.
ryannjohnson

4
Tôi đã phải sử dụng wrapper.__name__thay vì wrapper.func_name. Có lẽ đây là sự khác biệt giữa python2 và python3?
Resonance

2
Đó là vấn đề trong API khôi phục bình của tôi bằng cách sử dụng trình trang trí. wrapper.__name__ = func.__name__trước khi gọi wrapper đã giải quyết được vấn đề.
Tom Wojcik

28

Đối với người dùng sử dụng @ app.route, tốt hơn nên sử dụng đối số khóa endpointthay vì sau đó theo dõi giá trị __name__như Roei Bahumi đã nêu. Lấy ví dụ của anh ấy sẽ là:

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

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

8

Flask yêu cầu bạn liên kết một 'chức năng xem' với một 'điểm cuối'. Bạn đang gọi Main.as_view('main')hai lần tạo ra hai hàm khác nhau (chính xác là cùng một chức năng nhưng khác nhau về chữ ký bộ nhớ). Câu chuyện ngắn, bạn chỉ nên làm

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

Điều này cũng có thể xảy ra khi bạn có các tên hàm giống nhau trên các tuyến đường khác nhau.


2

Nếu bạn nghĩ rằng bạn có tên điểm cuối duy nhất và lỗi này vẫn được đưa ra thì có thể bạn đang gặp phải vấn đề . Trường hợp của tôi cũng vậy.

Sự cố này xảy ra với bình 0.10, trong trường hợp bạn có cùng phiên bản, hãy làm như sau để loại bỏ điều này:

sudo pip uninstall flask
sudo pip install flask=0.9

1

Có một bản sửa lỗi cho sự cố Flask # 570 được giới thiệu gần đây (bình 0.10) khiến ngoại lệ này được đưa ra.

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

Vì vậy, nếu bạn truy cập flask / app.py và nhận xét 4 dòng 948..951, điều này có thể hữu ích cho đến khi vấn đề được giải quyết hoàn toàn trong phiên bản mới.

Điểm khác biệt của thay đổi đó ở đây: http://github.com/mitsuhiko/flask/commit/661ee54bc2bc1ea0763ac9c226f8e14bb0beb5b1


3
Re: "cho đến khi vấn đề được giải quyết hoàn toàn trong một phiên bản mới": Không có "vấn đề" nào cần được giải quyết. Như cuộc thảo luận vấn đề cho thấy, việc nâng cao một ngoại lệ trong trường hợp mã trong câu hỏi là kết quả mong đợi. Như đã giải thích trong câu trả lời được chấp nhận, các điểm cuối xung đột. Đây là lỗi trong mã của người dùng Flask, KHÔNG phải trong chính Flask.
Mark Hildreth


0

sử dụng bình 0.9 thay vì sử dụng các lệnh sau sudo pip uninstall flask

sudo pip install flask==0.9

0

Việc thêm vào @wraps(f)bên trên hàm wrapper đã giải quyết được vấn đề của tôi.

def list_ownership(f):
    @wraps(f)
    def decorator(*args,**kwargs):
        return f(args,kwargs)
    return decorator
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.