SQLAlchemy Полиморфная связь с конкретным наследованием
Я использую конкретную таблицу наследования с SQLAlchemy. В классе модели склонительного стиля я настроил его успешно.
Мой код так же, как:
class Entry(AbstractConcreteBase, db.Model):
"""Base Class of Entry."""
id = db.Column(db.Integer, primary_key=True, nullable=False)
created = db.Column(db.DateTime, nullable=False)
post_id = declared_attr(lambda c: db.Column(db.ForeignKey("post.id")))
post = declared_attr(lambda c: db.relationship("Post", lazy="joined"))
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
@declared_attr
def __mapper_args__(cls):
# configurate subclasses about concrete table inheritance
return {'polymorphic_identity': cls.__name__,
'concrete': True} if cls.__name__ != "Entry" else {}
class TextEntry(Entry):
"""Text and Article Entry."""
text = db.deferred(db.Column(db.Text, nullable=False))
class PhotoEntry(Entry):
"""Photo Entry."""
path = db.deferred(db.Column(db.String(256), nullable=False))
Он отлично работает при тестировании в оболочке:
>>> from models.entry import Entry
>>>
>>> Entry.query.all()
[<PhotoEntry 'Title' created by tonyseek>,
<PhotoEntry 'TITLE 2' created by tonyseek>,
<PhotoEntry 'Title 3' created by tonyseek>,
<PhotoEntry 'Title 4' created by tonyseek>,
<TextEntry 'Title' created by tonyseek>]
Тогда я попадаю в неприятности, когда устанавливаю отношения в других моделях. Каждая запись имеет внешний ключ post_id
присоединиться Post
модель, но я не мог определить обратную ссылку в Post
, Это не может работать:
class Post(db.Model):
"""An Post."""
id = db.Column(db.Integer, primary_key=True, nullable=False)
description = db.Column(db.Unicode(140), nullable=False)
entries = db.relationship(Entry, lazy="dynamic")
Он поднял исключение и сказал:
InvalidRequestError: Не удалось инициализировать один или несколько сопоставителей - не удается продолжить инициализацию других сопоставителей. Первоначальное исключение: класс "models.entry.Entry" не сопоставлен.
Очевидный Entry
абстрактный класс, который не может быть сопоставлен с реально существующей таблицей У документа на официальном сайте есть пример, но его базовый класс не является абстрактным. Теперь, как я должен сделать, чтобы установить полиморфные отношения с абстрактной моделью?
1 ответ
Я нашел причину проблемы и ее решение.
Согласно документу официального сайта sqlalchemy, абстрактный класс может быть отображенным классом, потому что polymorphic_union
Функция может создать виртуальную таблицу.
Я использую декларативную модель стиля, а не сборщик вручную, поэтому виртуальная таблица pjoin
не должен быть создан вручную. Базовый класс AbstractConcreteBase
есть метод __delcare_last__
создаст pjoin
с polymorphic_union
функция, но она будет вызываться во время события after_configured
запуск.
Отношения с Entry
в Post
будет создан после Post
класс будет сгенерирован, в это время событие after_configured
не были запущены, так __delcare_last__
функция не создала виртуальную таблицу pjoin
и сопоставил это в Entry
, Таким образом, исключение "Класс models.entry.Entry не сопоставлен". будет поднят.
Теперь я рефакторинг Post
модель, пусть она создает отношения с Entry
в __delcare_last__
функция, то это будет успех из-за инициированного события и сопоставленного Entry
,
Мой новый реализованный класс выглядит так:
class Post(db.Model):
"""An Post."""
id = db.Column(db.Integer, primary_key=True, nullable=False)
description = db.Column(db.Unicode(140), nullable=False)
@classmethod
def __declare_last__(cls):
cls.entries = db.relationship(Entry, viewonly=True)
def attach_entries(self, entries):
"""Attach Entries To This Post.
Example:
>>> post = Post("An Interesting News", "Wow !!!")
>>> text_entry = TextEntry(*t_args)
>>> photo_entry = PhotoEntry(*p_args)
>>> post.attach_entries([text_entry, photo_entry])
>>> len(post.entries)
2
>>> db.session.commit()
>>>
"""
for entry in entries:
self.entries.append(entry)
entry.post = self
db.session.add(entry)