Assign a session variable in Jinja2 / flask in front end html page - python

Hello I have a problem with a select/option html where you can select the page number, so page 1 of 100, 2 of 200 etc... and then goes to page 1, 2, 3 ...
Everything works in the following code apart from the fact that inside the select button, after clicking on the page you want to go, after refreshing the page, it goes back to page 1, it always shows: page 1 of 100, even if actually in the url the page number is correct. I should use a session variable, but the problem is that I'm struggling to understand how to use it with Flask/Jinja2 directly in the html page. Someone can help?
using {% set session['page'] = page %} and then {{ session['page'] }} it gives me syntax error:
TemplateSyntaxError: expected token 'end of statement block', got '['
{% set session['page'] = page %}
<select onchange="window.location.href=this.value">
{%- for page in range (1,(form.total_PAGE.data | int) + 1 ) %}
<option value="{{ page }}">{{ session['page'] }}/{{ form.total_PAGE.data }}</option>
{%- endfor %}
</select>

In general, you cannot assign to an object atribute using set, neither using obj['attr'] or obj.attr syntax (see the documentation). However, you can enable the expression-statement extension and then set the attribute using dict update like this:
{% do session.update({'page': page}) %}
But as already stated in the comment, this doesn't really make sense and can be solved more cleanly using other approaches.

I have tested what mentioned by Tomáš Linhart but not worked for me as I did not update Expression statement extension and modify default what worked to assign a session variable in jinja2 flask is:
{% if session.update({session_var_name: []}) %}{% endif %}

Related

Django/Wagtail - How to create a conditional in template that checks for url path?

I'm struggling to finding a quick and easy solution to show HTML content based on a conditional that checks if the wagtail page is at root, aka '/'.
According to the Wagtail docs, I can also make this work using original request object from Django:
Additionally request. is available and contains Django’s request
object.
This is essentially what I want to do. I use the page object here from wagtail but it might be better if I used the request object from Django instead. How can I
{% if page.request.path == '/' %}
<div> show something </div>
{% else %}
#show nothing
{% endif %}
How can I structure a conditional to solve what I'm trying to do?
Access request
The request object can be accessed via request and not page.request.
A helpful tip is to add {% debug %} to see ALL the context that is available to the current template while working locally and debugging.
{% if request.path == '/' %}
<div> show something </div>
{% else %}
#show nothing
{% endif %}
More info
Within Wagtail the request object should be available to all templates, however you may need to enable this by following the instructions about Using RequestContext in the Django docs.
Alternatively this Django request in template answer provides a clear example of what to update in your settings file.

Jinja List Issue

I am getting a weird problem in Jinja, I have a list endpoints, which contains dictionary for every endpoint. In each dictionary, there is a key tags which is a list. Every item in tags is itself a dictionary where the key value gives the label of a tag. endpoint may have similar tags.
A sample abstract representation of an endpoints object can be:
[ {"tags":[{"value":"car"},{"value":"place"}]} , {"tags":[{"value":"van"},{"value":"place"}]} ]
what I want is to simple display unique tags in a div. It is simple, keeping a list of all displayed tags and upon getting a tag, checking if it is already in the list, and if not display it and add it to the list. Weirdly, it's not working.
The codes are:
{% set tagValues = [] %}
{% for endpoint in endpoints %}
{% for tag in endpoint["tags"]%}
{% set tagValue = tag["tag"]["value"] %}
{% if tagValue not in tagValues %}
{% set tagValues = tagValues + [tagValue] %}
<span >{{ tagValue }}</span></a>
{% endif %}
{% endfor %}
{% endfor %}
it is not working, for example, for the enpoints list above, I am getting the following output:
car place van place
is there any problem with the codes ?
I recommend creating a distinct list of tags in your View. e.g.
distinctTags = list(set([tag for endpoint in endpoints for tag in endpoint]))
and passing that to your template
{% for tag in distinctTags %}
<span >{{ tagValue }}</span></a>
{% endfor %}
this has the advantage of the distinct tag code being reusable and the code being less procedural.
my jinja knowledge is limited, but by adding tagValues to the output, it appears that it's reset after each iteration of the outer loop. I'd guess it's to do with scopes, but don't know.
My recommendation would be to pre-process your endpoints in regular python before passing to jinja

