I have a code where I'm flattening the jsonb column and I have created a macro for it. First, it takes three arguments model_name is the database from where I'm pulling the data,
and json_column is the column that has JSON info. Now when I transform this data and flat the result the datatype for all the fields is text. I think its because of this ->>
the operator which converts all values to string. I just want to change the type of the field to what it is. If it is a string then it's a string.
after flattening the jsonb this is what I get
{% macro flatten_json(model_name, json_column) %}
{% set survey_methods_query %}
SELECT DISTINCT(jsonb_object_keys({{json_column}})) as column_name
from {{model_name}}
{% endset %}
{% set results = run_query(survey_methods_query) %}
{% if execute %}
{# Return the first column #}
{% set results_list = results.columns[0].values() %}
{% else %}
{% set results_list = [] %}
{% endif %}
select
_airbyte_ab_id,
_airbyte_data,
{% for column_name in results_list %}
_airbyte_data ->>'{{ column_name }}' as {{ column_name }}{% if not loop.last %},{% endif %}
{% endfor %}
from {{model_name}}
{% endmacro %}
In a Djgano template I want to include a {% if x == y %} statement where both x and y are variables as follows:
<title>Category: {{category_id}}</title>
<select name="category_id">
{% for category in categories %}
<option value="{{category.id}}"
{% if category.id is category_id %} selected {% endif %}>{{category.id}} : {{category.name}}</option>
{% endfor %}
The {{category_id}} variable is set and in the context. It displays correctly if places outside of the {% if %}, but inside the {% if %} bracket does not work.
{% if category.id == category_id %}
does not work. I assume that in this case category_id is simply read as a non-variable.
{% if category.id is {{category_id}} %}
{% if category.id == {{category_id}} %}
Gives an error:
"Could not parse the remainder: '{{category_id}}' from '{{category_id}}'"
{% if category.id is category.id %}
Works, of course, but of course that means that everything in the loop will become "selected".
I'm trying to use a filter inside of an if statement and whenever I do, I get the error below.
I have looked through for typos and wasn't able to catch anything.
Details.html (the template)
{% extends "dashboard/header.html" %}
{% block content %}
{% load custom_filts %}
<h1>{{ result }} <span class="badge badge-pill badge-info" style="background-color: {{ colour | hexify }}">{{ result | get_model_name }}</span></h1>
{% if result|get_model_name == "Fixture" %}
{% block fixture_data %}
{% endblock %}
{% elif result | get_model_name == "Cable" %}
{% block cable_data %}
{% endblock %}
{% elif result | get_model_name == "Adapter" %}
{% block adapter_data %}
{% endblock %}
{% endif %}
{% endblock %}
My custom filters
from django import template
register = template.Library()
#register.filter
def get_model_name(value):
return value.__class__.__name__
#register.filter
def hexify(value):
return "#" + value
When this is used, I get this error:
TemplateSyntaxError at /dashboard/detail/1
Could not parse the remainder: '|' from '|'
I have an template:
{% if c == 2 %}
{% for time in a %}
code(1)
{% endfor %}
{% else %}
{% for time in b %}
repeat of code(1)
{% endfor %}
{% endif %}
As you can see this code has an repeating part. I want to refactor like this:
{% if c == 2 %}
var = a
{% else %}
var = b
{% endif %}
{% for time in var %}
code(1)
{% endfor %}
How to do this?
Don't do that in the template(and I don't think you can), do that in views.py instead:
var = c if c == 2 else b
# add to template context
context['var'] = var
If you add too much logic in template, people have to look at both places to figure out what's going on. But if you have all the logics in views.py it's clearer.
I would like to do something like:
variable p is from test.py which is a list ['a','b','c','d']
{% for i in p %}
{{variable++}}
{{variable}}
result output is:
1 2 3 4
You could use loop.index:
{% for i in p %}
{{ loop.index }}
{% endfor %}
Check the template designer documentation.
In more recent versions, due to scoping rules, the following would not work:
{% set count = 1 %}
{% for i in p %}
{{ count }}
{% set count = count + 1 %}
{% endfor %}
After 2.10, to solve the scope problem, you can do something like this:
{% set count = namespace(value=0) %}
{% for i in p %}
{{ count.value }}
{% set count.value = count.value + 1 %}
{% endfor %}
As Jeroen says there are scoping issues: if you set 'count' outside the loop, you can't modify it inside the loop.
You can defeat this behavior by using an object rather than a scalar for 'count':
{% set count = [1] %}
You can now manipulate count inside a forloop or even an %include%. Here's how I increment count (yes, it's kludgy but oh well):
{% if count.append(count.pop() + 1) %}{% endif %} {# increment count by 1 #}
Or...
{% set count = [] %}
{% for something-that-loops %}
{% set __ = count.append(1) %}
<div> Lorem ipsum meepzip dolor...
{{ count|length }}
</div>
{% endfor %}
(From comments by #eyettea and #PYB)
Here's my solution:
Put all the counters in a dictionary:
{% set counter = {
'counter1': 0,
'counter2': 0,
'etc': 0,
} %}
Define a macro to increment them easily:
{% macro increment(dct, key, inc=1)%}
{% if dct.update({key: dct[key] + inc}) %} {% endif %}
{% endmacro %}
Now, whenever you want to increment the 'counter1' counter, just do:
{{ increment(counter, 'counter1') }}
if anyone want to add a value inside loop then you can use this its working 100%
{% set ftotal= {'total': 0} %}
{%- for pe in payment_entry -%}
{% if ftotal.update({'total': ftotal.total + 5}) %}{% endif %}
{%- endfor -%}
{{ftotal.total}}
output = 5
Came searching for Django's way of doing this and found this post. Maybe someone else need the django solution who come here.
{% for item in item_list %}
{{ forloop.counter }} {# starting index 1 #}
{{ forloop.counter0 }} {# starting index 0 #}
{# do your stuff #}
{% endfor %}
Read more here:
https://docs.djangoproject.com/en/1.11/ref/templates/builtins/
I was struggle with this behavior too. I wanted to change div class in jinja based on counter. I was surprised that pythonic way did not work. Following code was reseting my counter on each iteration, so I had only red class.
{% if sloupec3: %}
{% set counter = 1 %}
{% for row in sloupec3: %}
{% if counter == 3 %}
{% set counter = 1 %}
{% endif %}
{% if counter == 1: %}
<div class="red"> some red div </div>
{% endif %}
{% if counter == 2: %}
<div class="gray"> some gray div </div>
{% endif %}
{% set counter = counter + 1 %}
{% endfor %}
{% endif %}
I used loop.index like this and it works:
{% if sloupec3: %}
{% for row in sloupec3: %}
{% if loop.index % 2 == 1: %}
<div class="red"> some red div </div>
{% endif %}
{% if loop.index % 2 == 0: %}
<div class="gray"> some gray div </div>
{% endif %}
{% endfor %}
{% endif %}
Just to shed more light into this problem.
Jinja2 variables behaves differently from that of conventional scripting languages, you can't modify the variable in a for loop.Hence to bypass this behaviour you can use a dictionary, since you can change the value of the dictionary.
**{% set margin={"margin_value":0} %}**
{% for lang in language %}
<ul>
<li style="margin-right: {{ margin.margin_value}}px">{{ lang }}</li>
</ul>
**{% if margin.update({"margin_value":margin.margin_value + 2}) %}
{% endif %}**
{% endfor %}
In the above code the value of the dictionary is being modified.