gpt4 book ai didi

python - SQLAlchemy 声明性语法中具有抽象基的多态多对多关系

转载 作者:太空宇宙 更新时间:2023-11-03 16:39:06 27 4
gpt4 key购买 nike

我正在创建一个具有多对多关系的 SQLAlchemy 声明性模型,其中一个表是具体的,另一个表是具有抽象基础的多态性。

用例:我正在发送包含多个组件(组件1、组件2)的消息,并且每个组件具有非常不同的属性集(因此每个组件都有自己的数据库表)。一个组件可以在多个不同的消息中发送。

我希望 Message 类和名为 Component 的抽象父类之间存在 M:N 关系 - 但数据库不应包含任何抽象“组件”表,而应仅包含具体表子级(“组件 1”、“组件 2”等)。

我尝试组合 abstract 1:N relation using AbstractConcreteBase (参见本章最后/第三个代码片段) regular M:N relation写入以下代码,无法找到抽象基类的表名称:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base, AbstractConcreteBase

BaseModel = declarative_base()

association = Table("message_component_association", BaseModel.metadata,
Column("message_id", Integer, ForeignKey("message.id")),
Column("component_id", Integer, ForeignKey("component.id"))) # Fails to reference the Component class

class Message(BaseModel):
__tablename__ = "message"
id = Column(Integer, primary_key=True)
components = relationship("Component", secondary=association, back_populates="messages")

class Component(AbstractConcreteBase, BaseModel):
__mapper_args__ = dict(polymorphic_identity="component", concrete=False) # This seems to be ignored

class Component1(Component):
__tablename__ = "component1"
__mapper_args__ = dict(polymorphic_identity="component1", concrete=True)
id = Column(Integer, primary_key=True)
messages = relationship("Message", secondary=association, back_populates="components")

engine = create_engine("sqlite://")
BaseModel.metadata.create_all(engine)

异常说:

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'message_component_association.component_id' could not find table 'component' with which to generate a foreign key to target column 'id'

为什么 Component 类的 ma​​pper_args 被忽略,并且无法通过提供的 polymorphic_identity 找到该类?

编辑:我意识到我可以使用连接表继承(grr,我不能发布超过 2 个链接),它用显式鉴别器替换声明性帮助器 mixin 以获得多态 M:N 关系- 但是,基类需要自己的数据库表

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

BaseModel = declarative_base()

association = Table("message_component_association", BaseModel.metadata,
Column("message_id", Integer, ForeignKey("message.id")),
Column("component_id", Integer, ForeignKey("component.id")))

class Message(BaseModel):
__tablename__ = "message"
id = Column(Integer, primary_key=True)
components = relationship("Component", secondary=association, back_populates="messages")

class Component(BaseModel): # Declarative mixin removed
__tablename__ = "component" # Requires a real DB table despite being abstract
__mapper_args__ = dict(polymorphic_identity="component", polymorphic_on="type") # Apply the discriminator
id = Column(Integer, primary_key=True)
type = Column(String(32)) # Explicit discriminator
messages = relationship("Message", secondary=association, back_populates="components")

class Component1(Component):
__tablename__ = "component1"
__mapper_args__ = dict(polymorphic_identity="component1")
id = Column(Integer, ForeignKey("component.id"), primary_key=True) # Shares the primary key sequence with the parent and with all other child classes
messages = relationship("Message", secondary=association, back_populates="components")

engine = create_engine("sqlite://", echo=True)
BaseModel.metadata.create_all(engine)
session = Session(engine)

component_1 = Component1(id=1)
session.commit()

到目前为止,代码似乎可以工作,但它提示刷新问题。只要我不手动写入“组件表”,忽略警告是否安全——或者有更好的方法吗?

SAWarning: Warning: relationship 'messages' on mapper 'Mapper|Component1|component1' supersedes the same relationship on inherited mapper 'Mapper|Component|component'; this can cause dependency issues during flush

最佳答案

解决方案:删除除 Message 类中的关系之外的所有关系,并将 back_populates 替换为 backref。 Backref 将动态创建相反的方向,并且映射器将看不到覆盖的关系。此外,抽象祖先上的 polymorphic_identity 不是必需的。

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

BaseModel = declarative_base()

association = Table("message_component_association", BaseModel.metadata,
Column("message_id", Integer, ForeignKey("message.id")),
Column("component_id", Integer, ForeignKey("component.id")))

class Message(BaseModel):
__tablename__ = "message"
id = Column(Integer, primary_key=True)
components = relationship("Component", secondary=association, backref="messages") # backref instead of back_populates

class Component(BaseModel):
__tablename__ = "component"
__mapper_args__ = dict(polymorphic_on="type") # Polymorphic identity removed
id = Column(Integer, primary_key=True)
type = Column(String(32))

# relationship removed

class Component1(Component):
__tablename__ = "component1"
__mapper_args__ = dict(polymorphic_identity="component1")
id = Column(Integer, ForeignKey("component.id"), primary_key=True)

# relationship removed

engine = create_engine("sqlite://", echo=True)
BaseModel.metadata.create_all(engine)
session = Session(engine)

component_1 = Component1(id=1)
session.commit()

关于python - SQLAlchemy 声明性语法中具有抽象基的多态多对多关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36984937/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com