如何正确调用url_for并指定路径参数?

How to correctly call url_for and specify path parameters?

这是views.py中的函数:

@application.route("/students/<int:id>", methods=["GET", "POST"])
def students(id):
    return render_template("students.html")

我在 HTML 页面上使用了此代码:

<a href="{{ url_for('students', id=student.id) }}">{{ student.id }}</a>

但是 url_for 正在生成这个:

http://127.0.0.1:5000/students?id=1

我想生成这个:

http://127.0.0.1:5000/students/1

请注意,我还有一个函数是在第一个函数之前编写的:

@application.route("/students")
def students():
    return render_template("students.html", students=Student.query.all())

我认为url_for正在使用这条路线。

问题是您有 2 个具有几乎相同模式的端点:

/students
/students/<int:id>

这就变成了以什么顺序定义这些端点的问题,因为调用 url_for('students', id=student.id) 可以在两个 :

上正确匹配
  • 如果匹配 /students first,如 url_for 文档中所述:“目标端点未知的可变参数作为查询参数附加到生成的 URL。。由于 id=1234 不是此端点上的已知参数,因此它成为查询参数 ?id=1234.
  • 如果匹配 /students/<int:id> first,那么您将得到预期的 /students/1234

依赖端点的顺序是一种脆弱且 error-prone 的策略,所以如果您认为您应该重新排序端点定义,不,那不是正确的方法。

我推荐的是这些选项:

  1. 重命名函数以帮助区分 url_for(和您的代码的读者)一个端点用于获取 所有 学生,以及另一个是通过 id 访问 一个 学生 。然后在 url_for:

    中明确调用正确的那个
    @application.route("/students/<int:id>", methods=["GET", "POST"])
    def student_by_id(id):
        return {"student": id}
    
    @application.route("/students")
    def all_students():
        return {"students": "all"}
    
    <a href="{{ url_for('student_by_id', id=student.id) }}">{{ student.id }}</a>
    
  2. 与选项 1 类似,但不是重命名函数,pass-in 一个 endpoint=... 关键字参数到 route(...) 装饰器以指定不同的端点名称。有关详细信息,请参阅 the docs for the route decorator and the section on URL Route Registrations。默认情况下,“如果未传递 endpoint 参数,路由的端点名称默认为视图函数的名称。”。所以在这里,将接受 id 的端点命名为 "student_by_id" 并在 url_for.

    中明确使用它
    @application.route(
        "/students/<int:id>", 
        methods=["GET", "POST"], 
        endpoint="student_by_id",  # <---------
    )
    def students(id):
        return {"student": id}
    
    @application.route("/students")
    def students():
        return {"students": "all"}
    
    <a href="{{ url_for('student_by_id', id=student.id) }}">{{ student.id }}</a>
    
  3. 将两者合并为 1 个端点。然后端点函数应首先检查是否指定了 id。如果是,则只处理 1 名学生的处理。否则,处理所有学生的处理。 url_for 调用不需要更改。

    @application.route("/students")
    @application.route("/students/<int:id>", methods=["GET", "POST"])
    def students(id=None):
        if id:
            return {"student": id}
        else:
            return {"students": "all"}
    
    <a href="{{ url_for('students', id=student.id) }}">{{ student.id }}</a>
    

选择最适合您的一种。

作为旁注,, I also recommend not using id as a parameter or variable name, because you might accidentally shadow the built-in id() function。将其更改为 student_id.

实际上可能更具可读性