sqlalchemy:与多个表的非平凡的一对一关系

时间:2014-07-20 15:37:51

标签: python sqlalchemy flask-sqlalchemy

我正在努力为我的Flask应用程序创建数据库模型。

让我们考虑一下我的产品类型很少,并且由于我的应用程序的性质,我想为每个产品分别创建表,同时将通用属性保存在一个公共表中:

Database diagram

示例:

  • 产品

    id  type          name      price
    1   'motorcycle'  'Harley'  10000.00
    2   'book'        'Bible'   9.99
    
  • 摩托车

    id  manufacturer       model                max_speed
    1   'Harley-Davidson'  'Night Rod Special'  150
    
  • 图书

    id  author              pages
    2   'Some random dude'  666
    

需要考虑的事项:

  • 所有表格都有一对一的关系
  • 产品表中 motorcycle_id book_id etc_id 选项
  • 在产品表中 product_id 是可以接受的
  • 双向关系

我如何宣布这种关系?

1 个答案:

答案 0 :(得分:3)

您正在寻找joined table inheritance。基类和每个子类各自创建自己的表,每个子类都有一个指向基表的外键主键。无论您是查询基类还是子类,SQLAlchemy都会自动处理加入。

以下是一些产品的工作示例:

from decimal import Decimal
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, Numeric
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

engine = create_engine('sqlite:///:memory:', echo=True)
session = sessionmaker(bind=engine)()
Base = declarative_base(bind=engine)


class Product(Base):
    __tablename__ = 'product'

    id = Column(Integer, primary_key=True)
    type = Column(String, nullable=False)
    name = Column(String, nullable=False, default='')
    price = Column(Numeric(7, 2), nullable=False, default=Decimal(0.0))

    __mapper_args__ = {
        'polymorphic_on': type,  # subclasses will each have a unique type
    }


class Motorcycle(Product):
    __tablename__ = 'motorcycle'

    # id is still primary key, but also foreign key to base class
    id = Column(Integer, ForeignKey(Product.id), primary_key=True)
    manufacturer = Column(String, nullable=False, default='')
    model = Column(String, nullable=False, default='')
    max_speed = Column(Integer, nullable=False, default=0)

    __mapper_args__ = {
        'polymorphic_identity': 'motorcycle',  # unique type for subclass
    }


class Book(Product):
    __tablename__ = 'book'

    id = Column(Integer, ForeignKey(Product.id), primary_key=True)
    author = Column(String, nullable=False, default='')
    pages = Column(Integer, nullable=False, default=0)

    __mapper_args__ = {
        'polymorphic_identity': 'book',
    }


Base.metadata.create_all()

# insert some products
session.add(Book())
session.add(Motorcycle())
session.commit()

print(session.query(Product).count())  # 2 products
print(session.query(Book).count())  # 1 book