繁体   English   中英

如果在 SQLAlchemy 中将“子”对象分配给“关系”,如何在“父”对象上设置属性?

[英]How can I set attributes on a "parent" object if a "child" object is assigned to a "relation" in SQLAlchemy?

当我有两个对象与 SQLAlchemy 中的“关系”相关联时,我意识到仅分配该关系不足以将值传播到另一个对象。 例如(见下文),如果我有一个“用户”表和一个“联系人”表(两者都是高度人为的,但很好地证明了问题),并且一个“用户”可以有多个“联系人”。 在这种情况下,我将在用户和联系人之间使用外键。 如果我创建的两个实例User ,并Contact到后来的用户分配的接触,我希望在FK的属性进行更新(即使没有DB齐平),但事实并非如此。 为什么? 我如何告诉 SA 自动执行此操作?

这将是我期望的工作,但正如您在下面的完整示例中看到的那样,它没有:

user = User(name='a', lname='b')
contact(type='email', value='foo@bar.com')
contact.user = user
assert contact.username == 'a'  # <-- Fails because the attribute is still `None`

完整的可运行示例:

"""
This code example shows two tables related to each other by a composite key,
using an SQLAlchemy "relation" to allow easy access to related items.

However, as the last few lines show, simply assigning an object A to the
relation of object B does not update the attributes of object B until at least
a "flush" is called.
"""
from sqlalchemy import Column, ForeignKeyConstraint, Unicode, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relation, sessionmaker

Base = declarative_base()

class User(Base):
    __tablename__ = "user"

    name = Column(Unicode, primary_key=True)
    lname = Column(Unicode, primary_key=True)


class Contact(Base):
    __tablename__ = "contact"
    __table_args__ = (
        ForeignKeyConstraint(
            ['username', 'userlname'],
            ['user.name', 'user.lname']
        ),
    )

    username = Column(Unicode, primary_key=True)
    userlname = Column(Unicode, primary_key=True)
    type = Column(Unicode)
    value = Column(Unicode)

    user = relation(User)


engine = create_engine('sqlite://')
Base.metadata.create_all(engine)

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

user = User(name="John", lname="Doe")
contact = Contact(type='email', value='john.doe@example.com')
contact.user = user  # <-- How can I tell SA to set the FKs on *contact* here?
session.add(contact)

print('Before flush: contact.username user=%r' % contact.username)
session.flush()
print('After flush : contact.username user=%r' % contact.username)

根据这个答案 - https://stackoverflow.com/a/52911047/4981223这是不可能的:

直到您显式或通过 commit() 发出 flush() 后,子对象的 FK 才会更新。 我认为这样做的原因是,如果关系的父对象也是一个带有自增 PK 的新实例,SQLAlchemy 需要从数据库中获取 PK,然后才能更新子对象上的 FK(但我支持待纠正!)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM