AssertionError: View function mapping จะเขียนทับฟังก์ชัน endpoint ที่มีอยู่: 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
ทำไมมันไม่ได้ผลฉันกำลังติดตามบทช่วยสอน
Kimmy

1
หากมีคนอยากรู้ว่าทำไม Flask จึงมีขอบเขตของชื่อมุมมองที่ไม่ซ้ำกันโปรดดูคำตอบของฉันสำหรับคำถามที่คล้ายกัน: stackoverflow.com/a/47558985/4440675คำตอบนี้จะอธิบายว่าตรรกะใดที่อยู่เบื้องหลังการมีชื่อเฉพาะสำหรับแต่ละวิธี
Amit Tripathi

คำตอบ:


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)การเรียกเมธอดควรถูกส่งผ่านเป็นชื่อสตริงที่ไม่ซ้ำกัน
Devy

112

ปัญหาเดียวกันนี้เกิดขึ้นกับฉันเมื่อฉันมีฟังก์ชัน API มากกว่าหนึ่งฟังก์ชันในโมดูลและพยายามรวมแต่ละฟังก์ชันด้วยผู้ตกแต่ง 2 คน:

  1. @ app.route ()
  2. มัณฑนากร @exception_handler ที่กำหนดเองของฉัน

ฉันได้รับข้อยกเว้นเดียวกันนี้เนื่องจากฉันพยายามรวมฟังก์ชันมากกว่าหนึ่งฟังก์ชันกับมัณฑนากรสองคนนี้:

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

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

โดยเฉพาะเกิดจากการพยายามลงทะเบียนฟังก์ชันบางอย่างด้วย name 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

การเปลี่ยนชื่อของฟังก์ชั่นแก้ไขให้ฉัน ( 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

4
ฉันต้องใช้wrapper.__name__แทนwrapper.func_name. บางทีนี่อาจเป็นความแตกต่างระหว่าง python2 และ python3?
Resonance

2
นั่นคือปัญหาใน API ที่พักผ่อนของฉันโดยใช้มัณฑนากร wrapper.__name__ = func.__name__ก่อนที่จะโทรไปที่ wrapper ช่วยแก้ปัญหาได้
Tom Wojcik

29

สำหรับผู้ใช้ที่ใช้งาน @ app.route มันจะดีกว่าที่จะใช้คีย์โต้แย้งendpointแทนแล้ว chaning ค่าของ__name__เช่นRoei Bahumiระบุ ตัวอย่างของเขาจะเป็น:

@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')สองครั้งซึ่งสร้างฟังก์ชันที่แตกต่างกันสองฟังก์ชัน (ฟังก์ชันเดียวกันทั้งหมด แต่แตกต่างกันในลายเซ็นหน่วยความจำ) เรื่องสั้นคุณควรทำ

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

ต้องการเพิ่มบทความที่น่าสนใจจริงๆ "Demystifying Decorators" ที่ฉันพบเมื่อเร็ว ๆ นี้: 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 ที่เปิดตัวเมื่อเร็ว ๆ นี้ (ขวด 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

การเพิ่ม@wraps(f)ฟังก์ชัน wrapper ช่วยแก้ปัญหาของฉันได้

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.