Django 嵌套视图
Django Nested Views
我正在开发一个内部应用程序,我希望能够嵌套我的视图以使一切井井有条。我计划通过将页面的不同部分保留在它们自己的 HTML 文件中来实现这一点,这些文件具有它们自己的视图(单独的侧边栏和导航栏、单独的图表等)。
views.py
from django.shortcuts import render
from django.views.generic import TemplateView
import Recall.data_logger.models as DLM
class ReportHome(TemplateView):
template_name = 'data_logger/index.html'
class SelectorSidebar(TemplateView):
template_name = 'data_logger/sidebar.html'
def get(self, request, *args, **kwargs):
companies = DLM.Company.objects.order_by('company_name').all()
return render(request, self.template_name, {'companies':companies,})
index.html
<html>
<head></head>
<body data-gr-c-s-loaded="true">
{% include 'data_logger/navbar.html' %}
<div class="container-fluid">
<div class="row">
{% include 'data_logger/sidebar.html' %} <!-- This is the part I need help with-->
</div>
</div>
</body>
</html>
sidebar.html
<div class="col-sm-3 col-md-1 sidebar">
<ul class="nav nav-sidebar">
{% for company in companies %}
<li><a href="#">{{ company.company_name }}</a></li>
{% endfor %}
</ul>
</div>
我知道仅使用 {% include 'data_logger/sidebar.html' %}
它只是加载 HTML 并绕过 SelectorSidebar
,如何通过视图引导它?
我想要一个允许我访问任何内容的解决方案,从简单的名称列表到被馈送到 D3 图表中的相对较大的数据集。
解决方案
这是我最终使用的:
index.html
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
crossorigin="anonymous"></script>
<script>
$.get("_sidebar", function(data, status){
$("#_sidebar").html(data);
});
</script>
</head>
<body data-gr-c-s-loaded="true">
{% include 'data_logger/navbar.html' %}
<div class="container-fluid">
<div class="row" id="_sidebar"></div>
</div>
</body>
</html>
其中 _sidebar
是 SelectorSidebar 的 URL:
urlpatterns = [
path('', v.ReportHome.as_view(), name='ReportHome'),
path('_sidebar', v.SelectorSidebar.as_view(), name='SelectorSidebar'),
]
我认为您对 Django 模板和视图如何协同工作感到困惑。
用非常简单的术语来说,Django 模板就是定义构成页面的 HTML 代码的东西。您可以使您的模板非常模块化和有条理;为此,您可以使用 include
模板标签或使用 template inheritance,这是拥有 "modular" 模板的非常强大的方法。
Django 视图基本上是一个接收 HTTP 请求并构建 HTTP 响应的函数(或者您使用的 class 基于 class 的视图)。
拥有 "nested" 个视图没有多大意义,因为通常您只有一个 HTTP 请求,而您只想构建一个具有显示页面所需 HTML 的响应。
所以我认为您可以愉快地使用 Django 模板将构成页面的所有模块(页眉、侧边栏等)放在一起,但每个页面都应对应一个 Django 视图。
另一种方法可以使用 AJAX 和 Javascript 发出不同的 HTTP 请求并在客户端构建页面,但我认为这不是您在此考虑的方法。
正如@baxeico 所回答的那样,一个页面不能有多个视图,因为一个 HTTP 请求就是一个视图。
如果您的内容需要出现在很多页面上,例如侧边栏,并且该内容还需要一些上下文信息才能呈现(例如要从数据库中获取的 companies
列表),你有两个选择:
如果需要添加到边栏的内容相当有限,请创建一个模板 context processor,然后将其添加到设置中的上下文处理器列表(TEMPLATES
设置).
def sidebar_context(request):
return {'companies': DLM.Company.objects.order_by('company_name').all()}
在您的设置中,您可以在列表顶部添加类似 'myapp.custom_contexts.sidebar_context'
的内容。
现在,每个模板都可以访问上下文变量 companies
,包括您的边栏模板。
如果边栏中显示的内容更动态或更复杂,您应该考虑使用 AJAX 从浏览器中获取数据。您将创建一个 returns JSON 而不是 HTML 的视图,并在侧边栏模板中添加 javascript 以获取数据并填充侧边栏。
视图与您当前的视图一样简单:
def sidebar(request):
return JsonResponse({'companies': Company.objects.all().values('name', 'id')})
这将 return 包含每个公司的名称和 ID 的字典列表。在成功响应的 AJAX 处理程序中(接收 data
),然后您可以循环遍历 data
并访问您可以使用的 data[i].name
和 data[i].id
填充您的列表。
我不会发布完整的 javascript(请搜索 jQuery、ajax 和 django),但这里有一点可以给你一个想法,假设jQuery:
$(window).on('load', function() {
$.ajax({
url: "{% url 'sidebar' %}", // assuming this is inside a template, if not {% url %} won't work and you'll have to get it in a different way
success: function(data) {
if (data.length > 0) {
for (var i=0; i<data.length; i++) {
var elem = $("<li>" + data[i].name + "</li>")
$("#companies").append(elem)
}
}
})
})
我正在开发一个内部应用程序,我希望能够嵌套我的视图以使一切井井有条。我计划通过将页面的不同部分保留在它们自己的 HTML 文件中来实现这一点,这些文件具有它们自己的视图(单独的侧边栏和导航栏、单独的图表等)。
views.py
from django.shortcuts import render
from django.views.generic import TemplateView
import Recall.data_logger.models as DLM
class ReportHome(TemplateView):
template_name = 'data_logger/index.html'
class SelectorSidebar(TemplateView):
template_name = 'data_logger/sidebar.html'
def get(self, request, *args, **kwargs):
companies = DLM.Company.objects.order_by('company_name').all()
return render(request, self.template_name, {'companies':companies,})
index.html
<html>
<head></head>
<body data-gr-c-s-loaded="true">
{% include 'data_logger/navbar.html' %}
<div class="container-fluid">
<div class="row">
{% include 'data_logger/sidebar.html' %} <!-- This is the part I need help with-->
</div>
</div>
</body>
</html>
sidebar.html
<div class="col-sm-3 col-md-1 sidebar">
<ul class="nav nav-sidebar">
{% for company in companies %}
<li><a href="#">{{ company.company_name }}</a></li>
{% endfor %}
</ul>
</div>
我知道仅使用 {% include 'data_logger/sidebar.html' %}
它只是加载 HTML 并绕过 SelectorSidebar
,如何通过视图引导它?
我想要一个允许我访问任何内容的解决方案,从简单的名称列表到被馈送到 D3 图表中的相对较大的数据集。
解决方案
这是我最终使用的:
index.html
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
crossorigin="anonymous"></script>
<script>
$.get("_sidebar", function(data, status){
$("#_sidebar").html(data);
});
</script>
</head>
<body data-gr-c-s-loaded="true">
{% include 'data_logger/navbar.html' %}
<div class="container-fluid">
<div class="row" id="_sidebar"></div>
</div>
</body>
</html>
其中 _sidebar
是 SelectorSidebar 的 URL:
urlpatterns = [
path('', v.ReportHome.as_view(), name='ReportHome'),
path('_sidebar', v.SelectorSidebar.as_view(), name='SelectorSidebar'),
]
我认为您对 Django 模板和视图如何协同工作感到困惑。
用非常简单的术语来说,Django 模板就是定义构成页面的 HTML 代码的东西。您可以使您的模板非常模块化和有条理;为此,您可以使用 include
模板标签或使用 template inheritance,这是拥有 "modular" 模板的非常强大的方法。
Django 视图基本上是一个接收 HTTP 请求并构建 HTTP 响应的函数(或者您使用的 class 基于 class 的视图)。 拥有 "nested" 个视图没有多大意义,因为通常您只有一个 HTTP 请求,而您只想构建一个具有显示页面所需 HTML 的响应。
所以我认为您可以愉快地使用 Django 模板将构成页面的所有模块(页眉、侧边栏等)放在一起,但每个页面都应对应一个 Django 视图。
另一种方法可以使用 AJAX 和 Javascript 发出不同的 HTTP 请求并在客户端构建页面,但我认为这不是您在此考虑的方法。
正如@baxeico 所回答的那样,一个页面不能有多个视图,因为一个 HTTP 请求就是一个视图。
如果您的内容需要出现在很多页面上,例如侧边栏,并且该内容还需要一些上下文信息才能呈现(例如要从数据库中获取的 companies
列表),你有两个选择:
如果需要添加到边栏的内容相当有限,请创建一个模板 context processor,然后将其添加到设置中的上下文处理器列表(
TEMPLATES
设置).def sidebar_context(request): return {'companies': DLM.Company.objects.order_by('company_name').all()}
在您的设置中,您可以在列表顶部添加类似
'myapp.custom_contexts.sidebar_context'
的内容。现在,每个模板都可以访问上下文变量
companies
,包括您的边栏模板。如果边栏中显示的内容更动态或更复杂,您应该考虑使用 AJAX 从浏览器中获取数据。您将创建一个 returns JSON 而不是 HTML 的视图,并在侧边栏模板中添加 javascript 以获取数据并填充侧边栏。
视图与您当前的视图一样简单:
def sidebar(request): return JsonResponse({'companies': Company.objects.all().values('name', 'id')})
这将 return 包含每个公司的名称和 ID 的字典列表。在成功响应的 AJAX 处理程序中(接收
data
),然后您可以循环遍历data
并访问您可以使用的data[i].name
和data[i].id
填充您的列表。我不会发布完整的 javascript(请搜索 jQuery、ajax 和 django),但这里有一点可以给你一个想法,假设jQuery:
$(window).on('load', function() { $.ajax({ url: "{% url 'sidebar' %}", // assuming this is inside a template, if not {% url %} won't work and you'll have to get it in a different way success: function(data) { if (data.length > 0) { for (var i=0; i<data.length; i++) { var elem = $("<li>" + data[i].name + "</li>") $("#companies").append(elem) } } }) })