it-swarm.com.de

So können Sie eine Liste von Wörterbüchern in Flask/Jinja auswählen/reduzieren

Ich habe eine Jinja-Vorlage mit einer Liste von Wörterbüchern. Ordnung ist wichtig. Ich möchte die Liste oder die Suchwerte basierend auf den Schlüsseln/Werten der Wörterbücher reduzieren. Hier ist ein Beispiel:

{%
    set ordered_dicts = [
        {
            'id': 'foo',
            'name': 'My name is Foo'
        },
        {
            'id': 'bar',
            'name': 'My name is Bar'
        }
    ]
%}

Wenn ich eine Variable some_id = 'foo' habe, wie bekomme ich 'My name is Foo' aus ordered_dicts in meiner Jinja-Vorlage? 

Ich habe select() und selectattr() ausprobiert, konnte sie aber aufgrund der Dokumentation nicht ermitteln. Folgendes habe ich versucht:

{{ ordered_dicts|selectattr("id", "foo") }}

Das gibt aus: 

<generator object _select_or_reject at 0x10748d870>

Ich glaube nicht, dass ich die Verwendung von select() und selectattr() richtig verstehe. 

Muss ich die Liste durchlaufen und die Suche manuell durchführen?


Update: 

Wie Codegeek und Gipi darauf hinwiesen, muss ich mit dem Generator so etwas tun:

{{ ordered_dicts|selectattr("id", "foo")|list }}

Der resultierende Fehler: TemplateRuntimeError: no test named 'foo', der die Funktionsweise von selectattr() erläutert. Das zweite Argument muss die eingebauten Tests sein. Soweit ich das beurteilen kann, kann ich bei keinem dieser Tests überprüfen, ob der einem Schlüssel zugeordnete Wert einem anderen Wert entspricht. Folgendes möchte ich tun:

{{ ordered_dicts|selectattr("id", "sameas", "foo")|list }}

Das funktioniert aber nicht, da der sameas-Test prüft, ob zwei Objekte tatsächlich das gleiche Objekt im Speicher sind, und nicht, ob zwei Zeichenfolgen/Zahlen gleich sind. 

Ist es also möglich, einen Artikel anhand eines Schlüssel/Wert-Vergleichstests auszuwählen?

19
No Surprises

Ich habe gerade equalto so portportiert:

app.jinja_env.tests['equalto'] = lambda value, other : value == other

Danach dieses Beispiel aus 2.8 Dokumenten funktioniert:

{{ users|selectattr("email", "equalto", "[email protected]") }}

Update: Flask hat einen Dekorator zum Registrieren von Tests, etwas reinere Syntax: http://flask.pocoo.org/docs/api/#flask.Flask.template_test

22
artvolk

Für Leute, die kein selectattr haben (z. B. sind Sie mit Jinja2.6 beschäftigt) und möchten keinen weiteren benutzerdefinierten Filter erstellen, lösen diese 2 Zeilen Ihr Problem schnell.

{% set selection = [] %}
{% for x in biglist if x.criteria == 'pickme' %}{% do selection.append(x) %}{% endfor %}
3
Aikude

Schauen Sie sich https://github.com/ansible/ansible/issues/8836 für dieses Problem an.

Eine Lösung/Workaround besteht darin, eine Datei filter_plugins/core.py in Ihrem Arbeitsmappenverzeichnis mit folgendem Inhalt zu erstellen:

def filter_list(list, key, value):
    return filter(lambda t: t[key] == value, list)

class FilterModule(object):
    def filters(self):
        return {
            'byattr': filter_list
        }

Und benutze es so:

{{ ordered_dicts|byattr("id", "foo") }}
2
Michael Wyraz

Eine natürlichere Methode für Ansible ist das Erstellen von /etc/ansible/test_plugins/custom.py mit Inhalt

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible import errors

def equalto(value, other):
    return bool(value == other)

class TestModule(object):
    ''' Ansible file jinja2 tests '''

    def tests(self):
        return {
            'equalto' : equalto,
        }
1
Sergey GRIZZLY

select() und selectattr() wirken auf ein list und geben ein list zurück. Wenn Sie also wissen, dass es nur ein Ergebnis gibt, nehmen Sie das erste vom Generator, d. h

{{ oredered_dicts|selectattr("id", "foo")|first }}

Hinweis: Code nicht getestet

1
gipi

Es sieht so aus, als ob der Filter equalto in Jinja2.8 ( changelog ) erscheint, aber noch kein Veröffentlichungsdatum festgelegt ist (24 Feb 2014). Als Problemumgehung empfehle ich den groupby - Filter:

<ul>
{% for group in persons|groupby('gender') %}
    <li>{{ group.grouper }}<ul>
    {% for person in group.list %}
        <li>{{ person.first_name }} {{ person.last_name }}</li>
    {% endfor %}</ul></li>
{% endfor %}
</ul>
0
lawicko