Zoeken…


Aangepaste filters

Met filters kunt u een functie op een variabele toepassen. Voor deze functie kan 0 of 1 argument nodig zijn. Hier is de syntaxis:

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

Filters kunnen worden gekoppeld, dus dit is volkomen geldig:

{{ variable|filter_name:argument|another_filter }}

Indien vertaald naar python zou de bovenstaande regel zoiets geven:

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

In dit voorbeeld zullen we een aangepaste filter verbose_name die van toepassing is op een Model (instantie of klasse) of een QuerySet. Het retourneert de uitgebreide naam van een model, of de uitgebreide naam meervoud als het argument is ingesteld op 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

Eenvoudige tags

De eenvoudigste manier om een aangepaste sjabloontag te definiëren, is door een simple_tag te gebruiken. Deze zijn zeer eenvoudig in te stellen. De functienaam is de tagnaam (hoewel u deze kunt overschrijven) en argumenten zijn tokens ("woorden" gescheiden door spaties, behalve spaties tussen aanhalingstekens). Het ondersteunt zelfs trefwoordargumenten.

Hier is een nutteloze tag die ons voorbeeld zal illustreren:

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

Laat foo en baz contextvariabelen zijn zoals de volgende:

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

Stel dat we deze zeer nutteloze tag als volgt willen weergeven:

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

Soort argumenten samenvoeging driemaal herhaald (waarvan 3 het eerste argument is).

Dit is hoe de tag-implementatie eruit zou kunnen zien:

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 maakt het mogelijk <br/> als veilige HTML te markeren, maar niet de inhoud van de outputs .

Geavanceerde aangepaste tags met behulp van Node

Soms is wat je wilt doen gewoon te complex voor een filter of een simple_tag . Dit moet je een compilatiefunctie en een renderer maken.

In dit voorbeeld maken we een sjabloontag verbose_name met de volgende syntaxis:

Voorbeeld Beschrijving
{% verbose_name obj %} Uitgebreide naam van een model
{% verbose_name obj 'status' %} Uitgebreide naam van het veld "status"
{% verbose_name obj plural %} Uitgebreide naam meervoud van een model
{% verbose_name obj plural capfirst %} Hoofdletterwoord in meervoud van een model
{% verbose_name obj 'foo' capfirst %} Hoofdletterwoord in hoofdletters van een veld
{% verbose_name obj field_name %} Uitgebreide naam van een veld uit een variabele
{% verbose_name obj 'foo'|add:'_bar' %} Uitgebreide naam van een veld "foo_bar"

De reden waarom we dit niet kunnen doen met een eenvoudige tag is dat plural en capfirst geen variabelen of strings zijn, ze zijn "sleutelwoorden". We kunnen natuurlijk besluiten om ze door te geven als 'plural' en 'capfirst' , maar het kan conflicteren met velden met deze namen. Zou {% verbose_name obj 'plural' %} betekenen "uitgebreide naam meervoud van obj " of "uitgebreide naam van obj.plural "?

Laten we eerst de compilatiefunctie maken:

@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)

En nu de 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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow