Django - Templatetags,包含和类层次结构

时间:2014-12-05 15:45:08

标签: python django django-templates class-hierarchy

我正在为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 %}

有什么建议吗?

1 个答案:

答案 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 %}