Django 模板:按外键过滤数据 views.py食谱.htmlingredients.htmlurls.py

问题描述

我是 Django 的新手,我有一个似乎无法解决的问题。长话短说,我创建了一个基于文本的应用程序,可帮助我创建膳食计划并生成购物清单。我正在尝试用 django 重新创建。

这是我的模型:

class Recipe(models.Model):
    name = models.CharField(max_length=40)

    def __str__(self):
        return self.name


class Category(models.Model):
    name = models.CharField(max_length=20)

    def __str__(self):
        return self.name


class Ingredient(models.Model):
    name = models.CharField(max_length=20)
    category = models.ForeignKey(Category,on_delete=models.CASCADE)

    def __str__(self):
        return self.name


class IngredientSet(models.Model):
    recipe = models.ForeignKey(Recipe,on_delete=models.SET_NULL,null=True)
    ingredient = models.ForeignKey(Ingredient,on_delete=models.DO_nothing)
    quantity = models.FloatField()

    def __str__(self):
        return self.ingredient.name

现在,在我的列表视图中,我想将存储的食谱名称显示链接。每个菜谱链接都应调用一个详细视图,该视图将显示所选菜谱的成分组。我不知道如何通过它们的外键(指向配方)访问它们。

解决方法

可以通过使用小写的模型名称并附加 _set 来访问反向关系。对于 RecipeIngredientSet,您可以编写 recipe.ingredientset_set.all() 以获取与配方相关的所有 IngredientSet 实例。可以通过设置 related_name 来自定义此名称,例如:

class IngredientSet(models.Model):
    recipe = models.ForeignKey(Recipe,on_delete=models.SET_NULL,null=True,related_name="ingredient_sets")
    ingredient = models.ForeignKey(Ingredient,on_delete=models.DO_NOTHING)
    quantity = models.FloatField()

    def __str__(self):
        return self.ingredient.name

现在您可以编写 recipe.ingredient_sets.all()

要在模板中循环,可以简单地写:

{% for ingredient_set in recipe.ingredient_sets.all %}
    {{ ingredient_set.ingredient.name }}
    {{ ingredient_set.quantity }}
{% endfor %}

注意:这将对每个食谱的数据库进行查询,以获取其成分集。您可以使用 prefetch_related [Django docs] 如果您想减少查询次数。

,

假设您想将 html 模板中存储的食谱名称显示为链接:

views.py

from .models import Recipe,Ingredient,IngredientSet
from django.shortcuts import render

def recipes(request):
    recipes_for_template = Recipe.objects.all()
    return render(request,'main/recipes.html',{"recipes": recipes_for_template})

def ingredients(request,cod_recipe):
    ingredients_sets = IngredientSet.objects.filter(recipe=cod_recipe)
    ingredients_to_template = []
    for ingredient_set in ingredients_sets:
        ingredient_obj = Ingredient.objects.get(id=ingredient_set.id)
        dict_of_ingredient = {
            "name": ingredient_obj.name,"quantity": ingredient_set.quantity
        }
        ingredients_to_template.append(dict_of_ingredient)
    return render(request,'main/ingredients.html',{"ingredients": ingredients_to_template})

其中 main 是应用程序的名称

食谱.html

<table>
    <thead>
        <th>Recipe</th>
    </thead>
    <tbody>
        {% for recipe in recipes %}
        <tr>
            <td>
                <a href="./{{recipe.id}}/">{{recipe.id}}</a>
            </td>
        </tr>
        {% endfor %}
    </tbody>
</table>

ingredients.html

{% for ingredient in ingredients %}
    {{ingredient.name}}
    {{ingredient.quantity}}
{% endfor %}

urls.py

from django.urls import path

from . import views


app_name = "main"

urlpatterns = [
    path('recipe/',views.recipes,name='recipes'),path('recipe/<int:cod_recipe>/',views.ingredients,name='ingredients'),]

我想就是这样,任何疑问我都会很乐意回答。