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

Django HTML模板无法读取嵌套字典中模型字段的问题求助

Django模板无法显示关联模型字段的解决方案

问题背景

在Django项目中,通过context字典传递嵌套结构数据到HTML模板时,无法显示视图传递的模型字段,仅输出{% empty %}分支内容。已确认数据库数据正确,QuerySet已存入字典并传递到模板。

相关代码

模型定义(models.py)

class Ingredients(models.Model):
    id = models.IntegerField(primary_key=True)
    recipe = models.ForeignKey(Recipes, on_delete=models.CASCADE, related_name='ingredients')
    ingredient = models.CharField(max_length=128)

    class Meta:
        managed = False
        db_table = 'ingredients'
        verbose_name_plural = 'Ingredients'

    def __str__(self):
        return f"{self.id} {self.recipe} - {self.ingredient}"

class Recipes(models.Model):
    id = models.IntegerField(primary_key=True)
    category = models.TextField(db_column='Category', null=False)
    submitted_by = models.TextField(
        db_column='Submitted_By', null=False)
    origin = models.TextField(db_column='Origin', null=False)
    title = models.TextField(db_column='Title', null=False)
    directions = models.TextField(
        db_column='Directions', null=False)
    comments = models.TextField(db_column='Comments', null=False)
    created = models.DateTimeField(null=False)
    modified = models.DateTimeField(null=True)

    def __str__(self):
        return f"{self.id} - {self.title}"

    class Meta:
        managed = False
        db_table = 'recipes'
        verbose_name_plural = 'Recipes'

视图代码(views.py)

recipes = Recipes.objects.all().order_by(
    "category", "title")

content['ingredients'] = {}
for recipe in recipes:
    ingredients = Ingredients.objects.filter(
        recipe=recipe.id).order_by("id")
    content['ingredients'][recipe.id] = ingredients
content['recipes'] = recipes

return render(
    request,
    "myApp/recipes.html",
    context=content)

模板代码(recipes.html)

{% for recipe in recipes %}
    <div id="id-{{recipe.id}}" class="grid-item {{recipe.category}} {{recipe.submitted_by}}">
        <div class="row">
            <div class="col-12 col-md-3 ingredients">
                {% for queryQbject in ingredients.recipe.id %}
                    {{ queryQbject.ingredient }}<br>
                {% empty %}
                    <span>No ingredients provided</span>
                {% endfor %}
            </div>
    </div>
{% endfor %}

错误原因

模板中ingredients.recipe.id的写法完全错误:ingredients是一个以菜谱ID为键的字典,而不是对象属性。这种写法无法正确获取对应菜谱的Ingredients QuerySet,导致进入{% empty %}分支。

解决方案

方案1:修复模板的字典取值方式

将模板中的循环行修改为以下两种写法之一:

写法A:使用Django模板的get过滤器

{% for item in ingredients|get:recipe.id %}
    {{ item.ingredient }}<br>
{% empty %}
    <span>No ingredients provided</span>
{% endfor %}

写法B:直接使用字典键取值(Django模板支持方括号语法)

{% for item in ingredients[recipe.id] %}
    {{ item.ingredient }}<br>
{% empty %}
    <span>No ingredients provided</span>
{% endfor %}

方案2:利用模型关联优化代码(更高效推荐)

模型中已经定义了related_name='ingredients',可以直接通过菜谱对象获取关联的食材,无需手动构建字典,还能避免N+1查询问题:

修改视图代码(views.py)

# 使用prefetch_related预取关联的ingredients,提升性能
recipes = Recipes.objects.all().order_by("category", "title").prefetch_related('ingredients')

content['recipes'] = recipes

return render(
    request,
    "myApp/recipes.html",
    context=content)

修改模板代码(recipes.html)

{% for recipe in recipes %}
    <div id="id-{{recipe.id}}" class="grid-item {{recipe.category}} {{recipe.submitted_by}}">
        <div class="row">
            <div class="col-12 col-md-3 ingredients">
                {% for item in recipe.ingredients.all %}
                    {{ item.ingredient }}<br>
                {% empty %}
                    <span>No ingredients provided</span>
                {% endfor %}
            </div>
    </div>
{% endfor %}

说明

方案2不仅简化了代码,还通过prefetch_related一次性加载所有关联数据,避免了循环中多次查询数据库的性能问题,是更推荐的实现方式。

内容的提问来源于stack exchange,提问作者Volker Petersen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 20:55:20