简体   繁体   中英

How do I use Flask's url_for in a template?

I am building a Flask application to manage character sheets for an RPG using an SQL database.

Currently, I have the following script that displays the list of a user's characters currently in the database.

@app.route("/<cha_name>")
@login_required
def character_sheet():
    characters = db.execute(
        """SELECT
          *
        FROM
            characters
        WHERE
            user_id = :user_id AND
            name = :cha_name
        """,
        user_id=session["user_id"],
        cha_name="???",
    )

    if not characters:
        return render_template("add_char.html")

I would like to include a button that navigates to the character sheet for the specic chosen character. So the page below would detail some of the stats for the character, and then a button would take the user to a populated character sheet on another page.

This is what I have so far for displaying a specific user's characters.

{% extends "main.html" %}

{% block title %}
    Characters
{% endblock %}

{% block main %}
      <table border = 1>
         <thead>
            <td>Player</td>
            <td>Name</td>
            <td>Race</td>
            <td>Class</td>
            <td>Level</td>
            <td>Status</td>
            <td>View</td>
         </thead>

         {% for row in rows %}
            <tr>
               <td>{{ character["user"] }}</td>
               <td>{{ character["name"] }}</td>
               <td>{{ character["race"] }}</td>
               <td>{{ character["cha_class"] }}</td>
               <td>{{ character["level"] }}</td>
               <td>{{ character["status"] }}</td>
               <td><a href={{ url_for('cha_name') }}>View Sheet</a></td> <!-- HERE -->
            </tr>
         {% endfor %}

      </table>
      <a href = "/add_char">Add a new Character</a>
      <a href = "/">Go back to home page</a>

   </body>
{% endblock %}

What do I use on the line with <!-- HERE --> to make a link to the character sheet URL?

Whew, there's a lot to unpack here!

Your example is/was invalid, eg cha_name= on the end of the db.execute() call, and there are no calls to render_template if a character is found, so it'll never produce a response even with a valid request.

Next, you've told Flask to pass a cha_name parameter to your character_sheet function, but haven't defined a parameter on the function itself.

Finally, in your template you're passing cha_name to the url_for function, which (so far as we can see from the sample code) isn't a route that you've defined, so can't work.

You need to include more information for us to help, such as telling us what error you're seeing. Right now, I imagine the Flask service won't even start due to the syntax error. Once that's fixed, I'd expect to see something like the following:

werkzeug.routing.BuildError: Could not build url for endpoint 'cha_name'. Did you mean 'character_sheet' instead?

I'd suggest you head back to the documentation on URL building and also look at the docs for the route decorator . You'll see on the latter that "Flask itself assumes the name of the view function as endpoint". That means that in order to get Flask to generate a URL for your character_sheet function, you'll need to pass that name to url_for , and then the parameters, like this:

url_for('character_sheet', cha_name=character.name)

If a user were to rename their character, all of the URLs would change, which is a bad user experience — what would happen if they'd bookmarked a particular character, then fixed a typo in the name?

Putting this all together, here's a hopefully-better example:

# app.py
@login_required
@app.route("/<character_id>")
def character_sheet(character_id):
    characters = db.execute(
        """SELECT
          *
        FROM
            characters
        WHERE
            id = :id AND
            user_id = :user_id
        """,
        id=character_id,
        user_id=session["user_id"],
    )

    if not characters:
        return abort(404)

    return render_template(
        "characters/sheet.html",
        character=characters[0],
    )
<!-- templates/characters/list.html -->
{% extends "main.html" %}

{% block title %}
    Characters
{% endblock %}

{% block main %}
    <table>
         {% for character in characters %}
            <tr>
               <td>{{ character.name }}</td>
               <td><a href={{ url_for('character_sheet', character_id=character.id) }}>View Sheet</a></td>
            </tr>
         {% endfor %}
    </table>
    <a href = "{{ url_for('add_char') }}">Add a new Character</a>
{% endblock %}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM