SQLAlchemy空白外键返回AttributeError

时间:2018-08-10 03:55:15

标签: python sqlalchemy

我正在尝试自学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'。如果我添加第二种啤酒的样式,则可以正常运行。

我尝试以几种不同的方式测试值是否为零,但是我无法使该功能生效。

我不知道这种关系是否必须比在此定义的复杂,或者我是否从根本上误解了如何在外键中使用空白值。任何人都可以提供的任何帮助将不胜感激。

1 个答案:

答案 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__