Создание моделей ORM вместе с детьми в SQLAlchemy - PullRequest
0 голосов
/ 30 сентября 2019

Меня всегда смущает, как и когда я могу создавать объекты вместе со своими детьми.

У меня есть заказ, который имеет один ко многим для LineItems и OrderTags, я хочу создать все это вместе. У меня было ощущение, что я должен быть в состоянии сделать

Order(
  ...
  line_items=[LineItem(...) for i in line_items],
  tags=[OrderTags(value="foobar")]
)
session.add(order)
session.commit()

, и это сработало бы, но line_item.order_id s не устанавливаются, а OrderTags терпят неудачу полностью

Iдумаю, это может иметь какое-то отношение к тому, действительно ли line_item.order_id объявляется как FK и как устанавливаются отношения. Вот соответствующие части модели и фактический код, пытающийся создать объекты.

class OrderTag(Base, BaseModelMixin):
    __tablename__ = "order_tags"
​
    id = Column(INTEGER(11), nullable=False, unique=True)
    order_id = Column(ForeignKey("orders.id", ondelete="CASCADE", onupdate="CASCADE"), primary_key=True, nullable=False)
    value = Column(String(45), primary_key=True, nullable=False)
    created_at = Column(DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP"))
​
    order = relationship("Order", uselist=True, back_populates="order_tags")
​
​
class LineItem(Base):
    """
    Line Item Model
    """
​
    """Reflect Table"""
    __tablename__ = "line_items"
​
    id = Column(INTEGER(11), nullable=False, index=True)
    partner_line_item_id = Column(String(45), primary_key=True, nullable=False, index=True)
    account_id = Column(String(9), primary_key=True, nullable=False)
    shop_name = Column(String(128), primary_key=True, nullable=False)
    order_id = Column(INTEGER(11), index=True)
    ....
​
    order = relationship(
        "Order", uselist=False, back_populates="line_items", primaryjoin="Order.id == foreign(LineItem.order_id)"
    )
​
​
class Order(Base, BaseModelMixin, PostCommitTriggersModelMixin, SanitizationModelMixin):
    """
    Order Model
    """
​
    __tablename__ = "orders"
    id = Column(INTEGER(11), nullable=False, unique=True)  # for some reason the autoincrement isn't here, but it definitely is on the DB
    account_id = Column(INTEGER(6), primary_key=True, nullable=False, index=True)
    order_number = Column(String(32), primary_key=True, nullable=False, index=True)
    shop_name = Column(String(128), primary_key=True, nullable=False, index=True, server_default=text("''"))
​
    account = relationship("Account", uselist=False, primaryjoin="Account.id == foreign(Order.account_id)")
​
    line_items = relationship("LineItem", back_populates="order", primaryjoin="Order.id == foreign(LineItem.order_id)")
​
​
line_items = []
for lid in line_item_data:
    line_item = LineItem(**lid)
    line_items.append(line_item)
​
order = Order(
    ....
    line_items=line_items,
    order_tags=[OrderTag(value="foobar"),
)
session.add(order)
session.commit()
​
In [14]: order.line_items
[]
​
In [15]: LineItem.query().filter(LineItem.order_id == None).all()
Out[15]: 
[<LineItem id:307280084, partner_line_item_id:4, account_id:48, order_number:None, order_id:None, ...>]

Это работает, если я вместо этого сделаю следующее:

order = Order(...)
session.add(order)
session.commit()

line_items = []
for lid in line_item_data:
  line_items.append(LineItem(**lid)
order.line_items.extend(line_items)
session.commit()

order.order_tags.extend([OrderTag(value='foobar')])
session.commit()

...