Python SQLAlchemy空白外键返回AttributeError

Python SQLAlchemy空白外键返回AttributeError,python,sqlalchemy,Python,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(

我想自学炼金术。我在处理具有关系的表时遇到了一个问题,但外键有时是空的。代码如下:

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\u name”。如果我为第二杯啤酒加上一种风格,它就很好喝了

我试过用几种不同的方法测试值是否为none,但我一直无法做到这一点


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

模式通过设置
nullable=True
,允许
Beer
Style
None
,因此任何与
Beer
一起工作的代码都需要能够处理这种可能性

一种方法是测试f-string中的style属性,如果它是
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'}")
产生

name: Bud Light, brewery: Budweiser, style: light beer
name: Stone IPA, brewery: Stone, style: MISSING
name: Americano Stout, brewery: Stone, style: india pale ale
这不是很优雅,而且每次你想打印啤酒的详细信息时,很容易忘记添加这张支票。如果你要大量使用这个F字符串,考虑把它添加到你的啤酒模型中,作为它的<代码>
class Beer(Base):

    ....

    def __str__(self):
        # This method is called whenever *str* is called on a Beer instance. 
        # Split long string in two and wrap in brackets so Python will
        # automatically concatenate them
        return (f"name: {self.beer_name}, brewery: {self.brewer.brewery_name}, "
                f"style: {self.style.style_name if self.style else 'MISSING'}")

for beer in query:
    print(beer)


name: Bud Light, brewery: Budweiser, style: light beer
name: Stone IPA, brewery: Stone, style: MISSING
name: Americano Stout, brewery: Stone, style: india pale ale

谢谢你的回答。我离得很近,但我不确定自己是否能独自到达那里。