Django父模型视图循环遍历子关联数据报不可迭代错误
问题描述
我尝试过诸多同类场景下其他开发者分享的解决方案,但几乎所有相关问题都对应极为特殊的业务场景,我无法将其适配到自身的开发需求中。
核心需求:在父模型的类视图模板中,通过for循环渲染展示关联的子模型信息
现有代码
模型(Models)定义
class Projects(models.Model): fk_user = models.ForeignKey(User, on_delete=models.CASCADE) name = models.BooleanField(default=False) class Projects_items(models.Model): itemName = models.BooleanField(default=False) fk_project = models.ForeignKey(Projects,on_delete=models.CASCADE, related_name="item") value = models.FloatField()
视图(Views)定义
class projects(LoginRequiredMixin, UserPassesTestMixin, UpdateView): model = Projects fields = [ 'name', ] template_name = 'games/project_details.html' context_object_name = 'projects' def form_valid(self, form): form.instance.fk_user = self.request.user form.save() # return super().form_valid(form) return HttpResponseRedirect(self.request.path_info) def test_func(self): post = self.get_object() if self.request.user == post.fk_user: return True return False
模板文件(projects_details.html)
{% extends './underlay.html' %} {% load static %} {% load crispy_forms_tags %} <link rel="stylesheet" type="text/css" href="{% static 'details.css' %}"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Poppins"> {% block content %} <H2>LIST OF ITEMS BELONGING TO THIS PROJECT</H2> ? 我尝试编写的循环逻辑参考如下: {% for projects.item in projects %} {{ projects.item.itemName }} - {{ projects.item.value }} {% endfor %}
运行报错:
'PROJECTS' OBJECT NOT ITERABLE(Projects对象不可迭代)
错误原因
- 你使用的
UpdateView是单实例视图,传入模板的projects上下文是单个Projects模型对象,不是可遍历的查询集,直接对它做for循环必然报错 - Django模板for循环语法为
{% for 临时遍历变量 in 可迭代对象 %},你写的{% for projects.item in projects %}不符合语法规则 - 子模型外键定义了
related_name="item",一对多的反向关联需要调用.all()才能拿到所有关联子项的集合,你之前的写法完全没有调用反向关联管理器。
解决方案
最简修复(无需修改模型和视图)
直接替换模板里错误的循环代码即可:
{% for item in projects.item.all %} {{ item.itemName }} - {{ item.value }} {% empty %} <p>当前项目暂无关联子项</p> {% endfor %}
说明:Django模板中调用关系管理器的
all()方法可以省略括号,直接写.all即可;{% empty %}标签用于处理无关联子项的场景,避免对应区域空白。
推荐优化
- 修正外键反向关联名,符合Django命名惯例
一对多关系的反向关联名建议使用复数形式,把Projects_items模型的外键字段修改为:
修改后模板循环对应调整为:fk_project = models.ForeignKey(Projects,on_delete=models.CASCADE, related_name="items"){% for item in projects.items.all %} {{ item.itemName }} - {{ item.value }} {% empty %} <p>当前项目暂无关联子项</p> {% endfor %} - 预加载关联数据避免N+1查询
在视图类中添加get_queryset方法,提前预取关联子项,减少数据库查询次数:def get_queryset(self): # 如果改了related_name为items,下面的prefetch_related参数对应改成'items' return super().get_queryset().prefetch_related('item')
内容的提问来源于stack exchange,提问作者Game Analysis
相关产品推荐
相关产品推荐

