Django父模板必须作为自己的子模板

时间:2017-06-19 04:18:01

标签: python django django-templates

我刚刚开始使用Django的模板扩展功能,而且我遇到了一些问题。 所以我这里有两个html模板,一个是主要的部分页面,另一个是特定的帖子'页

主要部分页面

{% if latest_post_list %}
    {% for post in latest_post_list %}
        <a href = "{% url 'blog:detail' post.id %}"><h1>{{post.title}}</h1></a>  
        <h2>{{post.author}}</h2>
        <h2>{{post.pub_date}}</h2>
        <p>{{post.body}}</p>
        {% if post.video_set.all.exists %}
            <h3>Videos</h3>
        {% endif %}
        {% for video in post.video_set.all %}
            <a href = "{{video.url}}"><h4>Here is a video</h4></a>
        {% endfor %}
        {% if post.link_set.all.exists %}
            <h3>Links</h3>
        {% endif %}
        {% for link in post.link_set.all %}
            <a href = "{{link.url}}">{{link.name}}</a>
        {% endfor %}
    {% endfor %}
{% else %}
    <p>no recent posts made</p>
{% endif %}

帖子页

<h1>{{post}}</h1>
<h2>{{post.author}}</h2>
<h2>{{post.pub_date}}</h2>
<p>{{post.body}}</p>
{% if post.video_set.all.exists %}
            <h3>Videos</h3>
{% endif %}
{% for video in post.video_set.all %}
    <a href = "{{video.url}}"><h4>Here is a video</h4></a>
{% endfor %}
{% if post.link_set.all.exists %}
    <h3>Links</h3>
{% endif %}
{% for link in post.link_set.all %}
    <a href = "{{link.url}}">{{link.name}}</a>
{% endfor %}

现在我要做的是拥有以下代码(两个页面都相同)得到扩展:

{% if post.video_set.all.exists %}
            <h3>Videos</h3>
{% endif %}
{% for video in post.video_set.all %}
    <a href = "{{video.url}}"><h4>Here is a video</h4></a>
{% endfor %}
{% if post.link_set.all.exists %}
    <h3>Links</h3>
{% endif %}
{% for link in post.link_set.all %}
    <a href = "{{link.url}}">{{link.name}}</a>
{% endfor %}

根据我对Django继承如何工作的理解,我将使这段代码成为父模板,并创建Main Section Page / Post Page子模板的唯一部分。问题出现在主要部分页面中,我无法将其轻松插入到父模板中。&#39;整个父母模板&#39;主要部分页面的一部分被包含在一个额外的{% for %}{% endfor %}循环中,这意味着来自父模板的代码位于(最终){% block %}子模板中,该模板本身意味着插回到父模板中。 (这类似于开始)

因此,我的难题是父模板必须作为自己的子模板,这是不可能的。因此,我有两个问题:

  1. 如何有效地重新构建主要部分页面以使其可插入?如果可能的话,我可以举个例子吗?

  2. 这种情况是否适合继承,或者让代码重叠更具战略意义?

1 个答案:

答案 0 :(得分:0)

如果我正确理解您的问题,您的方法就不适合您的问题。 基本上,您有一段要重用的代码。本节需要一些输入 - 变量post

您的代码段甚至可能会被扩展,因为除标题之外的所有内容似乎都相同 - 您还可以添加以下内容:

    <h2>{{post.author}}</h2>
    <h2>{{post.pub_date}}</h2>
    <p>{{post.body}}</p>

你现在有几种可能性。 我会告诉你有关包含和templatetags的信息 - templatetags是我最喜欢的。

夹杂物

您可以将模板中的那部分包含在&#34; normal&#34;模板 - 基本上与您想要首先执行的模板扩展相反(请参阅https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#include):

将此信息发布到新的随附模板中(yourapp/included.html为了简单起见):

<h2>{{post.author}}</h2>
<h2>{{post.pub_date}}</h2>
<p>{{post.body}}</p>
{% if post.video_set.all.exists %}
            <h3>Videos</h3>
{% endif %}
{% for video in post.video_set.all %}
    <a href = "{{video.url}}"><h4>Here is a video</h4></a>
{% endfor %}
{% if post.link_set.all.exists %}
    <h3>Links</h3>
{% endif %}
{% for link in post.link_set.all %}
    <a href = "{{link.url}}">{{link.name}}</a>
{% endfor %}

