在SQLAlchemy中以有效的方式使用一对多关系

时间:2015-05-06 12:41:51

标签: python sqlalchemy one-to-many

我是初学SQL用户。

我有一个包含三个表的数据库,表人和表酒店和公寓。每个人与一个酒店或公寓只有一个关系,但每个酒店或公寓可以分配一个或多个人。

拥有以下架构:

class Person(Base):
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True, nullable=False)
    person_name = Column(String, nullable=False)
    status = Column(String, nullable=False) 

class Hotel(Base):
    __tablename__ = 'hotel'
    id = Column(Integer, primary_key=True, nullable=False)
    hotel_name = Column(String, nullable=False)
    hotel_address = Column(String)

    person_id = Column(Integer, ForeignKey("person.id"), nullable=False)
    person = relationship("Person", backref=backref("hotel", uselist=False))

class Apartment(Base):
    __tablename__ = 'apartment'
    id = Column(Integer, primary_key=True, nullable=False)
    apartment_address = Column(String, nullable=False)

    person_id = Column(Integer, ForeignKey("person.id"), nullable=False)
    person = relationship("Person", backref=backref("apartment", uselist=False))

或者这个,每个酒店和公寓都有一个唯一的密钥,并且过滤新的“密钥”栏:

class Person(Base):
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True, nullable=False)
    person_name = Column(String, nullable=False)
    status = Column(String, nullable=False) 
    key = Column(String, nullable=False) 

class Hotel(Base):
    __tablename__ = 'hotel'
    id = Column(Integer, primary_key=True, nullable=False)
    hotel_name = Column(String, nullable=False)
    hotel_address = Column(String)
    key = Column(String, nullable=False, unique=True)

class Apartment(Base):
    __tablename__ = 'apartment'
    id = Column(Integer, primary_key=True, nullable=False)
    apartment_address = Column(String, nullable=False)
    key = Column(String, nullable=False, unique=True)

拥有唯一键时,酒店和公寓表中的列“id”是否不必要?

第二个问题是关于Person表中的这一列:

status = Column(String, nullable=False) 

我想让状态栏只是(酒店,公寓)中的一个值,它可以告诉我们在酒店或公寓的表格中找到关系的确切位置。

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

在第一个示例中,person_idHotel表中有Apartment个列,这意味着您将在HotelApartment表中有单独的记录每个人,看起来不像你打算做的那样。因此,外键应移至Person表。 因此,下一个问题是对两个表使用一个外键,这样您就不必进行繁琐的检查(例如检查设置apartment_id时是否设置了hotel_id)。这可以使用SqlAlchemy的polymorphic_identity来完成。你可以阅读它here。在这种情况下,这是您的模型结构应该是什么样的:

class Person(Base):
        __tablename__ = 'person'
        id = Column(Integer, primary_key=True, nullable=False)
        person_name = Column(String, nullable=False)

        accommodation_id = Column(Integer, ForeignKey("accommodation.id"))
        accommodation = relationship("Accommodation", backref="people")


class Accommodation(Base):
    __tablename__ = 'accommodation'
    __mapper_args__ = {
        'polymorphic_identity':'accommodation',
        # polymorphic_on determines the field that will have values like 'hotel' and 'apartment' depending on the table
        'polymorphic_on': 'accommodation_type'
    }

    id = Column(Integer, primary_key=True)
    accommodation_type = Column(String(32))
    address = Column(String)


class Hotel(Accommodation):
        __tablename__ = 'hotel'
        __mapper_args__ = {
            # all the records in this table will have accommodation_type = 'hotel'
            'polymorphic_identity': 'hotel'
        }

        id = Column(Integer, ForeignKey('accommodation.id'), primary_key=True)
        hotel_name = Column(String, nullable=False)


class Apartment(Accommodation):
        __tablename__ = 'apartment'
        __mapper_args__ = {
            # all the records in this table will have accommodation_type = 'apartment'
            'polymorphic_identity': 'apartment'
        }

        id = Column(Integer, ForeignKey('accommodation.id'), primary_key=True)

这样,您就拥有了基本模型Accommodation,并且id链接到表idHotel中的Appartment列,这些列仅包含特定于他们的字段。 person.accommodation将返回酒店或公寓,具体取决于实际值,并且父表和子表的所有属性都将可用。这样您就可以确保一个人不会被连接到酒店和公寓。您可以通过选中person.accommodation.accommodation_type来查看此人的住宿类型。