我正在尝试自学SQLAlchemy。使用具有关系的表时遇到了一个问题,但是外键有时是空白的。这是代码:
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()
class Brewer(Base):
__tablename__ = "brewer_table"
brewer_id = Column(Integer, primary_key=True)
brewery_name = Column(String)
class Style(Base):
__tablename__ = 'style_table'
style_id = Column(Integer, primary_key=True)
style_name = Column(String)
class Beer(Base):
__tablename__ = 'beer_table'
beer_id = Column(Integer, primary_key=True)
beer_name = Column(String)
beer_brewer = Column(Integer, ForeignKey("brewer_table.brewer_id"), nullable=True)
beer_style = Column(Integer, ForeignKey("style_table.style_id"), nullable=True)
brewer = relationship(Brewer)
style = relationship(Style)
Base.metadata.create_all(engine)
light_beer = Style(style_name="light beer")
stout = Style(style_name="stout")
ipa = Style(style_name="india pale ale")
session.add_all([light_beer, stout, ipa])
budweiser = Brewer(brewery_name="Budweiser")
stone = Brewer(brewery_name="Stone")
session.add_all([budweiser, stone])
bud_light = Beer(beer_name="Bud Light", brewer=budweiser, style=light_beer)
stone_ipa = Beer(beer_name="Stone IPA", brewer=stone)
stone_americano = Beer(beer_name="Americano Stout", brewer=stone, style=ipa)
session.add_all([bud_light, stone_ipa, stone_americano])
session.commit()
query = session.query(Beer)
for beer in query:
print(f"name: {beer.beer_name}, brewery: {beer.brewer.brewery_name}, style: {beer.style.style_name}")
如您所见,我没有为第二种啤酒设置样式。当我运行它时,它引发异常:AtributeError:'NoneType'没有对象属性'style_name'。如果我添加第二种啤酒的样式,则可以正常运行。
我尝试以几种不同的方式测试值是否为零,但是我无法使该功能生效。
我不知道这种关系是否必须比在此定义的复杂,或者我是否从根本上误解了如何在外键中使用空白值。任何人都可以提供的任何帮助将不胜感激。
答案 0 :(得分:0)
该架构允许将Beer
的{{1}}设为Style
-通过设置None
,因此与nullable=True
一起使用的任何代码都必须能够处理这种可能性。
执行此操作的一种方法是测试f字符串中的style属性,并在Beer
或空字符串时产生一些默认输出。
None
产生
for beer in query:
print(f"name: {beer.beer_name}, brewery: {beer.brewer.brewery_name}, style: {beer.style.style_name if beer.style else 'MISSING'}")
这不是很优雅,很容易忘记每次要打印啤酒详细信息时都要添加此支票。如果您将大量使用此F弦,请考虑将其作为name: Bud Light, brewery: Budweiser, style: light beer
name: Stone IPA, brewery: Stone, style: MISSING
name: Americano Stout, brewery: Stone, style: india pale ale
方法添加到啤酒模型中,如下所示:
__str__