Самореференциальная связь с внешним ключом в декларативном классе mixin SQLAlchemy с Объявленный_аттр - PullRequest
0 голосов
/ 05 июня 2018

У меня есть класс mixin, который я определяю в начале приложения SQLAlchemy, а затем наследую почти от каждой декларативной модели, которую я использую.

class Owned(object):

    @declared_attr
    def created_by_id(cls):
        return Column(Integer, ForeignKey("accounts.id"),
            nullable = True)

    @declared_attr
    def created_by(cls):
        return relationship("Account", foreign_keys = cls.created_by_id)

    @declared_attr
    def updated_by_id(cls):
        return Column(Integer, ForeignKey("accounts.id"),
            nullable = True)

    @declared_attr
    def updated_by(cls):
        return relationship("Account", foreign_keys = cls.updated_by_id)

Это хорошо работает для большинства предполагаемых вариантов использования.

class Thing(Owned, Base): # Base is from SQLAlchemy's declarative_base()
    pass

account = session.query(Account).first()

thing = Thing(created_by = account, updated_by = account)

session.add(thing)
session.commit()
session.refresh(thing)

assert thing.created_by == account # pass
assert thing.updated_by == account # pass

Тем не менее, я получаю неожиданное поведение, когда определяю Account как наследовавшееся от Owned.

class Account(Owned, Base):
    pass

account_old = session.query(Account).first()

account_new = Account(created_by = account_old, updated_by = account_old)

session.add(account_new)
session.commit()
session.refresh(account_new)

assert account_new.created_by_id == account_old.id # pass
assert account_new.updated_by_id == account_old.id # pass

# BUT!

assert account_new.created_by == account_old # fail
assert account_new.updated_by == account_old # fail

account_new.created_by # []
account_new.updated_by # []

Я вижу, что в этом случае мне исполнилось created_by_id и updated_by_id в самостоятельные внешние ключи.Однако я не понимаю, почему SQLAlchemy не заполняет связанные столбцы relationship ожидаемыми Account экземплярами.

Что я делаю не так?

1 Ответ

0 голосов
/ 05 июня 2018

В отношении списка смежности"направление" по умолчанию принимается равным один ко многим.Использование директивы remote_side устанавливает, что отношение «многие к одному», то, что вы ищете:

def _create_relationship(cls, foreign_keys):
    kwgs = {}
    # Bit of a chicken or egg situation:
    if cls.__name__ == "Account":
        kwgs["remote_side"] = [cls.id]

    return relationship("Account", foreign_keys=foreign_keys, **kwgs)


class Owned:

    @declared_attr
    def created_by_id(cls):
        return Column(Integer, ForeignKey("accounts.id"),
            nullable = True)

    @declared_attr
    def created_by(cls):
        return _create_relationship(cls, cls.created_by_id)

    @declared_attr
    def updated_by_id(cls):
        return Column(Integer, ForeignKey("accounts.id"),
            nullable = True)

    @declared_attr
    def updated_by(cls):
        return _create_relationship(cls, cls.updated_by_id)
...