Django模板:为什么__call__魔术方法会破坏非模型对象的渲染?

时间:2016-10-19 18:59:24

标签: python django templates magic-methods

今天我在一个开发项目上遇到了一个奇怪的问题。我用一个非常小的例子再现了它。看看这两个虚拟类(非Django模型子类):

class DummyClassA(object):
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return 'Dummy1 object called ' + self.name


class DummyClassB(object):
    """Same as ClassA, with the __call__ method added"""
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return 'Dummy2 object called ' + self.name

    def __call__(self, *args, **kwargs):
        return "bar"

它们是相同的,但第二种方法有一种特殊的__call__()方法。

我想使用内置的Django模板引擎在视图中显示这两个对象的实例:

class MyView(TemplateView):

    template_name = 'myapp/home.html'

    def get_context_data(self, **kwargs):
        ctx = super(MyView, self).get_context_data(**kwargs)

        list1 = [
            DummyClassA(name="John"),
            DummyClassA(name="Jack"),
        ]

        list2 = [
            DummyClassB(name="Albert"),
            DummyClassB(name="Elmer"),
        ]

        ctx.update({
            'list1': list1,
            'list2': list2,
        })
        return ctx

和相应的模板:

    <h1>Objects repr</h1>
    <ul>
        {% for element in list1 %}
            <li>{{ element }}</li>
        {% endfor %}
    </ul>
    <ul>
        {% for element in list2 %}
            <li>{{ element }}</li>
        {% endfor %}
    </ul>

    <h1>Access members</h1>
    <ul>
        {% for element in list1 %}
            <li>{{ element.name }}</li>
        {% endfor %}
    </ul>
    <ul>
        {% for element in list2 %}
            <li>{{ element.name }}</li>
        {% endfor %}
    </ul>

我得到了这个结果:

html result

当显示第二个类的实例({{ element }})时,执行__call__方法而不是__repr__(),当我想访问类的成员时,它不返回任何内容。

我不明白为什么定义__call__()会改变Django模板引擎处理这些实例的方式。我想这不是一个错误,但主要是一个功能,但我很好奇,为什么__call__()在这种情况下运行。为什么我无法在第二个列表中获得element.name的值?

1 个答案:

答案 0 :(得分:1)

因为这就是模板语言的设计目的。正如the docs state

  

如果[查找变量]的结果值是可调用的,则调用它时不带参数。调用的结果成为模板值。

如果没有这个,就无法在模板中调用方法,因为模板语法不允许使用括号。