我正在为django中的模板设计寻找一个优雅的解决方案。我试着做一个简约的例子:
在页面上有不同的功能区域,例如新闻字段和民意调查,由django中的自己的应用程序代表。这些区域的数量是完全不同的,因此可以有三个民意调查和两个新闻字段,按特定顺序排列(不按类型排序)。
所以这是一个示例实现,我将如何解决这个问题:
# in main app:
class Field(models.Model):
...
# in polls app:
class Poll(main.models.Field):
...
对于不同类型的民意调查:
class PrivatePoll(Poll):
...
然后,模板系统可以迭代Field类型的对象。
{% for field in fields %}
{% show_field field %}
{% endfor %}
但我的问题是, Field 的每个子类或 Poll 的子类都需要以自己的方式显示内容。我知道Django中的 templatetag 包含函数,但是templatetag必须区分子类以及如何呈现它...我想看到“模板代码“应用程序内部的每个应用程序,但我没有得到一个很好的解决方案。
自Django 1.7以来 include 标签怎么样?它可以用 render()表示方法?所以所有的类和子类都有一个 render()方法?我不明白如何使用这个新功能。
我有什么想法可以解决这个问题?模型不必是子类,也许最好有 OneToOneRelationship 或其他什么?
修改
我可以像这样使用 include 标签吗?这是一个很好的django风格吗?
{% for field in fields %}
{% include field.render %}
{% endfor %}
EDIT2:
我编写了自己的模板标签,如文档中所述。但这是正确的方法吗?
from django import template
from django.template.loader import render_to_string
register = template.Library()
@register.tag
def display_object(parser, token):
try:
tag_name, tile_object, template_to_render = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError("%r tag requires exactly two arguments" % token.contents.split()[0])
return MyNode(tile_object, template_to_render)
class MyNode(template.Node):
def __init__(self, tile_object, template_to_render):
self.tile_object = template.Variable(tile_object)
self.template_to_render = template_to_render
def render(self, context):
try:
tile_object = self.tile_object.resolve(context)
return render_to_string(self.template_to_render, tile_object)
except template.VariableDoesNotExist:
return ''
现在理论上我可以在我的模板中使用它:
{% for field in fields %}
{% display_object field field.template_to_use %}
{% endfor %}
但感觉不正确,尤其是display_object(..)
,其中变量通过字符串传递..!?如果我多次使用display_object
调用field
,并且不会碰撞此字符串,因为它总是与传递的字符串“field”相同..!
我想要的只是渲染从对象实例指定的模板,这么难以解决这个问题的唯一方法吗?或者我应该以不同的方式重建我的层次结构?
EDIT3:
好的,经过更多的研究,这正是include
标签的作用(source code)。我不明白为什么这么多人(在论坛/ stackoverflow上)说不应该使用'include'......
所以最后这将是我的解决方案:
{% for field in fields %}
{% include field.template_to_render with context=field.context %}
{% endfor %}
有什么建议吗?
答案 0 :(得分:0)
自Django 1.7以来的include标签怎么样,它可以代表一个 render()的方法?所以所有的类和子类都有一个 render()方法?
理论上的POV会违反图层的责任,因为模型适用于域逻辑,而不是表示。除非你的模型的“域逻辑”仅仅(或大部分)关于表示,当然(想想cms页面等)
但我的问题是,Poll的Field或子类的每个子类 需要以自己的方式来展示内容。
这意味着每个子类的一个模板。最简单的解决方案是将模板路径指定为模型的类属性,然后重写show_field
模板以使用此模板进行渲染...
我可以像这样使用include标签吗?这是一个很好的django风格吗?
{%表示字段%} {%include field.render%} {%endfor%}
假设field.render
是将上下文作为参数的方法,(技术上)正确使用将是:
{% for field in fields %}
{% include field %}
{% endfor %}