Seite 1 von 1
Jinja2 if-for loop-else
Verfasst: Mittwoch 17. August 2022, 12:38
von Karlirex
Hallo Leute,
ich arbeite zur Zeit an einer Webapp mit Flask und baue da eine Tabelle (HTML) die auf zwei Routings zutreffen kann, da die übergebenen Werte vom Aufbau gleich sind.
Bei den Daten übergebe ich einmal paginierte Daten, die ich im Template mit Daten.items und einer for loop darstelle. Die zweite Route übergibt an sich den gleichen Datenaufbau aber weniger Menge, weshalb ich hier die Pagination weglassen kann und hier ohne das Daten.items sonder rein mit Daten arbeiten kann.
Leider ist im Template da dann der Unterschied, welchen man normalerweise in Python über ein if..forloop else..forloop lösen könnte. Im Jinja2 steht mir hier der "Endblock" im Weg zumindest meckert so der Debugger.
Code: Alles auswählen
{% if request.method != 'POST' %}
{% for date in Daten.items %}
{%else%}
{% for date in Daten.items %}
<tr><td>{{ date.id }}</td></tr>
{%endfor%}
{%endif%}
Gibt es da vllt doch eine Möglichkeit?
*ja ich könnte die Blöcke nacheinander zweimal setzen also
Code: Alles auswählen
{% if request.method != 'POST' %}
{% for date in Daten.items %}
<tr><td>{{ date.id }}</td></tr>
{%endfor%}
{%else%}
{% for date in Daten.items %}
<tr><td>{{ date.id }}</td></tr>
{%endfor%}
{%endif%}
Dann würde ich aber aufgrund der Tabellengröße und anderen Templates etwa 40 Zeilen HTML Code "doppeln" und das gleich für 3 leicht unterschiedliche Tabellen. Daher ist die obere Variante eigentlich eleganter meiner Meinung nach.
Per Google/Docs finde ich leider nur if-Statements innerhalb der For-Loop...
Re: Jinja2 if-for loop-else
Verfasst: Mittwoch 17. August 2022, 12:51
von __blackjack__
@Karlirex: Rück das mal ordentlich ein, dann sollte klar werden warum das so nicht gehen kann. Würde es in Python auch nicht. Oder allen anderen Programmiersprachen mit diesen Strukturierten Blöcken für ``if``/``else`` und ``for``-Schleifen. Mal von der kaputten „Verzahnung“ der Syntaxkonstrukte abgesehen fehlt auch ein ``endfor``.
Re: Jinja2 if-for loop-else
Verfasst: Mittwoch 17. August 2022, 12:56
von Karlirex
@__blackjack__: habe es gerade gerückt. Im ersten Fall kann ja auch noch kein "endfor" stehen, da die Schleife ja erst nachdem <tr> geschlossen wird. Und in Pyhton funktioniert so etwas auch siehe:
Code: Alles auswählen
list = [1, 2, 3, 4, 5, 6]
x = 4
if x == 3:
for y in list:
print(y)
else:
for y in list:
print(x)
Mein Problem liegt darin, dass der <tr> -Block eben etwa 30 Zeilen enthält und es aufgrund von verschiedenen Tabellen in verschiedenen Routen ein solches Kontrukt leider öfter gibt und ich deshalb nicht 30 Zeilen Code wegen einem "if-else-for" doppeln möchte. Deshalb wollte ich mir so den <tr> - Block ein zweites Mal "sparen", wenn man dem Dont repeat yourself - Prinzip folgen würde, zumindest in meinen Augen
Re: Jinja2 if-for loop-else
Verfasst: Mittwoch 17. August 2022, 13:08
von __blackjack__
@Karlirex: In Python geht das nicht was Du im ersten Template-Beispiel machst, da kann man das nicht mal eingeben, weil die Endschlüsselworte implizit durch die Einrückung da sind. Das ist nicht eleganter sondern einfach nur kaputt, weil man Code so nicht strukturieren kann. Die Konstrukte müssen jeweils komplett sein.
Also musst Du entweder komplette Schleifen in ``if`` und ``else`` setzen, oder nur eine Schleife schreiben *in* der dann, an gegebenenfalls mehreren Stellen, die Unterschiede zwischen POST oder nicht-POST per ``if`` und gegebenenfalls ``else`` geregelt werden. Was alternativ oder zusätzlich vielleicht auch geht sind Makros. Das Äquivalent zu Funktionen in Code um Gemeinsamkeiten, eventuell parametrisiert, heraus zu ziehen.
Re: Jinja2 if-for loop-else
Verfasst: Mittwoch 17. August 2022, 13:16
von Karlirex
Das mit dem if und else selbst machen geht leider nicht, da es sich eben auf den zu iterierenden Term der Daten handelt, ich wüsste zumindest nicht, wie ich das innerhalb gestalte.
Wie gesagt, oben das ist nur Beispielhaft und die <tr> unter der for-loop sind deutlich länger und daher dann eben sehr viel "doppelt" in einem Template bzw dann anschließend in allen viern, wo ich diese Struktur bräuchte.
Aber gut schade.
Und ja das mit dem if for funktioniert so in Python auch nicht. Da das "print" in dem Sinn ja mein <tr> war, genau gleich aufgebaut klappt es nicht.
Re: Jinja2 if-for loop-else
Verfasst: Mittwoch 17. August 2022, 14:58
von __blackjack__
@Karlirex: Den ersten Satz verstehe ich inhaltlich nicht. Und auf Makros gehst Du in der Antwort auch nicht ein.
Zeig doch mal ein Beispiel das nicht so weit gekürzt ist, dass die Unterscheidung komplett sinnlos ist.
Re: Jinja2 if-for loop-else
Verfasst: Donnerstag 18. August 2022, 07:28
von Karlirex
Eine der Tabellen in der HTML-View:
Code: Alles auswählen
<tbody>
{% for adresse in Adresse %}
<tr>
<td>{{ adresse.id }}</td>
<td>{{ adresse.lbv_number }}</td>
<td>{{ adresse.th_number }}</td>
<td>{{ adresse.birthday | date_formate_html }}</td>
<td>{{ adresse.last_name }}</td>
<td>{{ adresse.first_name }}</td>
<td>{{ adresse.street }}</td>
<td>{{ adresse.city_plz }}</td>
<td>{{ adresse.city }}</td>
<td>{{ adresse.private_phone }}</td>
{% if adresse.active == 0 %}
<td>Nein</td>
{% elif adresse.active == 1 %}
<td>Ja</td>
{% else %}
<td>###</td>
{% endif %}
<td>{{ adresse.family }}</td>
<td>{{ adresse.enter_date }}</td>
<td>{{ adresse.comment }}</td>
<td>{{ adresse.group.group_name}}</td>
<td>{{ adresse.status }}</td>
<td><a style="color: black" href = "{{ url_for('adressen_details', adressen_id=adresse.id) }}">Details</a></td>
<td><a style="color: black" href = "{{ url_for('adressen_update', adressen_id=adresse.id) }}">Bearbeiten</a></td>
{% if check_role('Admin') %}
<td><a style="color: black" href = "{{ url_for('adressen_delete', adressen_id=adresse.id) }}" onclick="return confirm('{{ adresse.last_name }} wirklich löschen?')" class = "btn">Löschen</a></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
Mit dem möglichen Vorschlag müsste ich diesen Block ja unter das else nocheinmal schreiben. Was das Ganze wie gesagt sehr aufbläht. Und ich habe 5 solcher Tabellen, die eben unterschiedlich viele Spalten haben/aus unterschiedlichen Datenbanken kommen.
Das mit den Makros müsste ich mir erst anschauen, um darauf näher eingehen zu können.
Re: Jinja2 if-for loop-else
Verfasst: Donnerstag 18. August 2022, 08:21
von Karlirex
Ich habs jetzt übers backend und einem if vor der pagination gelöst:
HTML
Code: Alles auswählen
<tbody>
{% for adresse in Adresse %}
<tr>
<td>{{ adresse.id }}</td>
<td>{{ adresse.lbv_number }}</td>
<td>{{ adresse.th_number }}</td>
<td>{{ adresse.birthday | date_formate_html }}</td>
<td>{{ adresse.last_name }}</td>
<td>{{ adresse.first_name }}</td>
<td>{{ adresse.street }}</td>
<td>{{ adresse.city_plz }}</td>
<td>{{ adresse.city }}</td>
<td>{{ adresse.private_phone }}</td>
{% if adresse.active == 0 %}
<td>Nein</td>
{% elif adresse.active == 1 %}
<td>Ja</td>
{% else %}
<td>###</td>
{% endif %}
<td>{{ adresse.family }}</td>
<td>{{ adresse.enter_date }}</td>
<td>{{ adresse.comment }}</td>
<td>{{ adresse.group.group_name}}</td>
<td>{{ adresse.status }}</td>
<td><a style="color: black" href = "{{ url_for('adressen_details', adressen_id=adresse.id) }}">Details</a></td>
<td><a style="color: black" href = "{{ url_for('adressen_update', adressen_id=adresse.id) }}">Bearbeiten</a></td>
{% if check_role('Admin') %}
<td><a style="color: black" href = "{{ url_for('adressen_delete', adressen_id=adresse.id) }}" onclick="return confirm('{{ adresse.last_name }} wirklich löschen?')" class = "btn">Löschen</a></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% if request.method != 'POST' %}
<div class="pagination">
{% if pagination.has_prev %}
<span>
<a class='page-number' href="{{ url_for('adressen_all', page=pagination.prev_num) }}">
{{ '<<<' }}
</a>
</span>
{% endif %}
{% for number in pagination.iter_pages() %}
{% if pagination.page != number %}
<span>
<a class='page-number'
href="{{ url_for('adressen_all', page=number) }}">
{{ number }}
</a>
</span>
{% else %}
<span class='current-page-number'>{{ number }}</span>
{% endif %}
{% endfor %}
{% if pagination.has_next %}
<span>
<a class='page-number'
href="{{ url_for('adressen_all', page=pagination.next_num) }}">
{{ '>>>' }}
</a>
</span>
{% endif %}
</div>
{% endif %}
Backend
Code: Alles auswählen
@app.route('/adressen/')
@login_required
def adressen_all():
if request.method != 'POST':
pagination = Adressen.query.paginate(request.args.get('page', 1, type=int), per_page=20)
adressen_view = pagination.items
else: adressen_view = Adressen.query.all()
return render_template("HTML/Adressen/adressen_all.html", Adresse=adressen_view, pagination=pagination, title='Adressen')
Dafür musste ich die Routen logischerweise überall an passen, aber ich habe nur "4" Zeilen bei den Routen ähnlich und keine 30 im HTML Block doppelt. *zufrieden*
Re: Jinja2 if-for loop-else
Verfasst: Donnerstag 18. August 2022, 21:35
von Sirius3
`pagination` wird im else-Zweig nicht definiert. Nach einem : fängt immer eine neue Zeile an.
Und man schreibt keine komplizierte Logik ins Template. Welche Request-Methode benutzt wird, sollte dem Template egal sein.
Code: Alles auswählen
def adressen_all():
if request.method != 'POST':
pagination = Adressen.query.paginate(request.args.get('page', 1, type=int), per_page=20)
adressen_view = pagination.items
else:
pagination = None
adressen_view = Adressen.query.all()
return render_template("HTML/Adressen/adressen_all.html", Adresse=adressen_view, pagination=pagination, title='Adressen')
Wenn in jedem if-Teil die selben Tags stehen, dann gehören die drumrum. Warum packst Du einen literalen String in {{}}?
Code: Alles auswählen
<table>
<tbody>
{% for adresse in Adresse %}
<tr>
<td>{{ adresse.id }}</td>
<td>{{ adresse.lbv_number }}</td>
<td>{{ adresse.th_number }}</td>
<td>{{ adresse.birthday | date_formate_html }}</td>
<td>{{ adresse.last_name }}</td>
<td>{{ adresse.first_name }}</td>
<td>{{ adresse.street }}</td>
<td>{{ adresse.city_plz }}</td>
<td>{{ adresse.city }}</td>
<td>{{ adresse.private_phone }}</td>
<td>{% if adresse.active == 0 %}Nein{% elif adresse.active == 1 %}Ja{% else %}###{% endif %}</td>
<td>{{ adresse.family }}</td>
<td>{{ adresse.enter_date }}</td>
<td>{{ adresse.comment }}</td>
<td>{{ adresse.group.group_name}}</td>
<td>{{ adresse.status }}</td>
<td><a style="color: black" href = "{{ url_for('adressen_details', adressen_id=adresse.id) }}">Details</a></td>
<td><a style="color: black" href = "{{ url_for('adressen_update', adressen_id=adresse.id) }}">Bearbeiten</a></td>
{% if check_role('Admin') %}
<td><a style="color: black" href = "{{ url_for('adressen_delete', adressen_id=adresse.id) }}" onclick="return confirm('{{ adresse.last_name }} wirklich löschen?')" class = "btn">Löschen</a></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% if pagination %}
<div class="pagination">
{% if pagination.has_prev %}
<span><a class='page-number' href="{{ url_for('adressen_all', page=pagination.prev_num) }}"> <<<</a></span>
{% endif %}
{% for number in pagination.iter_pages() %}
{% if pagination.page != number %}
<span><a class='page-number' href="{{ url_for('adressen_all', page=number) }}">{{ number }}</a></span>
{% else %}
<span class='current-page-number'>{{ number }}</span>
{% endif %}
{% endfor %}
{% if pagination.has_next %}
<span><a class='page-number' href="{{ url_for('adressen_all', page=pagination.next_num) }}"> >>></a></span>
{% endif %}
</div>
{% endif %}
Re: Jinja2 if-for loop-else
Verfasst: Donnerstag 18. August 2022, 23:01
von __blackjack__
@Sirius3: Also zumindest ``{{ "<<<" }}`` finde ich schöner/lesbarer als die Alternative ``<<<``. Während man bei ``>>>`` das einfach schreiben könnte, sieht man da nicht selten aus ”Symmetriegründen” ``>>>``, und auch da finde ich dann ``{{ ">>>" }}`` irgendwie schöner zu lesen. Ist wahrscheinlich Geschmackssache.