Suche…


Benutzerdefinierte Filter

Mit Filtern können Sie eine Funktion auf eine Variable anwenden. Diese Funktion kann 0 oder 1 Argument annehmen. Hier ist die Syntax:

{{ variable|filter_name }} 
{{ variable|filter_name:argument }}

Filter können verkettet werden, so dass dies vollkommen gültig ist:

{{ variable|filter_name:argument|another_filter }}

Wenn in Python übersetzt, würde die obige Zeile ungefähr Folgendes ergeben:

print(another_filter(filter_name(variable, argument)))

In diesem Beispiel schreiben wir einen benutzerdefinierten Filter verbose_name , der für ein Modell (Instanz oder Klasse) oder ein QuerySet gilt. Es wird den ausführlichen Namen eines Modells oder dessen ausführlichen Namen Plural zurückgegeben, wenn das Argument auf True .

@register.filter
def verbose_name(model, plural=False):
    """Return the verbose name of a model.
    `model` can be either:
      - a Model class
      - a Model instance
      - a QuerySet
      - any object refering to a model through a `model` attribute.

    Usage:
      - Get the verbose name of an object
          {{ object|verbose_name }}
      - Get the plural verbose name of an object from a QuerySet
          {{ objects_list|verbose_name:True }}
    """
    if not hasattr(model, '_meta'):
        # handle the case of a QuerySet (among others)
        model = model.model
    opts = model._meta
    if plural:
        return opts.verbose_name_plural
    else:
        return opts.verbose_name

Einfache Tags

Die einfachste Methode zum Definieren eines benutzerdefinierten Vorlagen-Tags ist die Verwendung eines simple_tag . Diese sind sehr einfach einzurichten. Der Funktionsname ist der Tag-Name (obwohl Sie ihn überschreiben können), und Argumente sind Token ("Wörter", die durch Leerzeichen getrennt sind, mit Ausnahme von Leerzeichen zwischen Anführungszeichen). Es unterstützt sogar Keyword-Argumente.

Hier ist ein nutzloser Tag, der unser Beispiel veranschaulicht:

{% useless 3 foo 'hello world' foo=True bar=baz.hello|capfirst %}

Sei foo und baz Kontextvariablen wie die folgenden:

{'foo': "HELLO", 'baz': {'hello': "world"}}

Angenommen, wir möchten, dass dieses sehr nutzlose Tag so dargestellt wird:

HELLO;hello world;bar:World;foo:True<br/>
HELLO;hello world;bar:World;foo:True<br/>
HELLO;hello world;bar:World;foo:True<br/>

Art der Verkettung der Argumente dreimal wiederholt (3 ist das erste Argument).

So kann die Tag-Implementierung aussehen:

from django.utils.html import format_html_join

@register.simple_tag
def useless(repeat, *args, **kwargs):
    output = ';'.join(args + ['{}:{}'.format(*item) for item in kwargs.items()])
    outputs = [output] * repeat
    return format_html_join('\n', '{}<br/>', ((e,) for e in outputs))

format_html_join erlaubt es, <br/> als sicheres HTML zu kennzeichnen, nicht jedoch den Inhalt der outputs .

Erweiterte benutzerdefinierte Tags mit Node

Manchmal ist das, was Sie tun möchten, für einen filter oder einen simple_tag zu komplex. Um dies zu erreichen, müssen Sie eine Kompilierungsfunktion und einen Renderer erstellen.

In diesem Beispiel erstellen wir ein Vorlagen-Tag " verbose_name mit der folgenden Syntax:

Beispiel Beschreibung
{% verbose_name obj %} Ausführlicher Name eines Modells
{% verbose_name obj 'status' %} Ausführlicher Name des Feldes "Status"
{% verbose_name obj plural %} Ausführlicher Name Plural eines Modells
{% verbose_name obj plural capfirst %} Großbuchstabe verbose Name Plural eines Modells
{% verbose_name obj 'foo' capfirst %} Großbuchstabe verbose Name eines Feldes
{% verbose_name obj field_name %} Ausführlicher Name eines Feldes aus einer Variablen
{% verbose_name obj 'foo'|add:'_bar' %} Ausführlicher Name eines Feldes "foo_bar"

Der Grund, warum wir dies mit einem einfachen Tag nicht tun können, ist, dass plural und capfirst weder Variablen noch Zeichenfolgen sind, sondern "Schlüsselwörter". Wir könnten natürlich entscheiden, sie als Strings 'plural' und 'capfirst' , aber es kann Konflikte mit Feldern mit diesen Namen geben. Würde {% verbose_name obj 'plural' %} "verbose name plural von obj " oder "verbose name von obj.plural " obj.plural ?

Zuerst erstellen wir die Kompilierungsfunktion:

@register.tag(name='verbose_name')
def do_verbose_name(parser, token):
    """
    - parser: the Parser object. We will use it to parse tokens into
              nodes such as variables, strings, ...
    - token: the Token object. We will use it to iterate each token
             of the template tag.
    """
    # Split tokens within spaces (except spaces inside quotes)
    tokens = token.split_contents()
    tag_name = tokens[0]
    try:
        # each token is a string so we need to parse it to get the actual
        # variable instead of the variable name as a string.
        model = parser.compile_filter(tokens[1])
    except IndexError:
        raise TemplateSyntaxError(
            "'{}' tag requires at least 1 argument.".format(tag_name))

    field_name = None
    flags = {
        'plural': False,
        'capfirst': False,
    }

    bits = tokens[2:]
    for bit in bits:
        if bit in flags.keys():
            # here we don't need `parser.compile_filter` because we expect
            # 'plural' and 'capfirst' flags to be actual strings.
            if flags[bit]:
                raise TemplateSyntaxError(
                    "'{}' tag only accept one occurrence of '{}' flag".format(
                        tag_name, bit)
                )
            flags[bit] = True
            continue
        if field_name:
            raise TemplateSyntaxError((
                "'{}' tag only accept one field name at most. {} is the second "
                "field name encountered."
            ).format(tag_name, bit)
        field_name = parser.compile_filter(bit)

    # VerboseNameNode is our renderer which code is given right below
    return VerboseNameNode(model, field_name, **flags)

Und jetzt der Renderer:

class VerboseNameNode(Node):

    def __init__(self, model, field_name=None, **flags):
        self.model = model
        self.field_name = field_name
        self.plural = flags.get('plural', False)
        self.capfirst = flags.get('capfirst', False)

    def get_field_verbose_name(self):
        if self.plural:
            raise ValueError("Plural is not supported for fields verbose name.")
        return self.model._meta.get_field(self.field_name).verbose_name

    def get_model_verbose_name(self):
       if self.plural:
           return self.model._meta.verbose_name_plural
       else:
           return self.model._meta.verbose_name

    def render(self, context):
        """This is the main function, it will be called to render the tag.
        As you can see it takes context, but we don't need it here.
        For instance, an advanced version of this template tag could look for an
        `object` or `object_list` in the context if `self.model` is not provided.
        """
        if self.field_name:
            verbose_name = self.get_field_verbose_name()
        else:
            verbose_name = self.get_model_verbose_name()
        if self.capfirst:
            verbose_name = verbose_name.capitalize()
        return verbose_name


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow