Соотношение на основе значений SQLAlchemy без внешнего ключа - PullRequest
0 голосов
/ 01 октября 2018

Я пытаюсь объединить две исторические таблицы в SQLAlchemy, master-detail.

Каждая таблица имеет дату начала и окончания , и две записи с одинаковым идентификатором являются разными версиямиодного и того же объекта.Когда я запрашиваю ссылочные объекты текущего объекта, я хотел бы получить последнюю версию.

Я не могу построить отношение для запроса подробностей главного объекта.

Здесьпример:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from datetime import date

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, remote, foreign
from sqlalchemy import Column, Integer, String, Date, ForeignKey, cast, and_

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

__all__ = ["Base", "Street", "Place"]


Base = declarative_base()


class Street(Base):
    __tablename__ = 'streets'

    id = Column(Integer, primary_key=True)
    start_date = Column(Date, primary_key=True)
    end_date = Column(Date, default=date(9999, 12, 31), nullable=False)
    name = Column(String(50), nullable=False)

    def __repr__(self) -> str:
        return "<Street(id={}, name='{}')>".format(self.id, self.name)

    def __init__(self, id: int, name: str):
        self.id = id
        self.start_date = date.today()
        self.name = name


class Place(Base):
    __tablename__ = 'places'

    id = Column(Integer, primary_key=True)
    start_date = Column(Date, primary_key=True)
    end_date = Column(Date, default=date(9999, 12, 31), nullable=False)
    name = Column(String(50), nullable=False)
    # street_id = Column(Integer, ForeignKey("Street.id"), nullable=False)
    street_id = Column(Integer, nullable=False)

    def __repr__(self) -> str:
        return "<Place(id={}, name='{}', street_id={})>".format(self.id, self.name, self.street_id)

    def __init__(self, id: int, name: str, street_id: str):
        self.id = id
        self.start_date = date.today()
        self.name = name
        self.street_id = street_id


Place.street = relationship(Street,
                            primaryjoin=and_(remote(Street.id) == foreign(Place.street_id),
                                             cast(remote(Street.end_date), Date) == "9999-12-31"))

Street.places = relationship(Place, order_by=Place.id,
                            primaryjoin=and_(remote(Street.id) == foreign(Place.street_id),
#                                             cast(remote(Place.end_date), Date) == "9999-12-31"))
                                             cast(Place.end_date, Date) == "9999-12-31"))
#                                             cast(foreign(Place.end_date), Date) == "9999-12-31"))

if __name__ == "__main__":
    engine = create_engine("sqlite://")  # , echo=True)
    Session = sessionmaker(bind=engine)
    session = Session()

    Base.metadata.create_all(engine)

    session.query(Place).delete()
    session.query(Street).delete()
    session.commit()
    session.expunge_all()

    session.add_all([Street(1, "First Av."), Street(2, "Second Av.")])
    session.add_all([Place(11, "Place 1, First Av.", 1), Place(12, "Place 2, First Av.", 1),
                     Place(21, "Place 1, Second Av.", 2), Place(22, "Place 2, Second Av.", 2)])
    session.commit()
    session.expunge_all()

    ps = session.query(Place).all()
    for p in ps:
        print(str(p) + str(p.street))

    ss = session.query(Street).all()
    for s in ss:
        print(str(s))
        for p in s.places:
            print("  " + str(p))

В этом коде вы можете видеть, что детали могут ссылаться на своего собственного мастера, но мастера ссылаются на все детали, а не на его собственные.

Что не так с отношениями?

Результат:

<Street(id=1, name='First Av.')>
  <Place(id=11, name='Place 1, First Av.', street_id=1)>
  <Place(id=12, name='Place 2, First Av.', street_id=1)>
  <Place(id=21, name='Place 1, Second Av.', street_id=2)>
  <Place(id=22, name='Place 2, Second Av.', street_id=2)>
<Street(id=2, name='Second Av.')>
  <Place(id=11, name='Place 1, First Av.', street_id=1)>
  <Place(id=12, name='Place 2, First Av.', street_id=1)>
  <Place(id=21, name='Place 1, Second Av.', street_id=2)>
  <Place(id=22, name='Place 2, Second Av.', street_id=2)>

Но это должно быть:

<Street(id=1, name='First Av.')>
  <Place(id=11, name='Place 1, First Av.', street_id=1)>
  <Place(id=12, name='Place 2, First Av.', street_id=1)>
<Street(id=2, name='Second Av.')>
  <Place(id=21, name='Place 1, Second Av.', street_id=2)>
  <Place(id=22, name='Place 2, Second Av.', street_id=2)>

Каждое место на этой улице.

Заранее спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...