首页 文章

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

提问于
浏览
3

在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 }} 
<label>Last Name</label>: {{ user.last_name }}
<label>Username</label>: {{ user.username }}
<label>School</label>: {{ user.person.school.name }}

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

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

2 回答

  • 1

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

    可能有可能定义"standard"方法来渲染简单的模型属性,如 CharField - 当你进入更复杂的关系字段,如 ManyToManyFieldForeignKeyOneToOneField 时,这很快就变得不可能了 . 除了最简单的模型之外,您最终会快速覆盖任何默认表示 .

    其次,Django不是 - 也不应该 - 对你的模型的用途持主观态度,因此它不会试图假设你想要如何渲染它们 .

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

  • 2

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

    创建视图就像这样简单:

    class PersonDetail(DetailViewParent):
        model=Person
    

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

    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)中提到的链接加载到同一模态上,则可以更轻松地浏览详细视图 . 它还有一个"back"按钮可以返回上一个模型的视图 . 我不是在这里包括它,因为它是很多代码,超出了这个问题的范围 .

相关问题