run query with for loop dbt jinja - python

I have a list of tables and I want to run query using for ... in [] . After running code below I have an error. Where could be mistake?
I just want to print the result. Result I expect in a list for example [2,67,0,7].
tables = [
'table_1'
,'table_2'
,'table_3'
,'table_4'
,'table_5'
]
{%- call statement('my_statement', fetch_result=True) -%}
select count(*) as cnt
from {% for n in tables %} my_schema.n {% endfor %}
where students = 'great'
{%- endcall -%}
{%- set my_var = load_result('my_statement') -%}
{{my_var}}
OR I used it:
{%- set query -%}
select count(*) as cnt
from {% for n in tables %} my_schema.n {% endfor %}
where students = 'great'
{%- endset -%}
{% set results = run_query(query) %}
{{ results }}

Does this do what you want?
{% macro print_multi_tables() %}
{% set tables = ['table_1', 'table_2', 'table_3', 'table_4', 'table_5'] %}
{% set ns = namespace(query_results = [], final_result = '[') %}
{% set query_results = [] %}
{% for table_name in tables %}
{% set query %}
select count(*) from {{ ref(table_name) }} where students = 'great'
{% endset %}
{{ log(query, true) }}
{% set results = run_query(query) %}
{% set count = results.rows[0][0] %}
{% set query_results = query_results.append(count) %}
{% endfor %}
{# This gives a result like [Decimal('2'), Decimal('8')], so #}
{# there is more code below to print the exact results you want #}
{{ log(query_results, true) }}
{# Print the results in the format [result_1, result_2, etc] #}
{% for x in query_results %}
{% set ns.final_result = ns.final_result ~ x %}
{% if not loop.last %}
{% set ns.final_result = ns.final_result ~ ', ' %}
{% endif %}
{% endfor %}
{% set ns.final_result = ns.final_result ~ ']' %}
{{ log(ns.final_result, true) }}
{% endmacro %}
Results will look like
16:44:08
select count(*) from my_database.my_schema.table_1 where students = 'great'
16:44:08
select count(*) from my_database.my_schema.table_2 where students = 'great'
16:44:08
select count(*) from my_database.my_schema.table_3 where students = 'great'
16:44:08 [Decimal('2'), Decimal('6'), Decimal('8')]
16:44:08 [2, 6, 8]

Related

Django. Access list index in child for loop

How can I change the accessed index of an inner for loop list based on a counter from the outer loop? In normal python I would do something like
parent_list = ['One','Two','Three']
child_list = ['A','B','C']
for idx, item in enumerate(parent_list):
for child_item in child_list[idx]:
print(str(idx), item, child_item)
I've been looking at using with and forloop.counters but I either run into the index not being accessed or index not changing. This is what I currently have.
{% for item in payout_items %}
{% with forloop.counter0 as outer_counter %}
<h2>{{ item.market_place }} on {{ item.entry_date }}:
{% for item in royalty_items.outer_counter %}
<tr>
<th scope="row">{{ item.id }}</th>
<td>{{ item.entry_date }}</td>
<td>{{ item.market_place }}</td>
</tr>
{% endfor %}
{% endwith %}
{% endfor %}
If I change
{% for item in royalty_items.outer_counter %}
to
{% for item in royalty_items.0 %}
I get the first index repeated many times. I can see that outer_counter is incrementing from the output but just need royalty_items to increment the accessed index as well.
As requested the view is
detail_object = AccountingPeriod.objects.get(pk=detail_id)
payout_items = Payout.objects.filter(sales_period_start__range=[detail_object.period_start, detail_object.period_end])
royalty_items = []
for payout in payout_items:
temp = Royalty.objects.filter(entry_date__range=[payout.sales_period_start, payout.sales_period_end]).filter(market_place=payout.market_place)
print(str(payout.sales_period_start) + " - " + str(payout.sales_period_end) + " - " + payout.market_place + " = " + str(len(temp)))
royalty_items.append(temp)
And the following render call is passed.
render(request, 'royalties/accounting_period/summary.html', {'detail_object': detail_object, 'payout_items': payout_items, 'royalty_items': royalty_items})
Solution: I created a template filter but feel there should be a more elegant answer.
#register.filter()
def getRoyaltySet(royalty_items, outer_counter):
return royalty_items[outer_counter]
I would just add this to the items, so:
detail_object = get_object_or_404(AccountingPeriod, pk=detail_id)
payout_items = Payout.objects.filter(
sales_period_start__range=(
detail_object.period_start,
detail_object.period_end,
)
)
for payout in payout_items:
temp = Royalty.objects.filter(
entry_date__range=(payout.sales_period_start, payout.sales_period_end),
market_place=payout.market_place,
)
print(
f'{payout.sales_period_start} - {payout.sales_period_end} - {payout.market_place} = {len(temp)}'
)
payout.royalities = temp
Then you can access this through .royalities:
{% for item in payout_items %}
<h2>{{ item.market_place }} on {{ item.entry_date }}</h2>:
{% for subitem in item.royalites %}
<!-- … -->
{% endfor %}
{% endfor %}
You can use forloop.parentloop to get to the outer forloop
{{ forloop.parentloop.counter }}
You can even chain them if you have nested loops:
{{ forloop.parentloop.parentloop.counter }}
If you wanna absolutely use your own index you can access the dictionary with .items:
{% for key, value in mydict.items %}
{% for key2, value2 in otherdict.items %}
<div>{{ key }} - {{ key2 }}</div>
{% endfor %}
{% endfor %}

Comma separating a list of dictionary items using jinja template

I have a list of dictionaries that needs to be comma-separated except for last item.
For eg list of dictionaries should be something like this:
education_details: [{degree: "B.S.", type: "Full-type", location:"aus",grade:"A"}, {degree: "MCA", type: "Full-type", location:"aus",grade:"B"}]
I was rendering the above details(education_details) in my jinja template like below:
{% for data in profile.get('education_details', []) %}
{% if data.get('degree', '') %}
{% if not loop.last %}
<span>{{data.get('degree', '')}},</span>
{% else %}
<span>{{data.get('degree', '')}}</span>
{% endif %}
{% endif %}
{% if data.get('type', '') %}
{% if not loop.last %}
<span>{{data.get('type', '')}},</span>
{% else %}
<span>{{data.get('type', '')}}</span>
{% endif %}
{% endif %}
{% if data.get('location', '') %}
{% if not loop.last %}
<span>{{data.get('location', '')}},</span>
{% else %}
<span>{{data.get('location', '')}}</span>
{% endif %}
{% endif %}
{% endfor %}
I tried by using last, it's not working
Expected o/p:
Commas to appear after each field except for the last entered item
degree
degree, type, location
degree, location
Based on your sample data and expected o/p, I assume you want the output like this:
B.S., Full-type, aus
MCA, Full-type, aus
If this is the case, what you want is to print each list item row by row and to print each dictionary item's value one by one separated by , except last value.
If so, there is no need to use loop.last at all, instead, you just need to check the sequence of each dictionary key. Below is the code snippet (flask + jinja2) for that:
template = """
{% for data in profile.get('education_details', []) %}
{% if data.get('degree', '') %}
<span>{{data.get('degree', '')}},</span>
{% endif %}
{% if data.get('type', '') %}
<span>{{data.get('type', '')}},</span>
{% endif %}
{% if data.get('location', '') %}
<span>{{data.get('location', '')}}</span>
{% endif %}
<br/>
{% endfor %}
"""
education_details = [{"degree": "B.S.", "type": "Full-type", "location":"aus","grade":"A"},
{"degree": "MCA", "type": "Full-type", "location":"aus","grade":"B"}]
return render_template_string(template, profile={"education_details": education_details})
template:
{%- set listkeys = ['degree', 'type', 'location'] %}
{%- for data in profile.get('education_details', []) %}
{%- set nbr = namespace(value=0) %}
{%- for k in listkeys %}
{%- if data.get(k, '') %}{%- set nbr.value = nbr.value + 1 %}{%- endif %}
{%- endfor %}
{%- for k in listkeys %}
{%- if data.get(k, '') %}
{%- set nbr.value = nbr.value - 1 %}
{%- if nbr.value > 0 %}
<span>{{data.get(k, '')}},</span>
{%- else %}
<span>{{data.get(k, '')}}</span>
{%- endif %}
{%- endif %}
{%- endfor %}
<br/>
{%- endfor %}
playtest:
education_details = [{"degree": "B.S.", "location":"aus","grade":"A"},
{"degree": "B.S."},
{"degree": "B.S.","grade":"A"},
{"degree": "B.S.", "type": "Full-type","grade":"A"},
{"type": "Full-type", "grade": "A"},
{"degree": "MCA", "type": "Full-type", "location":"aus","grade":"B"}]
result:
<span>B.S.,</span>
<span>aus</span>
<br/>
<span>B.S.</span>
<br/>
<span>B.S.</span>
<br/>
<span>B.S.,</span>
<span>Full-type</span>
<br/>
<span>Full-type</span>
<br/>
<span>MCA,</span>
<span>Full-type,</span>
<span>aus</span>
<br/>
EDIT
template without namespace:
{%- set listkeys = ['degree', 'type', 'location'] %}
{%- for data in profile.get('education_details', []) %}
{%- set nbr = {'value': 0} %}
{%- for k in listkeys %}
{%- if data.get(k, '') %}{%- set _ = nbr.update({'value': nbr.value + 1}) %}{%- endif %}
{%- endfor %}
{%- for k in listkeys %}
{%- if data.get(k, '') %}
{%- set _ = nbr.update({'value': nbr.value - 1}) %}
{%- if nbr.value > 0 %}
<span>{{data.get(k, '')}},</span>
{%- else %}
<span>{{data.get(k, '')}}</span>
{%- endif %}
{%- endif %}
{%- endfor %}
<br/>
{%- endfor %}
you could use macro:
{%- macro inc(dct, key, inc=1) -%}
{%- if dct.update({key: dct[key] + inc}) %}{%- endif -%}
{%- endmacro -%}
{%- set listkeys = ['degree', 'type', 'location'] %}
{%- for data in profile.get('education_details', []) %}
{%- set nbr = {'value': 0} %}
{%- for k in listkeys %}
{%- if data.get(k, '') -%}{{ inc(nbr, 'value', 1) }}{%- endif %}
{%- endfor %}
{%- for k in listkeys %}
{%- if data.get(k, '') -%}
{{ inc(nbr, 'value', -1) }}
{%- if nbr.value > 0 %}
<span>{{data.get(k, '')}},</span>
{%- else %}
<span>{{data.get(k, '')}}</span>
{%- endif %}
{%- endif %}
{%- endfor %}
<br/>
{%- endfor %}

How to write a condition inside a jinja expression

I have a jinja expression as:
{% if meaning['example'] %}
{{ meaning['example'] }}<br>
{% endif %}
Which gives me o/p:
you don't know jack
Here word['word'] has the value jack in the o/p
How can I make the jack bold in the expression?
WRT SO I have tried as:
{{ <strong>word['words']</strong> if word['words'] in meaning['example'] }}
But this didn't work , Any help is much appreciated , TIA
{% if meaning['example'] %}
{% for w in meaning['example'] %}
{% if w == word['word']%}
<strong>{{w}} </strong>
{% else %}
{{w}}
{% endfor %}
{% endif %}
if you have number of word then replace
{% if w == word['word']%} -->> {% if w in word %}
You have a couple of options:
in an if block
{% if word['words'] in meaning['example'] %}
<strong>word['words']</strong> }}
{% endif %}
in a ternary if expression
{{ '<strong>' + word['words'] + '</strong>' if word['words'] in meaning['example'] else '' }}
I personally prefer the first option if I want to write markup, or the conditional expression is relatively long as in your example.
For anyone's ref
Thanks for #Mayank Jain comment from where i digged this solution for my Q :
{% if meaning['example'] %}
{% for w in meaning['example'].split(' ') %}
{% if w == word['word']%}
<strong>{{w}} </strong>
{% else %}
{{w}}
{% endif %}
{% endfor %}
{% endif %}

Python Jinjna variable doesnt keep value outside loop

I am currently trying to fix an issue by using jinja variables, but somehow the variable does not keep the value outside the loop, even though I declared it before the loop begins:
{% set disablecounter = 0 %}
{% if disablecounter == 0 %}
{% for einzelroom in all_einzelzimmer %}
{% if zimmer.id == einzelroom.zimmer_id %}
{% set price = einzelroom.preis %}
<div class="preis-element">
<p class="preis"> <span class="smallab"> ab </span> {{ price|int }}€ </p>
</div>
{% set disablecounter = disablecounter + 1 %}
{{ disablecounter }}
{% endif %}
{% endfor %}
{% endif %}
{{ disablecounter }}
The variable is disablecounter inside the loop it is 1 but outside it is still 0
Thanks!
EDIT
Surrounding with a with statement also didnt worked:
{% with foo = 42 %}
{{ foo }}
{% endwith %}
{% with %}
{% set foo = 42 %}
{{ foo }}
{% endwith %}
I found a great solution here on SO by #Chris Warth.
Original answer by #Peter Hollingsworth:
https://stackoverflow.com/a/32700975/5291566
{% with disablecounter = [0] %}
{% if disablecounter == [0] %}
{% for einzelroom in all_einzelzimmer %}
{% if zimmer.id == einzelroom.zimmer_id %}
<div class="preis-element">
<p class="preis"> <span class="smallab"> ab </span> {{ einzelroom.preis|int }}€ </p>
</div>
{% if disablecounter.append(disablecounter.pop() + 1) %}{% endif %}
{% endif %}
{% endfor %}
{% endif %}

Jinja2: Change the value of a variable inside a loop

I want to change the value of the variable declared outside the loop within a loop. But always changing, it keeps the initial value outside the loop.
{% set foo = False %}
{% for item in items %}
{% set foo = True %}
{% if foo %} Ok(1)! {% endif %}
{% endfor %}
{% if foo %} Ok(2)! {% endif %}
This renders:
Ok(1)!
So the only (bad) solution have found so far was this:
{% set foo = [] %}
{% for item in items %}
{% if foo.append(True) %} {% endif %}
{% if foo %} Ok(1)! {% endif %}
{% endfor %}
{% if foo %} Ok(2)! {% endif %}
This renders:
Ok(1)!
Ok(2)!
But, its is very ugly! Is there another more elegant solution?
Try also dictionary-based approach. It seems to be less ugly.
{% set vars = {'foo': False} %}
{% for item in items %}
{% if vars.update({'foo': True}) %} {% endif %}
{% if vars.foo %} Ok(1)! {% endif %}
{% endfor %}
{% if vars.foo %} Ok(2)! {% endif %}
This also renders:
Ok(1)!
Ok(2)!
as mentioned in the documentation:
Please note that assignments in loops will be cleared at the end of
the iteration and cannot outlive the loop scope.
but as of version 2.10 you can use namespaces:
{% set ns = namespace(foo=false) %}
{% for item in items %}
{% set ns.foo = True %}
{% if ns.foo %} Ok(1)! {% endif %}
{% endfor %}
{% if ns.foo %} Ok(2)! {% endif %}
You could do this to clean up the template code
{% for item in items %}
{{ set_foo_is_true(local_vars) }}
{% if local_vars.foo %} Ok(1)! {% endif %}
{% endfor %}
{% if local_vars.foo %} Ok(2)! {% endif %}
And in the server code use
items = ['item1', 'item2', 'item3']
#---------------------------------------------
local_vars = { 'foo': False }
def set_foo_is_true(local_vars):
local_vars['foo'] = True
return ''
env.globals['set_foo_is_true'] = set_foo_is_true
#---------------------------------------------
return env.get_template('template.html').render(items=items, local_vars=local_vars)
This could be generalized to the following
{{ set_local_var(local_vars, "foo", False) }}
{% for item in items %}
{{ set_local_var(local_vars, "foo", True) }}
{% if local_vars.foo %} Ok(1)! {% endif %}
{% endfor %}
{% if local_vars.foo %} Ok(2)! {% endif %}
And in the server code use
items = ['item1', 'item2', 'item3']
#---------------------------------------------
local_vars = { 'foo': False }
def set_local_var(local_vars, name, value):
local_vars[name] = value
return ''
env.globals['set_local_var'] = set_local_var
#---------------------------------------------
return env.get_template('template.html').render(items=items, local_vars=local_vars)

Categories