Sqlalchemy:版本化模型,二级和二级连接

时间:2016-09-07 09:57:44

标签: python python-3.x sqlalchemy

以下是设置:

有车的任务(例如从A点到B点) - 名为使命的模型。

Mission汽车(型号名为 Car )按日期版本(见下面的型号)

汽车有一个GPS设备(型号名为 GPS ),用于发送信号 当前位置。 GPS设备也按日期进行版本化(参见下面的模型)。

GPS设备与汽车(型号 CArGPS )的附件也会进行版本控制 (见下面的模型) (是的,它非常复杂,我无法改变架构。)

问题:这样设置关系,所以我可以获得任务的版本 汽车(通过 Mission.date_start )并获得附加到这辆车的gps设备版本 版本(通过 Mission.date_start )。

如果是SQL,那就是:

SELECT
  mission.id               AS mission_id,
  mission.date_start       AS mission_date_start,
  mission.car_id           AS mission_car_id,
  car_1.id                 AS car_1_id,
  car_1.car_id             AS car_1_car_id,
  car_1.start_date         AS car_1_start_date,
  car_1.end_date           AS car_1_end_date,
  car_1.version_start_date AS car_1_version_start_date,
  car_1.version_end_date   AS car_1_version_end_date,
  car_gps_1.id             AS car_gps_1_id,
  car_gps_1.gps_id         AS car_gps_1_gps_id,
  car_gps_1.car_id         AS car_gps_1_car_id,
  car_gps_1.start_date     AS car_gps_1_start_date,
  car_gps_1.end_date       AS car_gps_1_end_date,
  gps_1.gps_code           AS gps_1_gps_code
FROM mission

  LEFT OUTER JOIN car AS car_1 ON car_1.car_id = mission.car_id AND
                                  car_1.start_date <= mission.date_start AND
                                  car_1.end_date >= mission.date_start AND
                                  car_1.version_start_date <= mission.date_start AND
                                  car_1.version_end_date >= mission.date_start

  LEFT OUTER JOIN car_gps AS car_gps_1 ON car_gps_1.car_id = mission.car_id AND
                                          car_gps_1.start_date <= mission.date_start AND
                                          car_gps_1.end_date >= mission.date_start

  LEFT OUTER JOIN gps as gps_1 ON gps_1.id = car_gps_1.id AND
                                  gps_1.start_date <= mission.date_start AND
                                  gps_1.end_date >= mission.date_start

所以我想查询,比如

query = session.query(Mission).options(
    joinedload(Mission.car), joinedload(Mission.car_device)
)
results = query.all()

# and get gps code of mission car

gps_code = query.Mission.car_device.gps_code

模型代码等:

class GPS(Base):
    '''Version of gps-device'''
    __tablename__ = 'gps'

    id = Column(Integer(), primary_key=True)
    gps_id = Column(Integer(), primary_key=True)
    start_date = Column(Date(), primary_key=True)
    end_date = Column(Date(), primary_key=True)
    gps_code = Column(VARCHAR(20))


class Car(Base):
    '''Version of car'''
    __tablename__ = 'car'

    id = Column(Integer(), primary_key=True)
    car_id = Column(Integer(), primary_key=True)
    start_date = Column(Date(), primary_key=True)
    end_date = Column(Date(), primary_key=True)
    version_start_date = Column(Date(), primary_key=True)
    version_end_date = Column(Date(), primary_key=True)


class CarGPS(Base):
    '''Version of attachment of gps-device to car'''
    __tablename__ = 'car_gps'

    id = Column(Integer(), nullable=False)
    gps_id = Column(Integer(), ForeignKey(GPS.gps_id), primary_key=True)
    car_id = Column(Integer(), ForeignKey(Car.car_id), primary_key=True)
    start_date = Column(TIMESTAMP(timezone=True), primary_key=True)
    end_date = Column(TIMESTAMP(timezone=True), primary_key=True)


class Mission(Base):
    '''Car mission'''
    __tablename__ = 'mission'

    id = Column(Integer(), primary_key=True, nullable=False)
    date_start = Column(TIMESTAMP(timezone=False))
    car_id = Column(Integer(), ForeignKey(Car.id))

    # Version of mission car
    car = relationship(Car,
                       primaryjoin=and_(Car.car_id == car_id,
                                        Car.start_date <= date_start,
                                        Car.end_date >= date_start,
                                        Car.version_start_date <= date_start,
                                        Car.version_end_date >= date_start),
                       foreign_keys=car_id,
                       uselist=False, viewonly=True)
    # Version of mission car gpd-device attachment
    car_gps = relationship(CarGPS,
                           primaryjoin=and_(CarGPS.car_id == car_id,
                                            CarGPS.start_date <= date_start,
                                            CarGPS.end_date >= date_start),
                           foreign_keys=CarGPS.car_id,
                           uselist=False, viewonly=True)

Session = sessionmaker(bind=engine)
session = Session()

Base.metadata.create_all(engine)
# This query is good but without GPS device of car
query = session.query(Mission).options(
    joinedload(Mission.car), joinedload(Mission.car_gps)
)

query.all()

我是sqlAlchemy的新手,无法理解如何设置此类关系 GPS设备。也许可以使用secondary和secondaryjoin来实现 关系的属性?

目前可以通过此查询实现:

query = query.outerjoin(CarGPS, and_(
                    CarGPS.car_id == Mission.car_id,
                    CarGPS.start_date <= Mission.date_start,
                    CarGPS.end_date >= Mission.date_start))
query = query.outerjoin(
        GPS, and_(GPS.gps_id == CarGPS.gps_id,
                  GPS.start_date <= Mission.date_start,
                  GPS.end_date >= Mission.date_start))

但我想通过关系来做,而不是通过join / outerjoin。 谢谢!

SQLAlchemy版本:sqlalchemy == 1.0.14

Python版本:3.5.1

0 个答案:

没有答案