サーチ…


カスタムフィルタ

フィルタを使用すると、変数に関数を適用できます。この関数は0または1の引数をとることができます。構文は次のとおりです。

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

これは完全に有効なので、フィルタは連鎖することができます:

{{ variable|filter_name:argument|another_filter }}

Pythonに翻訳された場合、上記の行は次のようになります:

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

この例では、Model(インスタンスまたはクラス)またはverbose_nameに適用されるカスタムフィルタverbose_nameverbose_nameします。引数がTrue設定されている場合は、モデルの冗長な名前、またはその冗長な名前の複数形が返され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

単純なタグ

カスタムテンプレートタグを定義する最も簡単な方法は、 simple_tagを使用することsimple_tag 。これらはセットアップするのが非常に簡単です。関数名はタグ名になりますが、引数はトークン(引用符で囲まれたスペースを除いて空白で区切られた "トークン")になります。キーワード引数もサポートしています。

私たちの例を説明する無駄なタグがあります:

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

foobaz次のようなコンテキスト変数としましょう:

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

私たちは、このようなレンダリングに非常に役に立たないタグを使いたいとしましょう:

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

引き数連結の種類は3回繰り返されます(3が最初の引き数です)。

タグの実装は次のようになります。

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では、安全なHTMLとして<br/>をマークすることができますが、 outputsの内容はマークしません。

Nodeを使用した高度なカスタムタグ

場合によっては、 filtersimple_tagに対して複雑すぎることもあります。これを実行すると、コンパイル関数とレンダラーを作成する必要があります。

この例では、テンプレートタグverbose_nameを次の構文で作成します。

説明
{% verbose_name obj %} モデルの冗長な名前
{% verbose_name obj 'status' %} フィールド "ステータス"の冗長な名前
{% verbose_name obj plural %} 複数のモデルの冗長な名前
{% verbose_name obj plural capfirst %} 複数のモデルを大文字にした冗長な名前
{% verbose_name obj 'foo' capfirst %} フィールドの大文字と小文字の名前
{% verbose_name obj field_name %} 変数からのフィールドの詳細な名前
{% verbose_name obj 'foo'|add:'_bar' %} フィールド "foo_bar"の冗長な名前

単純なタグでこれを行うことができない理由は、 pluralcapfirstは変数でも文字列でもなく、 "キーワード"であるということです。明らかにそれらを文字列'plural''capfirst'として渡すことができますが、これらの名前のフィールドと競合する可能性があります。 {% verbose_name obj 'plural' %}は、「複数のobj詳細な名前」または「 obj.plural詳細な名前」をobj.pluralますか?

まずコンパイル関数を作成しましょう:

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

レンダラー:

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
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow