รับรายการเส้นทางทั้งหมดที่กำหนดไว้ในแอพ Flask


145

ฉันมีเว็บแอพพลิเคชั่นบน Flask ที่ซับซ้อน มีไฟล์แยกต่างหากมากมายพร้อมฟังก์ชั่นการดู URL ของพวกเขาถูกกำหนดด้วย@app.route('/...')มัณฑนากร มีวิธีรับรายการเส้นทางทั้งหมดที่ประกาศไว้ในแอพของฉันหรือไม่ อาจมีวิธีการบางอย่างที่ฉันสามารถโทรหาappวัตถุได้?

คำตอบ:


152

ทุกเส้นทางสำหรับโปรแกรมที่ถูกเก็บไว้บนซึ่งเป็นตัวอย่างของapp.url_map werkzeug.routing.Mapคุณสามารถวนซ้ำRuleอินสแตนซ์โดยใช้iter_rulesวิธีการ:

from flask import Flask, url_for

app = Flask(__name__)

def has_no_empty_params(rule):
    defaults = rule.defaults if rule.defaults is not None else ()
    arguments = rule.arguments if rule.arguments is not None else ()
    return len(defaults) >= len(arguments)


@app.route("/site-map")
def site_map():
    links = []
    for rule in app.url_map.iter_rules():
        # Filter out rules we can't navigate to in a browser
        # and rules that require parameters
        if "GET" in rule.methods and has_no_empty_params(rule):
            url = url_for(rule.endpoint, **(rule.defaults or {}))
            links.append((url, rule.endpoint))
    # links is now a list of url, endpoint tuples

ดูลิงก์ที่แสดงไปยังเว็บเพจใหม่ที่สร้างขึ้นสำหรับข้อมูลเพิ่มเติมอีกเล็กน้อย


หวาน! url = url_for(rule.endpoint)ยกเว้นผมมีปัญหากับสาย ฉันเพิ่งได้รับข้อผิดพลาดBuildError: ('DeleteEvent', {}, None)นี้ เพื่อรับ URL ที่ฉันทำurl = rule.ruleไปแทน ความคิดใดที่ว่าทำไมวิธีการของคุณใช้ไม่ได้
J-bob

@ J-bob - เส้นทางส่วนใหญ่ที่เกี่ยวข้องกับDeleteEventมีพารามิเตอร์ที่จำเป็น - คุณสามารถเป็นกรณีพิเศษที่หนึ่งหรือกรองออกกฎใด ๆ ที่len(rule.arguments) > len(rule.defaults)
ฌอน Vieira

โอ้ฉันคิดว่าฉันเข้าใจแล้ว url_forไม่สามารถสร้าง URL สำหรับ methid นั้นโดยไม่มีพารามิเตอร์ใช่ไหม ตกลง แต่ดูเหมือนว่าวิธีการของฉันจะใช้งานได้ แต่มันจะเก็บส่วนนั้นไว้ถ้า URL เป็นพารามิเตอร์ ขอบคุณ!
J-bob

1
นี่เป็นการเริ่มต้นที่ดี ข้อเสนอแนะใด ๆ สำหรับวิธีการสร้างเว็บเซอร์วิสแบบขวดเอกสารอัตโนมัติที่มีพารามิเตอร์ทั้งหมด (เช่น? spam = "ไข่") อยู่ในรายการหรือไม่ บางทีข้อมูลนี้สามารถดึงมาจาก docstring ของวิธีการใช้งาน
Leonid

2
แทนที่จะใช้การใช้url_for(rule.endpoint)งานrule.ruleนั้นดีกว่าเพราะจะแก้ปัญหาที่คุณมีมากกว่าหนึ่งเส้นทางสำหรับวิธีการเดียวกัน
Zini

84

ฉันเพิ่งพบคำถามเดียวกัน วิธีแก้ปัญหาข้างต้นนั้นซับซ้อนเกินไป เพียงเปิดเปลือกใหม่ภายใต้โครงการของคุณ:

    python
    >>> from app import app
    >>> app.url_map

' app ' ตัวแรกคือสคริปต์โครงการของฉัน: app.pyอีกอันคือชื่อเว็บของฉัน

(วิธีนี้เหมาะสำหรับเว็บเล็ก ๆ ที่มีเส้นทางเล็กน้อย)


1
สิ่งนี้อาจไม่ตอบคำถามโดยตรง แต่แน่ใจว่าสมควรได้รับการโหวตเพิ่มขึ้นอีกมากมาย
UltraInstinct

คำตอบนี้ดีมากที่ไม่ต้องการให้คุณเพิ่มรหัสใด ๆ ในแอปพลิเคชันของคุณ ฉันใช้มันเพื่อรับคำตอบที่ฉันต้องการภายในไม่กี่วินาทีโดยไม่ต้องสร้างรหัสใหม่
joshdick

"มีวิธีรับรายการเส้นทางทั้งหมดที่ประกาศไว้ในแอพของฉันหรือไม่" ฉันคิดว่านี่เป็นคำตอบของคำถามโดยตรงและควรเป็นคำตอบที่ยอมรับได้ ง่ายมาก. ขอบคุณ
andho

2
ฉันไม่เห็นว่าวิธีนี้จะง่ายกว่าหรือชัดเจนกว่าคำตอบที่ยอมรับ มันแนะนำวิธีเดียวกัน แต่ใช้เวลานานกว่าจะถึงจุดนั้นและไม่แสดงวิธีย้ำผ่านMapอินสแตนซ์หรือเข้าถึงคุณสมบัติใด ๆ ของRuleมันที่มีอยู่โดยที่คุณไม่สามารถทำอะไรได้เลย
Mark Amery

57

ฉันทำวิธีผู้ช่วยในของฉันmanage.py:

@manager.command
def list_routes():
    import urllib
    output = []
    for rule in app.url_map.iter_rules():

        options = {}
        for arg in rule.arguments:
            options[arg] = "[{0}]".format(arg)

        methods = ','.join(rule.methods)
        url = url_for(rule.endpoint, **options)
        line = urllib.unquote("{:50s} {:20s} {}".format(rule.endpoint, methods, url))
        output.append(line)

    for line in sorted(output):
        print line

มันแก้ข้อโต้แย้งที่ขาดหายไปโดยการสร้างตัวเลือกชุดจำลอง ผลลัพธ์ดูเหมือนว่า:

CampaignView:edit              HEAD,OPTIONS,GET     /account/[account_id]/campaigns/[campaign_id]/edit
CampaignView:get               HEAD,OPTIONS,GET     /account/[account_id]/campaign/[campaign_id]
CampaignView:new               HEAD,OPTIONS,GET     /account/[account_id]/new

จากนั้นเรียกใช้:

python manage.py list_routes

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการชำระเงิน Manage.py: http://flask-script.readthedocs.org/en/latest/


5
ใช้งานได้ดีมาก เพียงแค่เปลี่ยนurllib.unquoteไปurllib.parse.unquoteและprint lineไปprint(line)และทำงานในหลาม 3.x เช่นกัน
squeegee

1
วิธีนี้ใช้ไม่ได้กับอาร์กิวเมนต์ที่ไม่ใช่สตริงฉันแนะนำให้ใช้คำตอบของ John Jiang แทน
โก้

42

คล้ายกับคำตอบของโจนาธานฉันเลือกที่จะทำสิ่งนี้แทน ฉันไม่เห็นจุดที่ใช้ url_for เพราะมันจะแตกถ้าข้อโต้แย้งของคุณไม่ใช่สตริงเช่นลอย

@manager.command
def list_routes():
    import urllib

    output = []
    for rule in app.url_map.iter_rules():
        methods = ','.join(rule.methods)
        line = urllib.unquote("{:50s} {:20s} {}".format(rule.endpoint, methods, rule))
        output.append(line)

    for line in sorted(output):
        print(line)

32

เห็นได้ชัดว่าตั้งแต่เวอร์ชั่น 0.11 Flask มี CLI ในตัว คำสั่งในตัวหนึ่งรายการเส้นทาง:

FLASK_APP='my_project.app' flask routes

มันยอดเยี่ยมมาก!
pfabri

1
flask urlsสำหรับฉัน (0.12.1) เห็นว่าในflask --helpแต่ฉันไม่เห็นเส้นทางหรือ URL ในหน้า CLI
mrgnw

เส้นทางดูเหมือนว่าจะถูกลบออกในขวด 1.1.2
Jerry Ji

5

เนื่องจากคุณไม่ได้ระบุว่าจำเป็นต้องเรียกใช้บรรทัดคำสั่งจึงสามารถส่งคืนข้อมูลต่อไปนี้ใน json ได้อย่างง่ายดายสำหรับแดชบอร์ดหรืออินเทอร์เฟซที่ไม่ใช่บรรทัดคำสั่งอื่น ๆ ผลลัพธ์และผลลัพธ์ที่ได้ไม่ควรนำมาจากมุมมองของการออกแบบเลย มันเป็นการออกแบบโปรแกรมที่ไม่ดีแม้ว่ามันจะเป็นโปรแกรมเล็ก ๆ ผลลัพธ์ด้านล่างนั้นสามารถใช้ในเว็บแอปพลิเคชัน, บรรทัดคำสั่งหรือสิ่งอื่นใดที่นำเข้า json

คุณไม่ได้ระบุว่าคุณจำเป็นต้องรู้ฟังก์ชั่นของหลามที่เชื่อมโยงกับแต่ละเส้นทางดังนั้นสิ่งนี้จะตอบคำถามของคุณได้แม่นยำยิ่งขึ้น

ฉันใช้ด้านล่างเพื่อเพิ่มเอาต์พุตไปยังแดชบอร์ดการตรวจสอบด้วยตนเอง หากคุณต้องการวิธีการหาเส้นทางที่พร้อมใช้งาน (GET, POST, PUT, ฯลฯ ) คุณจะต้องรวมกับคำตอบอื่น ๆ ด้านบน

Rule's repr () ดูแลการแปลงอาร์กิวเมนต์ที่จำเป็นในเส้นทาง

def list_routes():
    routes = []

    for rule in app.url_map.iter_rules():
        routes.append('%s' % rule)

    return routes

สิ่งเดียวกันโดยใช้รายการความเข้าใจ:

def list_routes():
    return ['%s' % rule for rule in app.url_map.iter_rules()]

ตัวอย่างผลลัพธ์:

{
  "routes": [
    "/endpoint1", 
    "/nested/service/endpoint2", 
    "/favicon.ico", 
    "/static/<path:filename>"
  ]
}

2

หากคุณจำเป็นต้องเข้าถึงฟังก์ชั่นมุมมองของตัวเองแล้วแทนการใช้app.url_mapapp.view_functions

สคริปต์ตัวอย่าง:

from flask import Flask

app = Flask(__name__)

@app.route('/foo/bar')
def route1():
    pass

@app.route('/qux/baz')
def route2():
    pass

for name, func in app.view_functions.items():
    print(name)
    print(func)
    print()

เอาต์พุตจากการรันสคริปต์ด้านบน:

static
<bound method _PackageBoundObject.send_static_file of <Flask '__main__'>>

route1
<function route1 at 0x128f1b9d8>

route2
<function route2 at 0x128f1ba60>

(สังเกตการรวมเส้นทาง "คงที่" ซึ่งสร้างโดยอัตโนมัติโดย Flask)


2

คุณสามารถดูเส้นทางทั้งหมดผ่านเปลือกขวดโดยการเรียกใช้คำสั่งต่อไปนี้หลังจากการส่งออกหรือการตั้งค่าตัวแปรสภาพแวดล้อม FLASK_APP flask shell app.url_map


1

ภายในแอพขวดของคุณทำ:

flask shell
>>> app.url_map
Map([<Rule '/' (OPTIONS, HEAD, GET) -> helloworld>,
 <Rule '/static/<filename>' (OPTIONS, HEAD, GET) -> static>])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.