Python Flask Jinja Dynamic routing - python

On the html page
{{ item.filename }}
On the flask routing code :
#app.route("/<username>/<filename>")
def downloadimage(username, filename):
However, this isn't routing the routing method.
What's the issue here ?

You can use the url_for method here.
Use it like this:
{{ item.filename }}
Here, downloadimage is the name of the function added to the required URL, username and filename are the parameters that should be passed to the function.

Related

how to concate variables in url_for jinja2 flask? [duplicate]

I have a route defined like this:
#app.route('/magic/<filename>')
def moremagic(filename):
pass
And now in a template I want to call that route using url_for() like so:
<h1>you uploaded {{ name }}<h1>
Click to see magic happen
I have tried:
Click to see magic happen
That throws a jinja2.TemplateSyntaxError: expected token ':' got }
Can anyone suggest how to get the {{ name }} that appears in the template into the url_for() so that when I click I call the correct app.route?
Everything inside the {{ ... }} is a Python-like expression. You don't need to use another {{ ... }} inside that to reference variables.
Drop the extra brackets:
<h1>you uploaded {{ name }}<h1>
Click to see magic happen
(Note that the url_for() function takes the endpoint name, not a URL path; the name defaults to the name of the function, moremagic in your example).

How do is pass dictionaries to url_for in Flask

I want to pass an endpoint to url_for where the endpoint contains name=value parameters where the name is a variable.
Basically i have multiple templates which could be collapsed down to one template if I could pass parameter variable names. A solution could be to pass a dictionary, but there may be other ways. I could definitely do it by post-processing the html jinja generates before it gets rendered.
I have tried all the obvious tricks I can think of including nested {{ }}.
So at the end of my route code I have
# routes.py
...
#bp.route('/customer/add/prompt/<customer_id>',methods = ['POST', 'GET'])
#login_required
def customer_add_prompt(customer_id):
#code code code
return render_template('customer_add.html',
customer_id = customer_id)
Indeed I have lots of routes for different subjects (customer, product, invoice) that all end this way. So for each subject I need a jinja template that looks like this.
# customer_add.html
...
<form action = "{{ url_for(customer_add, customer_id = customer_id) }}" method = "POST">
<-- html htlm htlm -->
</form>
When the user submits the form the endpoint for customer_add is followed and customer_add expects and is passed customer_id = 1234 (or whatever the value is).
Here is the problem. I should be able to combine all the templates like so.
# subject_add.html
...
<form action = "{{ url_for(subject_target, subject = subject_id) }}" method = "POST">
<-- html htlm htlm -->
</form>
Then render it like so.
# routes.py
...
#bp.route('/customer/add/<customer_id>',methods = ['POST', 'GET'])
#login_required
def customer_add_prompt(customer_id):
#code code code
subject_target = 'customer_add.html'
subject = 'customer_id'
subject_id = customer_id
return render_template(subject_target,
subject = subject_id)
When I do this I get an error saying Could not build url for endpoint 'customer_add' with values ['subject']. Did you forget to specify values ['entity_id']?
Testing shows that subject_target and subject_id get substituted for fine. But subject is not substituted for because in the url_for syntax it is a parameter name and the endpoint is expecting a value for a variable named customer_id not subject.
I am hoping there is a way to say what the parameter name will be in jinja. Generalising I may want to pass a dictionary of parameters.
Ideally I could pass d = {'subject': x, ...} like this url_for(subject_action, d) and Jinja would regard this as equivalent to url_for(subject_action, subject=1234, ... when x=1234.
You can add arguments to url_for(). As per the docs:
Variable arguments that are unknown to the target endpoint are
appended to the generated URL as query arguments
so you can do
<form action = "{{ url_for(action_target,
subject_type=subject_id,
2nd_variable=2nd_variable,
etc...) }}" method = "POST">
But as wonka said you'd probably be better off sending data as POST params.
If I misunderstood and your trying to pass data from your render_template call in your view then you can do that too.
return render_template('template_name.html',
data={
"action_type": "action",
"subject_type": subject_value
})
which you can then access in your template using {{data["subject_type"]}}
The answer turns out to be obvious. Instead of evaluating url_for in the template using jinja, evaluate it in the route and pass the result to jinja via render_template.

Python flask 'generating urls'?

I'm pretty new to flask any web development in general. So I was wondering how you generate a link. as in, when somene registers on your website you create a link like site.com/leak1953 and that would be their profile.
For generating links there exists the function flask.url_for() which generates a URL given the endpoint with a method provided. You can use this function also in JINJA2 templates. To provide an external link use
{{ url_for('index.main', _external=True) }}
If you want to include parameters to the url just add them to the url_for parameters.
{{ url_for(show_user_profile, username='Klaus') }}
Variable Rules
To add variable parts to a URL you can mark these special sections as . Such a part is then passed as a keyword argument to your function. Optionally a converter can be used by specifying a rule with <converter:variable_name>.
#app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
#app.route('/post/<int:post_id>')
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post %d' % post_id
source: http://flask.pocoo.org/docs/0.12/quickstart/#variable-rules

python flask url_for is throwing constant werkzeug build errors

I am having a flask url_for('') error in a very simple application.
from flask import Blueprint, render_template, abort
from jinja2 import TemplateNotFound
base = Blueprint('main', __name__)
#base.route('/', defaults={'page':'home'})
#base.route('/<page>')
def show(page):
try:
return render_template('%s.html'%page, name='my name is')
except TemplateNotFound:
abort(404)
the above is my blueprints file, those routes work fine but if I try to do
with flask.test_request_context():
print url_for('home') #home.html or any other forms
I just get this error:
raise BuildError(endpoint, values, method)
werkzeug.routing.BuildError: ('home', {}, None)
can anyone help me figure out what's going on here?
in my html page I can print out the location of static files with:
{{ url_for('static', filename='style.css') }}
but if i try to do:
{{ url_for('home') }}
Again I get the same error. Anyone have some advise as how to proceed?
You're trying to use url_for the wrong way round, I think.
url_for in general maps an endpoint, i.e. a python function/method, to an url. In your case home is the value of a parameter, not an endpoint.
So, instead, use the name of the python function you want the url for:
url_for('show', page='home')
Should be what you're looking for.
When you do {{ url_for('home') }} it doesn't return route of home.html instead it returns the route of a function home, which by the way doesn't exist.
So to fix your problem,
The proper way of using url_for is :
{{ url_for('show') }}

Flask URL Routing

If I'm making a blog site and I want to set up routing such that
#app.route('/<username>/<postname>', methods=['GET'])
routes to the post with name 'postname' of the user with name 'username', how do I get the html to recognize this? I've been trying to do something like
<a href={{ url_for('/', username=user.name, postname=post.name) }}>{{post.name}}</a>
I'm also trying to reconcile this with Flask understanding special keywords /login or /about so that it checks if the user is trying to access those first. How can I implement those checks?
The first argument to url_for in your template should be the name of the view function you decorated:
#app.route('/<username>/<postname>', methods=['GET'])
def view_user_post(username, postname):
^^^^^^^^^^^^^^
Now, you can write this in your template:
{{ url_for('view_user_post', username=user.name, postname=post.name) }}
This lets you change the URL in the route without having to update it elsewhere in your codebase.

Categories

Resources