You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django模板继承base_planner.html后侧边栏内容丢失求助

问题描述

我有一个包含导航栏(navbar)和侧边栏(sidebar)的base_planner.html模板。其他模板继承该基础模板时,导航栏能正常继承,但侧边栏内容不显示,且无任何报错。唯一能正常显示侧边栏内容的是首页——仅包含一行代码{% extends 'app_planner\base_planner.html' %}的ListView页面projectsmodel_list.html。

代码文件

views.py(希望TestView能继承侧边栏内容)

class ProjectListView(LoginRequiredMixin, generic.edit.FormMixin, generic.ListView):
    context_object_name = 'project_list'
    model = ProjectsModel
    form_class = ProjectsForm
    success_url = reverse_lazy('app_planner:planner_home')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['create_project_form'] = ProjectsForm()
        return context
    
    def form_valid(self, form):
        project_name = form.cleaned_data['project_name']
        project_author = self.request.user
        create_project_form_item = ProjectsModel(project_name=project_name, project_author=project_author)
        create_project_form_item.save()
        return super().form_valid(form)

    def form_invalid(self, form):
        return super().form_invalid(form)

    def post(self, request, *args, **kwargs):
        self.object_list = self.get_queryset()
        form = self.get_form()
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(form)


class TestView(generic.TemplateView):
    template_name = 'app_planner/test.html'

urls.py

app_name = 'app_planner'

urlpatterns = [
    path('', views.ProjectListView.as_view(), name='planner_home'),
    path('test/', views.TestView.as_view(), name='test'),
]

base_planner.html(body部分)

{% if user.is_authenticated %}
        <nav id='navbar' class="navbar navbar-expand-lg bg-white">
            <div class="container-fluid">
              <a id='logo' class="navbar-brand" href="{% url 'app_planner:planner_home' %}"><h3><b><span style="color:#FC5E5E;">Savvy</span> Planner</b></h3></a>
              <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
              </button>
              <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
                <div class="navbar-nav">
                    <div class="navbar-center">
                        <a id='projects_board' class="nav-link {% if request.resolver_match.view_name == 'app_planner:planner_home' %}active{% endif %}" href="{% url 'app_planner:planner_home' %}">Projects & Tasks</a>
                        <a id='analytics' class="nav-link {% if request.resolver_match.view_name == 'app_planner:analytics' %}active{% endif %}" href="#">Analytics</a>
                        <a id='analytics' class="nav-link {% if request.resolver_match.view_name == 'app_planner:test' %}active{% endif %}" href="{% url 'app_planner:test' %}">Test</a>
                    </div>
                    <div class="navbar-right">
                        <a id='notifications' class="nav-link" href="#"><img src="{% static 'notifications_empty.svg' %}"></a>
                        <a id='logout' class="nav-link" href="{% url 'app_planner:logout' %}" class="btn btn-simple"><img src="{% static 'logout.svg' %}" width="20" height="20"></a>
                    </div>
                </div>
            </div>
            </div>
         </nav>

        <div class="sidebar">
            <div class='row' style="font-family: 'Nunito', sans-serif; padding-bottom: 25px;">
                <div class='col-sm-6' style="height: 60px; width: 60px; border-radius: 16px; background-color: #FC5E5E;"></div>
                <div class="col-sm-6" style="width: fit-content;">
                    <p><span style='font-size:25px'><b>Awesome Team</span><br>
                       <span style='color:#888B94'>Workspace</span></b></p>
                </div>
            </div>
            
            <div class='sidebar_projects' style="border-top: solid 2px #E3E4E9; margin-left: -10px;">
                <br>
                <form method="POST">
                    {% csrf_token %}
                    <div class='row project_form'>
                        {% for field in create_project_form %}
                            <div class='col-sm-4' style='align-items:center; display: flex;'>{{ field.label }}</div>
                            <div class='col-sm-4'>{{ field }}</div>
                            <div class='col-sm-4' style='align-items:center; display: flex;'><button id='add_project' type="submit" style='background:white;border:0px;'><img src="{% static 'plus_button.svg' %}"></button></div>
                        {% endfor %}
                    </div>
                </form>

                <div class="row">
                    {% for project in project_list %}
                        <div class='col-sm-12 single_project'><a href="{% url 'app_planner:project_detail'  pk=project.pk %}"><span style='color:rgba(255, 255, 255, 0);'>__</span>{{ project.project_name }}</a></div>
                    {% endfor %}
                </div>
            </div>
        </div>

        <div class='content'>
            {% block content %}
            {% endblock %}
        </div>
        {% endif %}

test.html

{% extends 'app_planner/base_planner.html' %}
{% block content %}
    <h1>Check the sidebar</h1>
{% endblock %}

我试过修改模板、把ProjectListView的内容复制到其他视图、单独创建sidebar.html用{% include %}引入,都没用,侧边栏还是空的。这是第一次遇到{% extend %}相关的异常,找不到问题原因,求帮助。


问题原因与解决办法

侧边栏内容不显示的核心原因是TestView没有向模板传递侧边栏所需的上下文数据:

  • 侧边栏里用到了create_project_form和project_list这两个变量,这两个变量是ProjectListView通过get_context_data和ListView自带的查询集逻辑提供的
  • 而TestView是普通的TemplateView,默认不会传递这两个变量,所以模板里的{% for field in create_project_form %}和{% for project in project_list %}循环都没有数据,看起来侧边栏就空了

解决方法有两种,选适合你的:

方法1:让TestView继承ListView并复用上下文逻辑

把TestView改成继承ListView,同时复用ProjectListView的上下文方法,这样就能自动获取project_list和表单:

class TestView(LoginRequiredMixin, generic.ListView):
    template_name = 'app_planner/test.html'
    model = ProjectsModel
    context_object_name = 'project_list'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['create_project_form'] = ProjectsForm()
        return context

(LoginRequiredMixin要加上,确保用户已登录,和ProjectListView保持一致)

方法2:给TestView手动添加上下文数据

如果你不想让TestView继承ListView,就在TestView里重写get_context_data方法,手动传入需要的变量:

class TestView(LoginRequiredMixin, generic.TemplateView):
    template_name = 'app_planner/test.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 传入项目列表,过滤当前用户的项目(和ProjectListView逻辑一致)
        context['project_list'] = ProjectsModel.objects.filter(project_author=self.request.user)
        # 传入创建项目的表单
        context['create_project_form'] = ProjectsForm()
        return context

额外优化建议

为了避免重复代码,你可以把获取侧边栏上下文的逻辑抽成一个混合类(Mixin),让所有需要侧边栏的视图继承它:

class SidebarContextMixin:
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['create_project_form'] = ProjectsForm()
        context['project_list'] = ProjectsModel.objects.filter(project_author=self.request.user)
        return context

# 然后你的视图可以这样写:
class ProjectListView(LoginRequiredMixin, SidebarContextMixin, generic.edit.FormMixin, generic.ListView):
    # 原有的代码,去掉重复的get_context_data
    context_object_name = 'project_list'
    model = ProjectsModel
    form_class = ProjectsForm
    success_url = reverse_lazy('app_planner:planner_home')

    # ... 其他方法保留,去掉原来的get_context_data ...

class TestView(LoginRequiredMixin, SidebarContextMixin, generic.TemplateView):
    template_name = 'app_planner/test.html'

这样所有继承SidebarContextMixin的视图都会自动拥有侧边栏所需的上下文,不用重复写代码。

内容的提问来源于stack exchange,提问作者Анатолий Григорович

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 20:39:58