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

Django templates: why does __call__ magic method breaks the rendering of a non-model object?

今天我在开发中遇到了一个奇怪的问题。我用一个非常小的例子复制了它。看看这两个虚拟 classes(非 Django 模型子 classes):

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>

我得到这个结果:

当显示第二个class({{ element }})的实例时,执行__call__方法而不是__repr__(),当我想访问一个成员class,returns什么都没有。

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

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

If the resulting value [of looking up a variable] is callable, it is called with no arguments. The result of the call becomes the template value.

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