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.
如果没有这个,就无法调用模板中的方法,因为模板语法不允许使用括号。
今天我在开发中遇到了一个奇怪的问题。我用一个非常小的例子复制了它。看看这两个虚拟 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.
如果没有这个,就无法调用模板中的方法,因为模板语法不允许使用括号。