我想用SQLAlchemy为食谱创建一个数据库,但是我不确定我的方法是否正确。如何将数据插入recipe_ingredient表?
我的方法:
食谱有一个名称,可以有多种成分。一种成分包括量,单位和名称(成分表),例如500毫升水。
表食谱 - id,主键 - 名称 (一个食谱可以有多种成分,一种成分可以有多种食谱)
table recipe_ingredient
表金额
表单位
表成分
代码:
recipe_ingredient = db.Table('recipe_ingredient',
db.Column('idrecipe', db.Integer, db.ForeignKey('recipe.id')),
db.Column('idingredient', db.Integer, db.ForeignKey('ingredients.id')),
db.Column('idunit', db.Integer, db.ForeignKey('units.id')),
db.Column('idamount', db.Integer, db.ForeignKey('amounts.id'))
)
class Recipe(db.Model):
id= db.Column(db.Integer, primary_key=True, autoincrement=True)
name= db.Column(db.VARCHAR(70), index=True)
ingredient= db.relationship("Ingredients", secondary=recipe_ingredient, backref='recipe')
amounts = db.relationship("Amounts", secondary=recipe_ingredient, backref='recipe')
units= db.relationship("Units", secondary=recipe_ingredient , backref='recipe')
class Ingredients(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
ingredient = db.Column(db.VARCHAR(200))
class Units(db.Model):
id= db.Column(db.Integer, primary_key=True, autoincrement=True)
unit= db.Column(db.VARCHAR(45), nullable=False)
class Amounts(db.Model):
id= db.Column(db.Integer, primary_key=True, autoincrement=True)
amount= db.Column(db.VARCHAR(45), nullable=False)
更新
class RecipeIngredient(db.Model):
__tablename__ = 'recipe_ingredient'
recipe_id = db.Column(db.Integer, db.ForeignKey('recipe.id'), primary_key=True)
ingredient_id = db.Column(db.Integer, db.ForeignKey('ingredient.id'), primary_key=True)
amount = db.Column(db.Integer, db.ForeignKey('amount.id'))
unit = db.Column(db.Integer, db.ForeignKey('unit.id'))
recipes = relationship("Recipe", back_populates="ingredients")
ingredients = relationship("Ingredient", back_populates="recipes")
class Recipe(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.VARCHAR(70), index=True)
ingredients = relationship("RecipeIngredient", back_populates="recipes")
class Ingredient(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.VARCHAR(200))
recipes = relationship("RecipeIngredient", back_populates="ingredients")
class Unit(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.VARCHAR(45), nullable=False)
class Amount(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
number = db.Column(db.VARCHAR(45), nullable=False)
我添加了以下对象
pizza = Recipe(name='Pizza')
flour = Ingredient(name='Flour')
water = Ingredient(name='Water')
g = Unit(name='g')
ml = Unit(name='ml')
a500 = Amount(number='500')
a100 = Amount(number='100')
r1= RecipeIngredient(recipe_id=pizza.id, ingredient_id=flour.id, amount=a500.id, unit=g.id)
r2= RecipeIngredient(recipe_id=pizza.id, ingredient_id=water.id, amount=a100.id, unit=ml.id)
pizza.ingredients的结果:
[<RecipeIngredient 1, 1>, <RecipeIngredient 1, 3>]
我需要添加到该模型中以获取成分的名称:
pizza.ingredients[0].name
答案 0 :(得分:2)
因此,您的关系定义和多对多recipe_ingredient
表格很好。您可以使用您拥有的代码执行您想要的操作。您有一些风格问题会使您的代码难以阅读。
让我们先来看看你的功能:
Recipe
个对象将具有ingredient
属性,其作用类似于列表。您可以向其附加Ingredients
个对象,当您调用它时,您将拥有Ingredients
的常规Python列表:
# Make a cake,
cake = Recipe(name='Cake')
flour = Ingredients(ingredient='Flour')
eggs = Ingredients(ingredient='Eggs')
cake.ingredient.append(flour)
cake.ingredient.append(eggs)
for i in cake.ingredient:
print(i.ingredient)
因为您已经定义了Recipe.amount
的{{1}}关系,secondary
,所以SQLAlchemy拥有管理多对多关系所需的所有信息。
secondary=recipe_ingredient
个对象将具有Ingredients
属性,其作用类似于列表,并引用相同的关系:
recipe
您甚至可以将配方添加到配料中,而不是将配料添加到配方中,它的工作方式也是如此:
# Find recipes using flour
for r in flour.recipe:
print(r.name)
你可能已经注意到,你命名的方式使它看起来有点笨拙。当任何属性引用a-to-many关系时,使用复数时更清楚。例如,# Make cookies
cookies = Recipe(name='Cookies')
eggs.recipe.append(cookies)
for i in cookies.ingredient:
print(i.ingredient)
中的成分关系如果实际上被称为Recipe
而不是ingredients
,则读起来会更好。这将让我们遍历ingredient
。反方向也是如此:调用backref cake.ingredients
而不是配方将使recipes
引用多个链接的食谱更加清晰,其中flour.recipes
可能有点误导。< / p>
关于对象是复数还是单数,也存在不一致。 flour.recipe
是单数,但Recipe
是复数。老实说,哪些是正确的风格的意见并不普遍 - 我更喜欢对我的所有模型使用单数,Ingredients
,Recipe
,Ingredient
,Amount
- 但这是只有我。选择一种风格并坚持下去,而不是在它们之间切换。
最后,您的属性名称有点多余。 Unit
有点多了。 Ingredients.ingredient
更有意义,而且更清晰。
这里还有一件事 - 它让我觉得你想要存储关于你的食谱/配料关系的更多信息,这是一种成分的数量和单位。您可能需要2个鸡蛋或500克面粉,我猜这是您的Ingredient.name
和Amounts
表的用途。在这种情况下,这些附加信息是您关系的关键部分,而不是尝试在单独的表中进行匹配,您可以直接在关联表中对其进行故事记录。这需要更多的工作 - SQLAlchemy文档更深入地了解如何使用Association object来管理这些额外的数据。我只想说使用这种模式可以使你的代码更清洁,更容易长期管理。
@ user7055220在我看来,您不需要单独的Units
或Amount
表,因为这些值仅作为Unit
关系的一部分具有意义。我会删除这些表格,并将RecipeIngredient
中的amount
和unit
属性更改为直接RecipeIngredient
和String
值,直接存储单位/金额:
Integer
在任何一种情况下,要回答关于如何访问成分值的问题 - 在您的示例中class RecipeIngredient(db.Model):
__tablename__ = 'recipe_ingredient'
recipe_id = db.Column(db.Integer, db.ForeignKey('recipe.id'), primary_key=True)
ingredient_id = db.Column(db.Integer, db.ForeignKey('ingredient.id'), primary_key=True)
amount = db.Column(db.Integer)
unit = db.Column(db.VARCHAR(45), nullable=False)
recipes = relationship("Recipe", back_populates="ingredients")
ingredients = relationship("Ingredient", back_populates="recipes")
现在包含一组关联对象。该成分是该关联对象的子成员,可以通过其pizza.ingredients
属性进行访问。如果您进行上述建议的更改,则可以直接访问ingredients
和unit
值。访问该数据将如下所示:
amount
或者,如果您只想使用您询问的语法:
for i in pizza.ingredients:
print(i.amount) # This only works if you're storing the amount directly in the association proxy table as per my example above
print(i.unit) # Same goes for this
print(i.ingredients.name) # here, the ingredient is accessed via the "ingredients" attribute of the association object
关于命名的另一件事:请注意,当关联对象中的backref对象只映射到单个成分时,它被称为print(pizza.ingredients[0].ingredients.name)
,因此它应该是单数 - 那么上面的示例将是{{ 1}},听起来好一点