如何在Django DetailView中展示单个主题的多条Entry
问题分析
你当前的ContentDetailView继承自DetailView且绑定的是Entries模型,所以它只会根据传入的pk获取单条Entry记录,这就是只能显示一条内容的核心原因。要实现点击主题后展示该主题下的所有Entry,需要把DetailView绑定到Topic模型,再通过Django的反向关联获取该主题对应的所有Entry。
解决方案步骤
1. 修改views.py
将详情视图改为基于Topic模型的DetailView,这样就能获取指定主题对象,后续可通过它关联所有Entry:
# views.py from django.views.generic import ListView, DetailView from .models import Topic, Entries class TopicListView(ListView): model = Topic template_name = 'cms_app/topic_list.html' context_object_name = 'topics' # 改为复数形式,语义更准确 class TopicDetailView(DetailView): model = Topic template_name = 'cms_app/topic_detail.html' # 模板名对应主题详情,更清晰 context_object_name = 'topic'
2. 修改urls.py
更新URL配置,将详情页视图替换为新的TopicDetailView,路径参数保持为Topic的pk:
# urls.py from django.urls import path from .views import TopicListView, TopicDetailView urlpatterns = [ path('', TopicListView.as_view(), name='all-topic'), path('content/<int:pk>', TopicDetailView.as_view(), name='all-content'), ]
3. 调整主题列表模板(topic_list.html)
把循环变量的上下文名改为topics,和ListView的配置对应:
<!-- topic_list.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>All Topics</title> </head> <body> <h1>Topic List</h1> <h3> {% for data in topics %} <p><a href="{% url 'all-content' data.id %}">{{ data.title }}</a></p> {% endfor %} </h3> </body> </html>
4. 创建主题详情模板(topic_detail.html)
通过Django自动生成的反向关联属性topic.entries_set.all,遍历该主题下的所有Entry:
<!-- topic_detail.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ topic.title }} - All Contents</title> </head> <body> <h1>{{ topic.title }}</h1> {% for entry in topic.entries_set.all %} <div class="entry"> <p>{{ entry.text }}</p> {% if entry.image %} <img src="{{ entry.image.url }}" alt="Entry image"> {% endif %} <p>Added on: {{ entry.date_added }}</p> <hr> </div> {% empty %} <p>No entries for this topic yet.</p> {% endfor %} </body> </html>
可选优化:自定义反向关联名称
如果觉得entries_set不够直观,可在Entries模型的外键字段添加related_name参数:
# models.py class Entries(models.Model): '''Entries and Topic will have many to one relationship''' topic = models.ForeignKey(Topic, on_delete=models.CASCADE, related_name='entries') text = models.TextField() image = models.ImageField(upload_to='images', blank=True) date_added = models.DateTimeField(auto_now_add=True)
之后在模板中就可以用topic.entries.all代替topic.entries_set.all,语义更清晰。
内容的提问来源于stack exchange,提问作者Trishna
相关产品推荐
相关产品推荐

