Я пытаюсь объединить две исторические таблицы в 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)>
Каждое место на этой улице.
Заранее спасибо.