Flask redirect on select onchange

I'm a beginner to flask and I'm making a small web scraper app. What I've done so far has created a dropdown with a list of elements. Now I want to be able to render another page when the user selects a value from the list and I want to pass that value to the next page as well.
{% extends "base.html" %}
{% block content %}
<select id = "foo" onchange="">
{% for item in Citydata %}
<option value = {{ item.link }}> {{ item.name }} </option>
{% endfor %}
</select>
{% endblock %}
This makes the list and adds in all the links and values. I know that what should happen is that when an option is selected a new route is selected/used and a new template file is loaded. But I don't know how to do it.
If you are trying to do a form submission, follow colidyre's suggestion.
It seems to me, however, that you're looking to add a variable in your path, so you will need to use Flask's Variable Rules
It is unclear what item.link is, however if you have formatted that to be associated with an item's id such as /item/1, you could create an <a> tag like so:
{% for item in Citydata %}
{{ item.name }}
{% endfor %}
That would handle populating the href properly on the front-end, next you will need to set up the proper route on the server to handle the path:
#app.route('/item/<int:item_id>')
def item_route(item_id):
# do some stuff
NOTE: you don't have to create <a> tags, but it is a bit more straight forward than <option>. To stick with <option> you would just need to add some JavaScript client-side to call the back-end service based on the selected <option>'s value attribute instead.

Jinja2 variable (string) not being printed if surrounded by {{ delimiter }}

I have a macro in jinja2 that was working perfectly up until I tried to pass a string to it that looks something like this /test/{{ vehicle.id }}. The string printed to the page is /test/.
The string is coming from a database, so I'm a little confused what's happening. It's like jinja is trying to parse the string and replace the values (which is actually what I'm trying to accomplish), but it's failing and ripping the expression out instead. I tried passing the vehicle dict to the macro as well to see if it would 'just work', but no dice. I thought if maybe I had vehicle available to the context it would work without much effort on my part.
Here's some simple sample code:
# Assume db_values.url is set to '/test/{{ vehicle.id }}'
{% macro banner(db_values, vehicle={}) %}
{% endmacro %}
And where I'm calling it:
# Assume vehicle = { 'id': '1' }
{{ vehicle.id }}
{{ db_values }}
<div class="banner-link">
{{ banner(db_values, vehicle) }}
</div>
And this is what's being outputted to the page:
1
{u'url': u'/test/'}
<div class="banner-link">
</div>
Hitting mongodb directly in terminal responds with:
{ 'url': 'test/{{ vehicle.id }}' }
Anybody else run into something like this before? Basically what I'm trying to do is allow somebody in an admin interface to use tokens in the url that are replaced at runtime based on the context of the page. Seems simple enough, but jinja keeps stripping it.
Okay, I solved this on my own. The reason my database value had the {{ vehicle.id }} syntax in it is because I wanted to jinja to parse it. So when jinja wasn't parsing it (probably because of a context issue), I took to a custom filter and I'm happily on my way.
Here's the gist of it:
Jinja2 Filter
from jinja2 import Environment
def replace_tokens(url, vehicle):
if url is not None:
url = Environment().from_string(url).render({ 'vehicle': vehicle })
return url
Macro
# Assume db_values.url is set to '/test/{{ vehicle.id }}'
{% macro banner(db_values, vehicle={}) %}
{% endmacro %}

Using variables with a django template

I have a developed a filter which does alot of database queries in my django templete. I have several uses for the same filter with the same values which will provide the same result on the same templete. I wish to save the filter result in a variable within the templete so I can make sure I dont re-run the same queries over again.
I cant send this from my view because I am doing this filter call in a for loop for each object in my model.
an example of what I need can be seen in the url tag :
{% url 'path.to.view' arg arg2 as the_url %}
I need the "as" operation over a filter.
{% with bla=arg|foo %}
{% url 'view' bla %}
{% endwith %}

Categories