Django中如何正确实现食谱与食材的一对多关联?
解决Django中Recipe与Ingredient的一对多关系问题
嘿,你现在的问题核心是ForeignKey的位置放反了!你想要的是「一个食谱对应多个食材」的一对多关系,这时候ForeignKey应该定义在多的那一端(也就是Ingredient模型),而不是Recipe模型里。
一、修正模型结构
当前你的Recipe模型里的ingredients字段是ForeignKey,这会变成「多个食谱对应同一个食材」的多对一关系,刚好和你的需求相反。我们把ForeignKey移到Ingredient模型,指向Recipe:
from django.db import models class Recipe(models.Model): title = models.CharField(max_length=120) preparation = models.TextField(default='Here comes the preparation...') # 帮你修正了拼写错误哦 def __str__(self): return self.title # 方便在后台和shell里快速识别对象 class Ingredient(models.Model): ingredient_title = models.CharField(max_length=120) amount = models.IntegerField() unit = models.CharField(max_length=10) recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, related_name="ingredients") # 设置related_name后,你可以直接用recipe.ingredients访问关联食材,不用默认的ingredient_set def __str__(self): return f"{self.amount}{self.unit} {self.ingredient_title}"
二、执行数据库迁移
修改完模型后,需要更新数据库结构:
python manage.py makemigrations python manage.py migrate
三、在Shell中创建实例
现在你可以先创建Recipe,再给它绑定多个Ingredient了:
# 1. 先创建一个食谱对象 recipe = Recipe.objects.create(title='Essen1', preparation='prep1') # 2. 给这个食谱添加单个食材 Ingredient.objects.create(ingredient_title="ZutatTitel1", amount=2, unit='g', recipe=recipe) Ingredient.objects.create(ingredient_title="ZutatTitel2", amount=5, unit='ml', recipe=recipe) # 3. 或者批量添加食材 ingredient1 = Ingredient(ingredient_title="ZutatTitel3", amount=1, unit='piece') ingredient2 = Ingredient(ingredient_title="ZutatTitel4", amount=300, unit='g') recipe.ingredients.add(ingredient1, ingredient2) # 得益于我们设置的related_name
四、优化后台管理页面
为了在Django Admin里能直接编辑食谱的所有食材(不用跳转到Ingredient单独页面),可以配置Inline组件:
在admin.py里添加:
from django.contrib import admin from .models import Recipe, Ingredient class IngredientInline(admin.TabularInline): model = Ingredient extra = 3 # 默认显示3个空的食材输入框,方便批量添加 class RecipeAdmin(admin.ModelAdmin): inlines = [IngredientInline] admin.site.register(Recipe, RecipeAdmin) admin.site.register(Ingredient)
现在进入Recipe的后台编辑页面,就能直接添加、修改多个食材了,不用再只能选一个!
五、访问关联数据
- 获取某个食谱的所有食材:
recipe.ingredients.all()(因为设置了related_name) - 获取某个食材所属的食谱:
ingredient.recipe
内容的提问来源于stack exchange,提问作者Frederick
相关产品推荐
相关产品推荐

