如何在 Django 模板中使用方法参数?

Posted

技术标签:

【中文标题】如何在 Django 模板中使用方法参数?【英文标题】:How to use method parameters in a Django template? 【发布时间】:2010-12-04 12:18:33 【问题描述】:

我知道这里有一个帖子:django template system, calling a function inside a model 描述了如何制作自定义模板过滤器来实现这一点,但从程序员的角度来看,这是一个失败,因为这会破解一些不适合这样做的东西。不能在 Django 的模板系统中调用带参数的方法,这看起来几乎是荒谬的。

【问题讨论】:

Django: passing an argument to a method on a template variable的可能重复 【参考方案1】:

Django 团队从理念上决定不允许在视图中传递方法参数。就个人而言,我同意他们的看法;它强制将逻辑和表示分离,我觉得这很有帮助。它可以防止 php 臭名昭著的那种意大利面条式代码。

在您链接的情况下,正确的做法是通过上下文将该调用的结果从视图传递到模板中。这种方式更易于维护。如果稍后您需要将my_related_deltas(3) 更改为my_related_deltas(4),请转到应该相当简洁的视图,而不是通过模板搜索以确定它的确切定义位置。

【讨论】:

嗯,好在他们不会把你绑在上面。我认识一些使用 Jinja2 (jinja.pocoo.org/2/documentation) 作为模板而不是 Django 模板系统的人。显然,它很容易切换出来使用。 这里更换Django模板系统的指南:lethain.com/entry/2008/jul/22/… “for 循环”怎么不是逻辑?【参考方案2】:

尽管 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)

【讨论】:

以上是关于如何在 Django 模板中使用方法参数?的主要内容,如果未能解决你的问题,请参考以下文章

如何在django模板中读取传递过去的字典参数中的某一项?

如何在 django 模板中调用带有参数的 python 函数? [复制]

如何将三个或多个参数传递给自定义模板标签过滤器 django?

如果输入参数在Django模板中无效,如何抛出异常

使用 Django,如何在模板中动态设置 ModelForm 字段值?

Django - 自定义模板标签传递关键字参数