我正在学习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 %}
再次被覆盖?我应该如何防止它,以及“正确”的方式是什么?
由于
答案 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()
方法 - 您可以删除该部分代码。