在SQL中,一個外鍵必須被映射到一個特定的表,所以你需要把外鍵在「汽車」或「SUV」表指向「info.id」。
這可能是您所需要的矯枉過正,但這裏是解決這個問題的一種方法(假設你做實際上希望每個車到只有一個信息):
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy import event
Base = declarative_base()
class Info(Base):
__tablename__ = 'info'
id = Column(Integer(), primary_key=True)
type = Column(String())
# NOTE: can't use backref='info' because we need the attributes defined
# directly on both classes so we can attach event listeners
car = relationship('Car', back_populates='info', uselist=False)
suv = relationship('Suv', back_populates='info', uselist=False)
@property
def item(self):
# could check self.type here if you wanted
return self.car or self.suv
@item.setter
def item(self, value):
if isinstance(value, Car):
self.car = value
elif isinstance(value, Suv):
self.suv = value
elif value is None:
self.car = None
self.suv = None
else:
raise ValueError("item must be Car or Suv")
@event.listens_for(Info.car, 'set')
def _car_set_event(target, value, oldvalue, initiator):
if value is not None:
target.type = 'car'
if target.suv:
target.suv = None
elif target.type == 'car':
target.type = None
@event.listens_for(Info.suv, 'set')
def _suv_set_event(target, value, oldvalue, initiator):
if value is not None:
target.type = 'suv'
if target.car:
target.car = None
elif target.type == 'suv':
target.type = None
class Car(Base):
__tablename__ = 'car'
id = Column(Integer(), primary_key=True)
info_id = Column(Integer(), ForeignKey('info.id'))
info = relationship(Info, back_populates='car')
@event.listens_for(Car.info, 'set')
def _car_info_set_event(target, value, oldvalue, initiator):
if value is not None:
value.type = 'car'
class Suv(Base):
__tablename__ = 'suv'
id = Column(Integer(), primary_key=True)
info_id = Column(Integer(), ForeignKey('info.id'))
info = relationship(Info, back_populates='suv')
@event.listens_for(Suv.info, 'set')
def _suv_info_set_event(target, value, oldvalue, initiator):
if value is not None:
value.type = 'suv'
什麼事件偵聽器的複雜性讓你的是,類型自動管理,當你做這樣的事情:
car1.info = Info()
assert (car1.info.type == 'car')
或
info1 = car1.info
info1.suv = suv1
assert (car1.info is None)
assert (info1.type == 'suv')
如果您想讓Info.type,Info.car和Info.suv保持一致,您可以省略所有事件偵聽器函數。
爲CarInfo和SuvInfo設置單獨的對象和表也是一個非常合理的選擇,並且完全避免了所有這些複雜性。
每輛車應該與物品有一對一的關係還是一對多? – 2012-02-04 08:52:36
這是汽車或suv和信息之間的一對一 – 2012-02-05 03:35:21