Как использовать параметры метода в шаблоне Django?

Я знаю, что здесь есть сообщение: система шаблонов django, вызывающая функция внутри модели, описывающая, как вы можете создать собственный шаблонный фильтр для достижения этой цели, но с точки зрения программиста это неудача, потому что это взламывает то, что не предназначено для этого. Кажется почти смешным, что вы не можете вызвать метод с параметрами в системе шаблонов Django.


person orokusaki    schedule 07.10.2009    source источник
comment
Возможный дубликат Django: передача аргумента в метод переменной шаблона   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 12.05.2016


Ответы (2)


Команда Django из соображений философии решила не разрешать передачу параметров метода в представление. Лично я с ними согласен; он заставляет разделить логику и представление, что я считаю полезным. Он предотвращает спагетти-код, которым печально известен PHP.

В случае, если вы связались, правильнее всего передать результат этого вызова из представления в шаблон через контекст. Это просто более удобно в обслуживании. Если позже вам потребуется изменить my_related_deltas(3) на my_related_deltas(4), вы перейдете к представлению, которое должно быть довольно кратким, вместо того, чтобы искать по шаблонам, чтобы точно определить, где оно определено.

person tghw    schedule 07.10.2009
comment
Что ж, хорошо, что они не привязывают тебя к этому. Я знаю нескольких людей, которые используют Jinja2 (jinja.pocoo.org/2/documentation) для их шаблоны вместо системы шаблонов Django. По-видимому, довольно легко отказаться от этого и использовать вместо него. - person tghw; 07.10.2009
comment
Руководство по замене системы шаблонов Django здесь: lethain.com/entry/2008/jul/22/ - person tghw; 07.10.2009
comment
Как циклы for не являются логикой? - person Blaze; 01.11.2013

Несмотря на то, что авторы django предлагают не загружать наши методы аргументами, вы все равно можете сделать это, используя этот «маленький» тег шаблона, который я написал.

В моем примере я просто показываю, что это возможно. Из соображений безопасности я настоятельно рекомендую вам писать теги шаблонов вместо того, чтобы пытаться передавать аргументы методам модели.

! ВНИМАНИЕ! это только для целей тестирования! Используя это, вы можете взломать NASA, а также можете быть убиты.

class CallNode(template.Node):
    def __init__(self,object, method, args=None, kwargs=None, context_name=None):
        self.object = template.Variable(object)
        self.method = method
        if args:
            self.args = []
            for arg in args:
                self.args.append(template.Variable(arg))
        else:
            self.args = None

        if kwargs:
            self.kwargs = {}
            for key in kwargs:
                self.kwargs[key] = template.Variable(kwargs[key])
        else:
            self.kwargs = None

        self.context_name = context_name

    def render(self, context):
        object = self.object.resolve(context)
        if isinstance(object, str):
            raise template.TemplateSyntaxError('Given object is string ("%s") of length %d' 
                                               % (object, len(object)))

        args = []
        kwargs = {}
        if self.args:
            for arg in self.args:
                args.append(arg.resolve(context))
        if self.kwargs:
            for key in self.kwargs:
                kwargs[key] = self.kwargs[key].resolve(context)

        method = getattr(object, self.method, None)

        if method:
            if hasattr(method, '__call__'): 
                result = method(*args, **kwargs)
            else:
                result = method
            if self.context_name:
                context[self.context_name] = result
                return ''
            else:
                if not result == None: 
                    return result
                else:
                    return ''
        else:
            raise template.TemplateSyntaxError('Model %s doesn\'t have method "%s"' 
                                               % (object._meta.object_name, self.method))


@register.tag
def call(parser, token):
    """
    Passes given arguments to given method and returns result

    Syntax::

        {% call <object>[.<foreignobject>].<method or attribute> [with <*args> <**kwargs>] [as <context_name>] %}

    Example usage::

        {% call article.__unicode__ %}
        {% call article.get_absolute_url as article_url %}
        {% call article.is_visible with user %}
        {% call article.get_related with tag 5 as related_articles %}

        {% call object.foreign_object.test with other_object "some text" 123 article=article text="some text" number=123 as test %} 
    """

    bits = token.split_contents()
    syntax_message = ("%(tag_name)s expects a syntax of %(tag_name)s "
                       "<object>.<method or attribute> [with <*args> <**kwargs>] [as <context_name>]" %
                       dict(tag_name=bits[0]))

    temp = bits[1].split('.')
    method = temp[-1]
    object = '.'.join(temp[:-1])

    # Must have at least 2 bits in the tag
    if len(bits) > 2:
        try:
            as_pos = bits.index('as')
        except ValueError:
            as_pos = None
        try:
            with_pos = bits.index('with')
        except ValueError:
            with_pos = None

        if as_pos:
            context_name = bits[as_pos+1]
        else:
            context_name = None

        if with_pos:
            if as_pos:
                bargs = bits[with_pos+1:as_pos]
            else:
                bargs = bits[with_pos+1:]
        else:
            bargs = []

        args = []
        kwargs = {}

        if bargs:
            for barg in bargs:
                t = barg.split('=')
                if len(t) > 1:
                    kwargs[t[0]] = t[1]
                else:
                    args.append(t[0])

        return CallNode(object, method, args=args, kwargs=kwargs, context_name=context_name)
    elif len(bits) == 2:
        return CallNode(object, method)
    else:
        raise template.TemplateSyntaxError(syntax_message)
person seler    schedule 21.08.2011