Let’s say I have the following models:
class Customer(Model): __tablename__ = 'customer' id = Column(Integer()) treatments = relationship('Treatment', back_populates='customer') shipments = relationship('Shipment', back_populates='customer') class Treatment(Model): __tablename__ = 'treatment' customer_id = Column(Integer(), ForeignKey('customer.id')) customer = relationship('Customer', back_populates='treatments') treatment_date = Column(DateTime(), nullable=False) class Shipment(Model): __tablename__ = 'shipment' customer_id = Column(Integer(), ForeignKey('customer.id')) customer = relationship('Customer', back_populates='shipments') ship_date = Column(DateTime(), nullable=False)
I would like to be able to default the Shipment.ship_date to be the day before the Treatment.treatment_date. In other words, I want to do the following:
customer = Customer() treatment = Treatment(treatment_date="11/02/2017") customer.treatments.append(treatment) shipment = Shipment() customer.shipments.append(shipment) shipment.ship_date # 11/01/2017
How do I set defaults based on relationships when they’re set dynamically by methods like append
?
For clarification, this is a question about SqlAlchemy and when relationships are set up. For example, I’ve tried the following:
class Shipment(Model): # ...same set up as above def __init__(self, **kwargs): super().__init__(**kwargs) self.ship_date = self.customer.treatments[0].treatment_date - timedelta(1)
But that throws a TypeError because SqlAlchemy hasn’t set up the self.customer
field yet.
Advertisement
Answer
It appears as though SQLAlchemy does not configure relationships both ways until after the model has been added and committed to the session.
customer.shipments.append(new_shipment) customer.shipments # includes the new shipment new_shipment.customer # None session.add(customer) session.commit() new_shipment.customer # <Customer object>
While this is annoying and I’m not sure why SQLAlchemy doesn’t populate the two-way relationship when one side is created, it can be resolved by manually setting the relationship on both sides. For example:
new_shipment = Shipment(customer=customer) new_shipment.ship_date # 11/01/2017 customer.shipments.append(new_shipment)