Jinja2多层模板继承问题

时间:2022-10-19 20:48:26

I have the following three files in a Django App, with the template engine being Jinja2

我在Django应用程序中有以下三个文件,模板引擎是Jinja2

skeleton.html

skeleton.html

<head>
    {% block head_content %}
        <meta charset="utf-8">
        <title> {% if page_title %} {{ page_title }} | {% endif %} Bhargavi Books & Stationery </title>
        <link rel="stylesheet" href="{{ static("css/semantic.min.css") }}">
        <link rel="stylesheet" href="{{ static("Icons/font-awesome.min.css") }}">
    {% endblock head_content %}
</head>

<body>
    <div id="navigation">
    {% block navigation %}
        <div class="ui three item menu">
          <a class="active item">Home</a>
          <a class="item">New Bill</a>
          <a class="item">View Bills</a>
        </div>
    {% endblock navigation %}
    </div>

    <div id="frame">
        {% block frame_content %}
            <p> Body content goes here. Body for {{ content_name }}</p>
        {% endblock frame_content %}
    </div>

    <div id="app">
        {% block app_content %}
            <p> APP content goes here. Body for {{ content_name }}</p>
        {% endblock app_content %}
    </div>

    {% block scripts %}
        <script src="{{ static("js/jquery.js") }}"></script>
        <script src=" {{ static("js/semantic.min.js") }} "></script>
    {% endblock scripts %}
</body>

base.html

base.html

{% extends "skeleton.html" %}
{% from "macros/globalmacros.html" import
            SUIIconList,SUISimpleList,
            SUIImageLabel,SUILabel,
            SUIActionInput,SUILabeledInput,SUIInput,
            SUIDimmableActionCard,SUICard,
 %}


{% block frame_content %}
Frame Content
{% endblock frame_content %}

{% block scripts %}

{{ super() }}
<script src=" {{ static("js/globalmacros.js") }} "></script>

{% endblock scripts %}

dashboard.html

dashboard.html

{% extends "base.html" %}

<div>
{% block body_content %}
Body 3
{% endblock body_content %}
</div>

<div>
{% block app_content %}

DASHBOARD

{% endblock app_content %}
</div>

In this setup, Jinja renders everything except the "DASHBOARD" in the final page. However, when I add an empty block in "base.html", like so..

在此设置中,Jinja呈现除最后一页中的“仪表板”之外的所有内容。但是,当我在“base”中添加一个空块时。html”,像这样. .

{% block app_content %}

App content Goes here...

{% endblock app_content %}

In the final template, "DASHBOARD" is printed. Is this some quirk in Jinja? Is this behavior defined in any docs??

在最后的模板中,“DASHBOARD”被打印出来。这是津佳的怪癖吗?这种行为在任何文档中都有定义吗?

1 个解决方案

#1


1  

I understand your issue: you've got template A, template B (extends template A), and template C (extends template B). There's a block defined in template A, but it's not showing up in the page that uses template C, unless you define that block in template B. If you do that, then the block in question shows up.

我理解你的问题:你有模板,模板B(扩展模板),C(B)扩展模板和模板。有一个块中定义的模板,但是它不是出现在页面中使用模板C,除非你在模板定义块B。如果你这样做,那么在问题出现。

First: you are correct in your understanding that this is not how the Jinja template hierarchy is supposed to work. Second, I did not encounter your issue (found a different one, though), and I have constructed a proof to demonstrate this. Here's what I did (again, using Python 3 and Django 1.11):

首先:您的理解是正确的,即Jinja模板层次结构不应该这样工作。第二,我没有遇到你的问题(尽管我发现了另一个问题),我构建了一个证明来证明这一点。下面是我所做的(再次使用Python 3和Django 1.11):

$ python startproject myapp

In the myapp/myapp/settings.py file, I updated the template engine:

myapp / myapp /设置。py文件,我更新了模板引擎:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [
            os.path.join(BASE_DIR, 'myapp/templates') # hack / should add `myapp` to INSTALLED_APPS instead
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

In myapp/myapp/urls.py, I created a dummy view function & route:

在myapp / myapp / url。py,我创建了一个虚拟视图函数&路由:

from django.conf.urls import url
from django.shortcuts import render_to_response

def home(request):
    return render_to_response('dashboard.html')

urlpatterns = [
    url(r'^$', home),
]

And finally, I established those templates, but I removed the call to import your macros, along with all instances of static().

最后,我建立了这些模板,但是我删除了导入宏的调用,以及所有static()的实例。

Here is the myapp/myapp/templates/skeleton.html file:

这是myapp / myapp /模板/骨架。html文件:

<!doctype html>
<html lang="en">
<head>
  {% block head_content %}
    <meta charset="utf-8">
    <title> {% if page_title %} {{ page_title }} | {% endif %} Bhargavi Books & Stationery </title>
  {% endblock head_content %}
</head>

<body>
<div id="navigation">
  {% block navigation %}
    <div class="ui three item menu">
      <a class="active item">Home</a>
      <a class="item">New Bill</a>
      <a class="item">View Bills</a>
    </div>
  {% endblock navigation %}
</div>

<div id="frame">
  {% block frame_content %}
    <p> Body content goes here. Body for {{ content_name }}</p>
  {% endblock frame_content %}
</div>

<div id="app">
  {% block app_content %}
    <p> APP content goes here. Body for {{ content_name }}</p>
  {% endblock app_content %}
</div>

{% block scripts %}
{% endblock scripts %}
</body>
</html>

Here is the myapp/myapp/base.html file:

这是myapp myapp /基地。html文件:

{% extends "skeleton.html" %}

{% block frame_content %}
  Frame Content
{% endblock frame_content %}

{% block scripts %}
  {{ super() }}
{% endblock scripts %}

And here is the myapp/myapp/templates/dashboard.html file:

这是myapp/myapp/模板/仪表板。html文件:

{% extends "base.html" %}

<div>
  {% block body_content %}
    Body 3
  {% endblock body_content %}
</div>

<div>
  {% block app_content %}
    DASHBOARD
  {% endblock app_content %}
</div>

And here is the output, after viewing that page in my browser:

这是在我的浏览器中看到这个页面后的输出:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title> Bhargavi Books & Stationery </title>
</head>

<body>
<div id="navigation">
  <div class="ui three item menu">
    <a class="active item">Home</a>
    <a class="item">New Bill</a>
    <a class="item">View Bills</a>
  </div>
</div>

<div id="frame">
  Frame Content
</div>

<div id="app">
  DASHBOARD
</div>
</body>
</html>

Since this all works as expected*, my conclusion is that you might have a problem with the base.html template file. Perhaps it's failing to import your macros, and subsequently not behaving correctly? I notice a trailing comma in there, and I'm not sure if that could be problematic or not. I would suggest using the above code as a starting point, and then slowly add back in the parts that I stripped out, and perhaps the problem will become visible/understandable.

由于这一切都按预期运行*,我的结论是您可能会对基有问题。html模板文件。也许它没有导入您的宏,并且随后的行为不正确?我注意到后面有一个逗号,我不确定这是否有问题。我建议使用上面的代码作为起点,然后慢慢地把我剥离出来的部分重新添加回去,也许这个问题会变得可见/可以理解。

*One thing I found odd, that I don't understand: the body_content block is completely missing from my output, unless I define that block in the skeleton.html template. It doesn't work if I define it in the base.html template, which seems wrong to me, because then we're not really extending that second template (base.html)... so there does seem to be something weird there... but I was not able to encounter the original issue you described, so maybe this will be helpful in that particular regards, at least.

*我发现一件奇怪的事情,我不理解:body_content块在我的输出中完全丢失,除非我在框架中定义该块。html模板。如果我在底边定义它就不行。html模板,这在我看来是错误的,因为我们并没有扩展第二个模板(base.html)…所以这里确实有些奇怪的东西……但我没能遇到你描述的原始问题,所以这可能至少在这方面会有帮助。

#1


1  

I understand your issue: you've got template A, template B (extends template A), and template C (extends template B). There's a block defined in template A, but it's not showing up in the page that uses template C, unless you define that block in template B. If you do that, then the block in question shows up.

我理解你的问题:你有模板,模板B(扩展模板),C(B)扩展模板和模板。有一个块中定义的模板,但是它不是出现在页面中使用模板C,除非你在模板定义块B。如果你这样做,那么在问题出现。

First: you are correct in your understanding that this is not how the Jinja template hierarchy is supposed to work. Second, I did not encounter your issue (found a different one, though), and I have constructed a proof to demonstrate this. Here's what I did (again, using Python 3 and Django 1.11):

首先:您的理解是正确的,即Jinja模板层次结构不应该这样工作。第二,我没有遇到你的问题(尽管我发现了另一个问题),我构建了一个证明来证明这一点。下面是我所做的(再次使用Python 3和Django 1.11):

$ python startproject myapp

In the myapp/myapp/settings.py file, I updated the template engine:

myapp / myapp /设置。py文件,我更新了模板引擎:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [
            os.path.join(BASE_DIR, 'myapp/templates') # hack / should add `myapp` to INSTALLED_APPS instead
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

In myapp/myapp/urls.py, I created a dummy view function & route:

在myapp / myapp / url。py,我创建了一个虚拟视图函数&路由:

from django.conf.urls import url
from django.shortcuts import render_to_response

def home(request):
    return render_to_response('dashboard.html')

urlpatterns = [
    url(r'^$', home),
]

And finally, I established those templates, but I removed the call to import your macros, along with all instances of static().

最后,我建立了这些模板,但是我删除了导入宏的调用,以及所有static()的实例。

Here is the myapp/myapp/templates/skeleton.html file:

这是myapp / myapp /模板/骨架。html文件:

<!doctype html>
<html lang="en">
<head>
  {% block head_content %}
    <meta charset="utf-8">
    <title> {% if page_title %} {{ page_title }} | {% endif %} Bhargavi Books & Stationery </title>
  {% endblock head_content %}
</head>

<body>
<div id="navigation">
  {% block navigation %}
    <div class="ui three item menu">
      <a class="active item">Home</a>
      <a class="item">New Bill</a>
      <a class="item">View Bills</a>
    </div>
  {% endblock navigation %}
</div>

<div id="frame">
  {% block frame_content %}
    <p> Body content goes here. Body for {{ content_name }}</p>
  {% endblock frame_content %}
</div>

<div id="app">
  {% block app_content %}
    <p> APP content goes here. Body for {{ content_name }}</p>
  {% endblock app_content %}
</div>

{% block scripts %}
{% endblock scripts %}
</body>
</html>

Here is the myapp/myapp/base.html file:

这是myapp myapp /基地。html文件:

{% extends "skeleton.html" %}

{% block frame_content %}
  Frame Content
{% endblock frame_content %}

{% block scripts %}
  {{ super() }}
{% endblock scripts %}

And here is the myapp/myapp/templates/dashboard.html file:

这是myapp/myapp/模板/仪表板。html文件:

{% extends "base.html" %}

<div>
  {% block body_content %}
    Body 3
  {% endblock body_content %}
</div>

<div>
  {% block app_content %}
    DASHBOARD
  {% endblock app_content %}
</div>

And here is the output, after viewing that page in my browser:

这是在我的浏览器中看到这个页面后的输出:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title> Bhargavi Books & Stationery </title>
</head>

<body>
<div id="navigation">
  <div class="ui three item menu">
    <a class="active item">Home</a>
    <a class="item">New Bill</a>
    <a class="item">View Bills</a>
  </div>
</div>

<div id="frame">
  Frame Content
</div>

<div id="app">
  DASHBOARD
</div>
</body>
</html>

Since this all works as expected*, my conclusion is that you might have a problem with the base.html template file. Perhaps it's failing to import your macros, and subsequently not behaving correctly? I notice a trailing comma in there, and I'm not sure if that could be problematic or not. I would suggest using the above code as a starting point, and then slowly add back in the parts that I stripped out, and perhaps the problem will become visible/understandable.

由于这一切都按预期运行*,我的结论是您可能会对基有问题。html模板文件。也许它没有导入您的宏,并且随后的行为不正确?我注意到后面有一个逗号,我不确定这是否有问题。我建议使用上面的代码作为起点,然后慢慢地把我剥离出来的部分重新添加回去,也许这个问题会变得可见/可以理解。

*One thing I found odd, that I don't understand: the body_content block is completely missing from my output, unless I define that block in the skeleton.html template. It doesn't work if I define it in the base.html template, which seems wrong to me, because then we're not really extending that second template (base.html)... so there does seem to be something weird there... but I was not able to encounter the original issue you described, so maybe this will be helpful in that particular regards, at least.

*我发现一件奇怪的事情,我不理解:body_content块在我的输出中完全丢失,除非我在框架中定义该块。html模板。如果我在底边定义它就不行。html模板,这在我看来是错误的,因为我们并没有扩展第二个模板(base.html)…所以这里确实有些奇怪的东西……但我没能遇到你描述的原始问题,所以这可能至少在这方面会有帮助。