Jinja2: Flask's url_for() combined with Knocko

2019-07-10 01:44发布

I'm using Flask and Knockout together in a web application with Jinja2 as the templating engine. In my Flask application I have two routes: /accounts/ and /accounts/<int:acc_id>/, which look something like this:

@app.route("/accounts/")
@login_required
def accounts():
    return render_template("accounts.html")


@app.route("/accounts/<int:acc_id>/")
@login_required
def account(acc_id):
    return render_template("account.html",
        account_id=acc_id)

The /accounts/ route loads an HTML page with a Knockout view model. The view model then AJAX loads a list of accounts into an observableArray and renders something like this:

<!-- ko foreach: accounts -->
    <span data-bind="text: name></span>
<!-- /ko -->

The /accounts/<int:acc_id>/ route displays information about a single account.

What I'm trying to do is create an href attribute on each account in the HTML snippet above using url_for(), passing the account's id as a parameter. I'm having trouble making the Python call to url_for() with a parameter from the Knockout model.

A couple of variations I've tried so far:

Concatenating the id into the url_for function call:

<a data-bind="attr: { href: '{{ url_for('account', acc_id=' + id() + ' }}'}">
    <span data-bind="text: name"></span>
</a>

This produces a ValueError: invalid literal for int() with base 10: '+ id() +' since it reads the call to id() as a string literal.

Creating a function in the view model that returns the url_for string:

self.accountUrl = function(account_id) {
    return '{{ url_for("admin.account", acc_id=' + account_id + ') }}';
};

and calling it like so:

<a data-bind="attr: { href: $root.accountUrl(id()) }">
    <span data-bind="text: name"></span>
</a>

This results in the href attribute being set as the string literal returned from accountUrl(), i.e. the HTML looks like this:

<a href='{{ url_for("account", acc_id=1) }}'>

I feel like there's something I must be overlooking here. Any ideas?

1条回答
爷、活的狠高调
2楼-- · 2019-07-10 02:12

Your python code (url_for) runs on the server side when the HTML is generated but the Knockout code runs your in the browser when the page is rendered. So you cannot pass variables from Knockout into to the python url_for method.

What you can do is to generate only the /accounts/ and build the rest of the URL with KO:

<a data-bind="attr: { href: '{{ url_for('account') }}' + '/' + id() }">
    <span data-bind="text: name"></span>
</a>
查看更多
登录 后发表回答