django - 一旦扩展块被覆盖

时间:2018-04-02 22:33:11

标签: python django

我正在学习django 2.0,在python 3.6中,在windows上学习。我想创建包含三个不同块的页面,因此,这可以在base.html中看到:

base.html

<!DOCTYPE html>
<html lang="en">

<head>
    <title>{% block title %}My amazing site{% endblock %}</title>
</head>

<body>
    <div class='menu'>{% block menu %} start menu {% endblock menu %}</div>
    <div class="content">{% block content %} start content {% endblock content %}</div>
    <div class="buttons">{% block buttons %} start buttons {% endblock buttons %}</div> 
</body>

</html>

这就是我的urls.py的样子:

urls.py

from django.urls import path

from . import views

urlpatterns = [
    path('', views.MenuView.as_view(), name='menu'),
    path('folder<pk>/', views.FolderView.as_view(), name='folder'),
    path('picture<int:picture_id>/', views.picture, name='picture_url')
]

当我来到localhost:8000 / check_images时,我调用了菜单视图,它应该扩展base.html。

在第一个块中,我想显示菜单栏,其中显示所有文件夹。我希望每个页面上都能看到这个栏。 这可以通过以下视图调用:

views.py

class MenuView(generic.ListView):
    model = Folder
    template_name = 'check_images/menu.html'
    context_object_name = 'folders'
    def get_queryset(self):
        return self.model.objects.all()

呈现为check_image / menu.html:

menu.html

{% extends "check_images/base.html" %}
{% block menu %}
    {% for folder in folders %}
        <a href="{% url 'folder' folder.id %}">{{ folder.id }} -- {{ folder.name }}</a>
    {% endfor %}
{% endblock menu %}

到目前为止,一切都按预期运作。当我进入页面时,菜单会加载,并且base.html已扩展。

然而,每当我点击任何菜单项时,我希望菜单保留,并且只渲染菜单下方的块 - 内容和按钮,因为我试着在这里编码。 但是菜单不会停留,所以再次只显示“开始菜单”字符串,在base.html中进行硬编码。

views.py

class FolderView(generic.DetailView):
    model = Folder
    template_name = 'check_images/folder.html'

folder.html

{% extends "check_images/base.html" %}
{% block content %}
    {{ object.picture_set.all.0 }}
{% endblock content %}
{% block buttons %} 
    {% if object.picture_set.all.1 %}
    <a href="{% url 'picture_url' object.picture_set.all.1.id %}"> Next </a>
    {% else %}
    nada
    {% endif %}
{% endblock buttons %}

那么我应该如何扩展已经扩展的base.html?为什么{% block menu %}再次被覆盖?我应该如何防止它,以及“正确”的方式是什么?

由于

3 个答案:

答案 0 :(得分:1)

您可以随时使用include指令代替菜单。 folder.html文件看起来像这样

    {% extends "check_images/base.html" %}
     <div class='menu'>{% include 'check_images/menu.html' %}</div>
    {% block content %}
    {{ object.picture_set.all.0 }}
    {% endblock content %}
    {% block buttons %} 
    {% if object.picture_set.all.1 %}
    <a href="{% url 'picture_url' object.picture_set.all.1.id %}">     Next </a>
     {% else %}
    nada
    {% endif %}
    {% endblock buttons %}

然后您的菜单文件将是

{% for folder in folders %}
<a href="{% url 'folder' folder.id %}">{{ folder.id }} -- {{  folder.name }}</a>
{% endfor %}

然后,您可以随时在任何您不需要的模板上包含或不包含菜单文件,例如您的主页,关于页面等。

答案 1 :(得分:1)

如果我理解得很好,你认为如果你扩展base.html一次,然后在块中编写一些代码,那么它将保存在你扩展base.html的每个其他html文件中吗?

它没有那样工作。每次调用另一个html文件并扩展base.html时,它只会加载base.html中编码的内容。

您无法扩展menu.html,因为它可以从视图中显示一些数据。在我看来,你必须制作一个视图,然后如果点击某个文件夹,你告诉你的视图它现在应该显示特定文件夹的块内容和按钮。

答案 2 :(得分:1)

为什么阻止菜单会覆盖你所说的? 非常简单 - 您只是没有在folder.html模板中定义此块,因此Django使用默认行start menu

您只在{% block menu %}模板中指定了menu.html,它不会被“结转”。其他任何地方。

您可能想要解决此问题: 首先在模板中加入menu.html,您希望菜单显示folders.html中的所有文件夹。

{% extends "check_images/base.html" %}
{% include 'check_images/menu.html' %}
{% block content %}
    {{ object.picture_set.all.0 }}
{% endblock content %}
{% block buttons %} 
    {% if object.picture_set.all.1 %}
    <a href="{% url 'picture_url' object.picture_set.all.1.id %}"> Next </a>
    {% else %}
    nada
    {% endif %}
{% endblock buttons %}

如果您希望它在扩展base.html的所有模板上显示该菜单,那么您可能希望从menu.html移动那个for循环,这样您就不必在任何地方包含它,如下所示:

<!DOCTYPE html>
<html lang="en">

<head>
    <title>{% block title %}My amazing site{% endblock %}</title>
</head>

<body>
    <div class='menu'>   {% for folder in folders %}
        <a href="{% url 'folder' folder.id %}">{{ folder.id }} -- {{ folder.name }}</a>
    {% endfor %}{% block menu %}  my menu {% endblock menu %}</div>
    <div class="content">{% block content %} start content {% endblock content %}</div>
    <div class="buttons">{% block buttons %} start buttons {% endblock buttons %}</div> 
</body>

</html>

然后在视图中添加一些代码,因此django知道文件夹是什么。

class FolderView(generic.DetailView):
    model = Folder
    template_name = 'check_images/folder.html'

    def get_context_data(self,**kwargs):
        context = super(FolderView,self).get_context_data(**kwargs)
        context['folders'] = Folder.objects.all()
        return context

缺点是您必须指定&#39;文件夹&#39;在每个使用base.html的视图中。

编辑:如果您不想在任何地方指定它,将文件夹全局提供给模板,请执行以下操作:

打开settings.py并找到TEMPLATES,它可能看起来像

TEMPLATES = [
    {
        'BACKEND': '...',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        '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',
            ],
        },
    },
]

然后将'your_app.context_processors.folders_menu'添加到其中,如下所示: (记得将your_app&#39;更改为your_app的名称:)

TEMPLATES = [
    {
        'BACKEND': '...',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        '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',
                'your_app.context_processors.folders_menu',
            ],
        },
    },
]

在app目录中创建一个文件context_processors.py并写入:

def folders_menu(request):
    from your_app.models import Folder
    return {'folders': Folder.objects.all()}

现在,您可以将{for循环文件夹放在base.html中,它可以在任何地方使用,而不会覆盖get_context_data()方法 - 您可以删除该部分代码。