Как я могу установить атрибуты для «родительского» объекта, если «дочерний» объект назначен «отношению» в SQLAlchemy? - PullRequest
2 голосов
/ 06 марта 2020

Когда у меня есть два объекта, связанных с «отношением» в SQLAlchemy, я понял, что простого присвоения этого отношения недостаточно для распространения значений на другой объект. Например (см. Ниже), если у меня есть таблица «пользователь» и таблица «контакт» (обе они очень надуманные, но хорошо демонстрируют проблему), и у «пользователя» может быть несколько «контактов». В этом случае у меня будет внешний ключ между пользователями и контактами. Если я создам оба экземпляра User и Contact и позже назначу пользователю на контакт, я бы ожидал, что атрибуты FK будут обновлены (даже без DB flu sh) но это не так. Почему? И как я могу сказать 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)

1 Ответ

2 голосов
/ 09 марта 2020

Согласно этому ответу - { ссылка } это невозможно:

FK дочернего объекта не обновляется, пока вы не выполните грипп sh ( ) либо явно, либо через commit (). Я думаю, что причина этого заключается в том, что если родительский объект отношения также является новым экземпляром с PK с автоматическим приращением, SQLAlchemy необходимо получить PK из базы данных, прежде чем он сможет обновить FK на дочернем объекте (но я стою быть исправленным!).

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