Как класс SQLAlchemy может наследовать должным образом, несмотря на сложные отношения ForeignKey? - PullRequest
0 голосов
/ 05 декабря 2011

Я реализовал наследование объединенной таблицы, как описано в вопросе Наследование SQLAlchemy .

Существует следующая ситуация: Я хотел бы иметь

  • Пользователь , который имеет emailaddress
  • Псевдоним , который присваивает псевдоним - emailaddress другому адресу электронной почты

Чтобы сохранитьemailaddress уникально, идея заключается в том, чтобы оба класса наследовали от Emailaddress, используя наследование объединенной таблицы .В примерах реализованы следующие классы:

  • Emailaddress
  • EmailaddressUser(Emailaddress)
  • EmailaddressAlias(Emailaddress)

Наследование позволяетследующее использование:

u = EmailaddressUser(name="Testuser", emailaddress="testuser@test.com")

=> Мне не нужно создавать экземпляр Emailaddress заранее - это облегчает использование.

К сожалению, то же самое не работает для EmailaddressAlias, хотя единственное отличие - это второй атрибут ForeignKey с тем же атрибутом emailaddress.Поэтому мне нужно указать attribute_concept .НО:

  a = EmailaddressAlias (
      real_emailaddress="testuser@test.com",
      alias_emailaddress="tu@test.com"
      )

-> Выдает ошибку IntegrityError при добавлении его в базу данных.Смотрите полный пример здесь:

import sqlalchemy as sa
import sqlalchemy.orm as orm
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Emailaddress(Base):
  __tablename__ = 'emailaddresses'
  emailaddress = sa.Column(sa.String, primary_key=True)
  emailtype = sa.Column(sa.String, nullable=False)
  __mapper_args__ = {'polymorphic_on': emailtype}


class EmailaddressUser(Emailaddress):
  __tablename__ = 'emailaddress_users'
  __mapper_args__ = {'polymorphic_identity': 'user'}
  emailaddress = sa.Column(
      sa.String,
      sa.ForeignKey('emailaddresses.emailaddress'),
      primary_key=True)
  name = sa.Column(sa.String, nullable=False)


class EmailaddressAlias(Emailaddress):
  __tablename__ = 'emailaddresses_alias'
  alias_emailaddress = sa.Column(
      sa.String,
      sa.ForeignKey('emailaddresses.emailaddress'),
      primary_key=True)
  real_emailaddress = sa.Column(
      sa.ForeignKey('emailaddresses.emailaddress'),
      nullable=False)
  __mapper_args__ = {
      'polymorphic_identity': 'alias',
      'inherit_condition':Emailaddress.emailaddress==alias_emailaddress}


if __name__ == '__main__':
  engine = sa.create_engine ('sqlite:///email.sqlite', echo=True)
  Base.metadata.bind = engine
  Base.metadata.create_all ()
  Session = orm.sessionmaker (engine)
  session = Session ()
  # add user (works):
  u = EmailaddressUser(name="Testuser", emailaddress="testuser@test.com")
  session.add(u)
  session.commit()
  # --> INSERT INTO emailaddresses (emailaddress, emailtype) VALUES (?, ?)
  # --> ('testuser@test.com', 'user')
  # 'emailaddress' is inserted correctly

  # add alias (throws an IntegrityError):
  a = EmailaddressAlias (
      real_emailaddress="testuser@test.com",
      alias_emailaddress="tu@test.com"
      )
  session.add(a)
  session.commit()
  # --> INSERT INTO emailaddresses (emailtype) VALUES (?)' ('alias',)
  # 'emailaddress' is missing! => IntegrityError

1 Ответ

2 голосов
/ 06 декабря 2011

Возможно, проблема в том, что EmailaddressAlias ​​наследуется от EmailAddress, а не от Base.

Я не эксперт в этом, и я не делал этого через mapper_args, но я обнаружил, что использование relations () для настройки внешних ключей работает довольно хорошо. Например:

from sqlalchemy.orm import relationship
class EmailaddressAlias(Base):
...
    alias_emailaddress_fk = sa.Column(sa.String, sa.ForeignKey('emailaddresses.emailaddress'))
    alias_emailaddress = relationship(EmailAddress, primaryjoin=alias_emaladdress_fk==EmailAddress.emailaddress)
    real_emailaddress_fk = sa.Column(sa.String, ForeignKey('emailaddresses.emailaddress'))
    real_emailaddress = relationship(EmailAddress,primaryjoin=real_emailaddress_fk==EmailAddress.emailaddress)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...