Django新手求助:如何按序将多模型数据渲染至HTML不同板块?
问题说明
首次开发Django项目,页面使用Bootstrap折叠面板,现有关联模型、模板及视图代码如下,需实现不同案例对应数量不同的折叠面板,并从各模型取数据对应展示到HTML板块,需求包括:
- 为各数据表创建对象的方法
- 页面动态展示各表存储的数据
现有模型代码
class CaseStudy_list(models.Model): CaseStudy_id = models.IntegerField(primary_key=True) title = models.CharField(max_length=255) def __str__(self): return self.title class CaseStudy_parts(models.Model): # 对应折叠面板 case_study = models.ForeignKey(CaseStudy_list, on_delete=models.CASCADE) CaseStudy_part_id = models.AutoField(primary_key=True) CaseStudy_order = models.IntegerField(default="") CaseStudy_title_accordian = models.CharField(max_length=255) def __str__(self): return self.CaseStudy_title_accordian class CaseStudy_content(models.Model): # 左侧文本区 case_study = models.ForeignKey(CaseStudy_list, on_delete=models.CASCADE) content_title = models.CharField(max_length=255, default="") content_text = models.TextField(blank=True) content_link = models.TextField(blank=True) def __str__(self): return self.content_title class CaseStudy_Media(models.Model): # 右侧媒体区 case_study = models.ForeignKey(CaseStudy_list, on_delete=models.CASCADE) content_img = models.ImageField(upload_to='casestudy/images', default="") class CaseStudy_buttons(models.Model): content = models.ForeignKey(CaseStudy_content, on_delete=models.CASCADE) button_id = models.CharField(max_length=255) button_label = models.CharField(max_length=255)
解决方案
一、模型关联优化(可选但逻辑更合理)
当前CaseStudy_content、CaseStudy_Media直接关联CaseStudy_list,但实际每个折叠面板(CaseStudy_parts)应对应专属内容和媒体,建议调整外键关联:
# 修改CaseStudy_content外键 class CaseStudy_content(models.Model): case_study_part = models.ForeignKey(CaseStudy_parts, on_delete=models.CASCADE) content_title = models.CharField(max_length=255, default="") content_text = models.TextField(blank=True) content_link = models.TextField(blank=True) def __str__(self): return self.content_title # 修改CaseStudy_Media外键 class CaseStudy_Media(models.Model): case_study_part = models.ForeignKey(CaseStudy_parts, on_delete=models.CASCADE) content_img = models.ImageField(upload_to='casestudy/images', default="")
二、视图层:正确获取并传递数据
修改视图,获取当前案例下所有折叠面板,同时预加载关联数据减少数据库查询:
from django.shortcuts import get_object_or_404, render def casestudy(request, CaseStudy_id ): # 获取当前案例 casestudy_object = get_object_or_404(CaseStudy_list, CaseStudy_id=CaseStudy_id) # 获取该案例下所有折叠面板,按顺序排序并预加载关联内容、媒体 casestudy_parts = CaseStudy_parts.objects.filter(case_study=casestudy_object)\ .order_by('CaseStudy_order')\ .prefetch_related('casestudy_content_set', 'casestudy_media_set') context = { 'casestudy_object': casestudy_object, 'casestudy_parts': casestudy_parts, # 传递查询集而非模型类 } return render(request, 'casestudy.html', context)
三、模板层:动态渲染折叠面板
使用Django模板标签循环生成折叠面板,避免硬编码:
<div class="page-layout"> <div class="accordion" id="accordionPanelsStayOpenExample"> {% for part in casestudy_parts %} <div class="accordion-item"> <h6 class="accordion-header"> <button class="accordion-button {% if forloop.first %}show{% else %}collapsed{% endif %}" type="button" data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapse{{ forloop.counter }}" aria-expanded="{% if forloop.first %}true{% else %}false{% endif %}" aria-controls="panelsStayOpen-collapse{{ forloop.counter }}"> {{ part.CaseStudy_title_accordian }} </button> </h6> <div id="panelsStayOpen-collapse{{ forloop.counter }}" class="accordion-collapse collapse {% if forloop.first %}show{% endif %}"> <div class="accordion-body"> <div class="container-area"> <!-- 左侧内容区 --> <div class="col-content"> {% for content in part.casestudy_content_set.all %} <div class='introduction-content'> <h3>{{ content.content_title }}</h3> <p>{{ content.content_text }}</p> {% if content.content_link %} <a href="{{ content.content_link }}" target="_blank">查看详情</a> {% endif %} <!-- 渲染对应按钮 --> {% for button in content.casestudy_buttons_set.all %} <button type="button" id="{{ button.button_id }}" class="process-btn btn btn-info"> {{ button.button_label }} </button> {% endfor %} </div> {% endfor %} </div> <!-- 右侧媒体区 --> <div class="col-data"> {% for media in part.casestudy_media_set.all %} {% if media.content_img %} <img src="{{ media.content_img.url }}" alt="案例媒体图"> {% endif %} {% endfor %} </div> </div> </div> </div> </div> {% endfor %} </div> </div>
模板说明:
- 用
{% for %}循环遍历所有折叠面板,动态生成唯一ID避免重复 - 第一个面板默认展开,其余默认折叠
- 通过反向关联
part.casestudy_content_set.all获取当前面板的内容,同理获取媒体和按钮
四、创建数据表对象的方法
方法1:Django Admin后台创建
- 在
admin.py中注册所有模型:
from django.contrib import admin from .models import CaseStudy_list, CaseStudy_parts, CaseStudy_content, CaseStudy_Media, CaseStudy_buttons admin.site.register(CaseStudy_list) admin.site.register(CaseStudy_parts) admin.site.register(CaseStudy_content) admin.site.register(CaseStudy_Media) admin.site.register(CaseStudy_buttons)
- 运行
python manage.py createsuperuser创建管理员账号,登录后台即可手动添加数据。
方法2:脚本批量创建
编写populate_data.py脚本(放在app目录下):
import os os.environ.setdefault('DJANGO_SETTINGS_MODULE', '你的项目名.settings') import django django.setup() from 你的app名.models import CaseStudy_list, CaseStudy_parts, CaseStudy_content, CaseStudy_Media, CaseStudy_buttons # 创建案例 case1 = CaseStudy_list.objects.create(CaseStudy_id=1, title="Iris数据集案例") # 创建折叠面板 part1 = CaseStudy_parts.objects.create(case_study=case1, CaseStudy_order=1, CaseStudy_title_accordian="项目概述") # 创建内容 content1 = CaseStudy_content.objects.create(case_study_part=part1, content_title="项目目标", content_text="分析Iris数据集特征,实现分类模型") # 创建按钮 CaseStudy_buttons.objects.create(content=content1, button_id="load-data-btn", button_label="加载数据") # 创建媒体 CaseStudy_Media.objects.create(case_study_part=part1, content_img="casestudy/images/iris-full-img.png")
运行脚本:python manage.py shell < populate_data.py
内容的提问来源于stack exchange,提问作者Abheer Mehrotra
相关产品推荐
相关产品推荐

