如何在CourseDetailView中展示关联的Module实例?
Django 关联模型数据展示问题解决
问题背景
我通过外键关联了Course、Module、Report三个模型,想要在CourseDetailView(DetailView)中展示当前课程对应的所有Module实例,以及每个Module关联的Report实例。但目前用Module.objects.all()会取出所有模块,无法过滤出当前课程对应的部分,不知道该如何处理。
模型定义
class Course(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=200, blank=True, null=True)
class Module(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=200, blank=True, null=True) course_id = models.ForeignKey( Course, null=True, on_delete=models.SET_NULL, related_name="modules", default=uuid.uuid4, )
class Report(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=200, blank=True, null=True) module_id = models.ForeignKey( Module, null=True, on_delete=models.SET_NULL, related_name="reports", default=uuid.uuid4, )
当前视图代码
class CourseDetailView(DetailView): model = Course context_object_name = "course" template_name = "course/course_detail.html" fields = ["title", "description"] def get_context_data(self, **kwargs): context = super(CourseDetailView, self).get_context_data(**kwargs) context["courses"] = Course.objects.filter(pk=self.kwargs.get("pk")) return context
当前模板代码
{{ course.description|safe }} {% for module in modules %} <div> <h2><a href="{{ module.get_absolute_url }}">{{ modules.title }}</a></h2> </div> {% endfor %}
解决方案
1. 获取当前课程关联的Module
DetailView会自动将当前请求的Course实例赋值给self.object,结合Module外键设置的related_name="modules",可以直接通过实例关联获取对应模块:
修改get_context_data方法:
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 直接通过当前Course实例获取关联的所有Module context["modules"] = self.object.modules.all() return context
如果不想依赖related_name,也可以手动过滤:
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["modules"] = Module.objects.filter(course_id=self.object) return context
2. 修正模板错误
模板中循环变量是module,但你写了{{ modules.title }},这会导致无法正确显示模块标题,需要改为:
{{ course.description|safe }} {% for module in modules %} <div> <h2><a href="{{ module.get_absolute_url }}">{{ module.title }}</a></h2> <!-- 额外:展示当前模块关联的Report --> {% for report in module.reports.all %} <p>{{ report.title }}</p> {% endfor %} </div> {% endfor %}
3. 性能优化(可选)
为避免页面渲染时出现N+1查询问题,可以预加载关联数据,在视图中添加get_queryset方法:
def get_queryset(self): # 预加载当前课程的所有Module,以及每个Module的Report return Course.objects.prefetch_related('modules__reports').filter(pk=self.kwargs.get("pk"))
内容的提问来源于stack exchange,提问作者BlindSide
相关产品推荐
相关产品推荐

