为什么Django的DetailView没有可重用的模板?

时间:2016-05-03 20:15:57

标签: django

在Django中显示模板中的表单非常简单:

<form action="" method="post">{% csrf_token %}
    {{ form }}
    <input type="submit" value="Update" />
</form>

基本上只有一个词 - 显示{{ form }}。它非常简单,您可以为不同的表单使用相同的模板。

如果您使用的是CBV,如CreateView或UpdateView,则可以使用fields = []列表限制表单上显示的字段。

与此并行绘制,人们期望有一个类似的工作流程来显示模型(而不是编辑),例如在DetailView中。但是,没有这样的东西..你必须为你使用的每个DetailView编写一个自定义模板。如:

<h3>User: {{ user }}</h3>
<label>First Name</label>: {{ user.first_name }} <br />
<label>Last Name</label>: {{ user.last_name }} <br />
<label>Username</label>: {{ user.username }} <br />
<label>School</label>: {{ user.person.school.name }} <br />

这与{{ form }}生成的内容非常相似,除了此处打印的字段值,而不是input在那里打印。

所以,我想知道,为什么还没有针对DetailView的可重复使用的通用模板?对此有技术限制,还是不像我想象的那样可重复使用?

2 个答案:

答案 0 :(得分:3)

我认为它不像你想象的那样可重复使用。

可以想象,可以定义&#34;标准&#34;渲染简单模型属性(如CharField)的方法 - 当您进入更复杂的关系字段(如ManyToManyFieldForeignKeyOneToOneField时,这很快就变得不可能了。除了最简单的模型之外,您最终会快速覆盖任何默认表示。

其次,Django不是 - 也不应该 - 对你的模型的用途持主观态度,因此它没有尝试假设你想要如何呈现它们。

这与在Django和HTML中定义单个表单字段的结构的表单不同,并且两者之间存在很强的相关性。

答案 1 :(得分:3)

我已经创建并且已经使用了大约一年,现在我自己的通用模板。所以,我想分享,这里是:

创建视图就像这样简单:

class PersonDetail(DetailViewParent):
    model=Person

上面使用的DetailViewParent(根据需要覆盖fieldsexclude;默认包含所有):

class DetailViewParent(DetailView):
    fields=[]
    exclude=[]
    template_name='common/modal_detail.html'

    def get_context_data(self, **kwargs):
        context=super(DetailViewParent, self).get_context_data(**kwargs)
        context['exclude']=self.exclude
        context['fields']=self.fields
        return context

模板的相关部分:

  {% fields %}
  {% for name, label, value, is_link in fields %}
    <tr>
      <td><strong>{{ label|capfirst }}</strong></td>
      <td>
        {% if value.get_absolute_url and request.is_ajax %}
          <a class="modal-loader" href="{{ value.get_absolute_url }}">{{ value }}</a>
        {% elif value.get_absolute_url %}
          <a href="{{ value.get_absolute_url }}">{{ value }}</a>
        {% else %}
          {% if is_link and request.is_ajax %}
            <a class="modal-loader" href="{{ value }}">{{ value }}</a>
          {% elif is_link %}
            <a href="{{ value }}">{{ value }}</a>
          {% else %}
            {{ value }}
          {% endif %}
        {% endif %}
      </td>
    </tr>
  {% endfor %}

模板标签:

@register.tag(name="fields")
def generate_fields(parser, token):
    """
    {% fields %} - loads field name, label, value, is_link to the context
    """
    args=token.contents.split()
    object_name='object'
    if len(args) == 2:
        object_name=args[1]
    return FieldsNode(object_name)


class FieldsNode(template.Node):
    """
    called by generate_fields above
    """

    def __init__(self, object_name):
        self.object_name=object_name

    def render(self, context):
        # Get the data necessary for rendering the thing, and add it to the context.

        try:
            obj=template.Variable(self.object_name).resolve(context)
        except template.VariableDoesNotExist:
            return ''

        include_fields=context.get("fields", None)
        exclude_fields=context.get("exclude", None)

        fields=[]
        for field in obj._meta.fields:
            name=field.name

            if exclude_fields and name in exclude_fields:
                continue

            if include_fields and name not in include_fields:
                continue

            label=field.verbose_name
            value=getattr(obj, field.name)
            is_link=(type(field).__name__ in ('URLField',))

            if isinstance(value, bool):
                value=get_bool_check_mark(value)
            elif value is None:
                value=''

            fields.append((
                name, label, value, is_link,
                ))

        # If include_fields was defined, then sort by the order.
        if include_fields:
            fields=sorted(fields, key=lambda field_: include_fields.index(field_[0]))

        context['fields']=fields

        return ''

模板可根据您的需求和喜好进行定制。但我想指出两件事:

1)get_absolute_url:如果定义了此(标准django)模型方法,则字段值显示为url。

2)modal-loader class:这会触发客户端的js以在bootstrap 3模式中显示详细视图。此外,如果点击1)中提到的链接加载到同一模态上,则可以更轻松地浏览详细视图。它还有一个&#34; back&#34;按钮返回上一个模型的视图。我不是在这里包括它,因为它是很多代码,超出了这个问题的范围。