然后将其包含在您的其他模板中:

{% include "yourapp/included.html" %}

Templatetags

Django允许您编写自己的模板标签。这意味着您不必手动渲染博客条目,而是将其加到标签上,让标签完成剩下的工作。这通常允许简单的tempalte阅读流程,因此是我最喜欢的解决方案。您甚至可以为其添加其他选项(例如,用于链接标题以便合并该标题的开关)或执行多个标记。

tempaltetags的初始设置有点复杂,但从长远来看绝对值得。有关详细信息,请参阅https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/

我会向您展示一个带有一个模板标签的解决方案,特别是对于视频和链接列表,我建议您稍后将其拆分为多个标签(相同方法但更多标签):

  1. 在您的app文件夹中,创建一个模块&#34; templatetags&#34; (不要忘记 init .py文件)
  2. 在此templatetags文件夹中,创建一个新模块。模块名称是您稍后将加载的模板标签库的名称。示例:yourapp_tags.py
  3. 注册一个包含标记并将变量通过它传递给模板(非常欢迎您在文档上更具创意):

    from django import template
    register = template.Library()
    @register.inclusion_tag('templatetags/yourapp/post.html')
    def render_post(post):
        """
        Rendering a Post into the template
        :param post: The blog post that should be rendered
        :return: Rendered blog post
        :template: templatetags/yourapp/post.html
        """
        return {
            "post": post,
        }
    
  4. 现在在您的应用模板目录中创建模板路径和模板(我通常将tempaltetag tempaltes与普通模板分开):

    <h2>{{post.author}}</h2>
    <h2>{{post.pub_date}}</h2>
    <p>{{post.body}}</p>
    {% if post.video_set.all.exists %}
                <h3>Videos</h3>
    {% endif %}
    {% for video in post.video_set.all %}
        <a href = "{{video.url}}"><h4>Here is a video</h4></a>
    {% endfor %}
    {% if post.link_set.all.exists %}
        <h3>Links</h3>
    {% endif %}
    {% for link in post.link_set.all %}
        <a href = "{{link.url}}">{{link.name}}</a>
    {% endfor %}
    
    1. 在您的模板中,现在导入模板标记库并使用新模板标记呈现您的帖子:
  5. 主要部分页面

    {% load yourapp_tags %}
    {% if latest_post_list %}
        {% for post in latest_post_list %}
            <a href = "{% url 'blog:detail' post.id %}"><h1>{{post.title}}</h1></a> 
            {% render_post post %} 
        {% endfor %}
    {% else %}
        <p>no recent posts made</p>
    {% endif %}
    

    帖子页

    {% load yourapp_tags %}
    <h1>{{post}}</h1>
    {% render_post post %}
    

    这绝对看起来更复杂。但是,只需在模板标签中创建部分模板,并将此示例标签分成3个不同的标签,您就可以在任意位置单独渲染帖子内容,视频和链接,在列表中渲染没有视频和链接的帖子,...所有只需编写模板标签。使用templatetags,代码很容易重用。我经常使用它们来渲染模板中的内容或创建可以包含在主页面或侧边栏中的小部件。

    为了完整答案

    为了完成,我想直接回答你的问题:

      

    如何有效地重新建模主要部分页面以进行制作   可插拔?如果可能的话,我可以举个例子吗?

    根据我的经验,最好定义一个只包含基本页面布局和块定义的基本模板。所有其他模板都扩展了此基本模板,并仅覆盖了所需的块。例如,如果您只想修改更专业的页面的一部分,则可以多次扩展模板。您甚至可以在扩展基本模板的模板中定义新块,并在扩展定义新块的模板的下一个模板中覆盖它们。但要小心,那些&#34;继承层次结构&#34;让你比较快,很难维护。使用它们,但要谨慎使用它们。

      

    这种情况是否适合继承,或者让代码重叠更具战略意义?

    都不是。如上所述,这非常适合包含子模板或 - 在我看来更好 - 创建自己的模板标签。你是绝对正确的,代码重叠永远不是一件好事。不惜一切代价避免这种情况(我的个人意见)。另一方面,继承并不像你希望的那样动态。对于模板,继承是继承结构,而不是重复解析相同的信息。这就是包含(templatetags是恕我直言也是一种更灵活的包含附加属性的方式)。

    很长的帖子,但希望它帮助你解决问题: - )