Mixin 是一个将其数据复制到表中的类,但对于 SQL 而言,重要的是您是该数据(表)的所有者还是引用(外键)。
您似乎正在尝试创建既是事实来源又是参考来源的 Mixin。这在 SQL 中是不可能的。
让你的例子更进一步,像这样定义OrdersMixin会让我认为问题更加明显。
class OrdersMixin(UserMixin, ItemMixin):
id = sa.Column(sa.Integer(), primary_key=True)
例如,一旦事情解决,MyOrders 就会像这样结束。
class MyOrders(Base):
__tablename__ = 'myorders'
# This is from UserMixin
id = sa.Column(sa.Integer(), primary_key=True)
first_name = sa.Column(sa.Unicode(255))
last_name = sa.Column(sa.Unicode(255))
# This is from ItemMixin
id = sa.Column(sa.Integer(), primary_key=True)
name = sa.Column(sa.Unicode(255))
short_description = sa.Column(sa.Unicode(255))
# From OrdersMixin
id = sa.Column(sa.Integer(), primary_key=True) # This is defined last so it overrides all others with the same name.
user_id = sa.Column(sa.Integer(), sa.ForeignKey('???'))
item_id = sa.Column(sa.Integer(), sa.ForeignKey('???'))
随着您如何使用 Mixin 定义使用该 Mixin 的任何表,primary_keys 的 id 列会发生冲突。此外,您正在复制 Mixin 中的每一列,通常您希望在 SQL 中避免这种情况(请参阅Database normal form)。
最终的结果是这样的。这是一大堆列,这意味着您不需要引用任何其他表,并且您拥有的所有引用 id 都被覆盖了,这意味着您无论如何都无法加入它们。
class MyOrders(Base):
__tablename__ = 'myorders'
first_name = sa.Column(sa.Unicode(255))
last_name = sa.Column(sa.Unicode(255))
name = sa.Column(sa.Unicode(255))
short_description = sa.Column(sa.Unicode(255))
id = sa.Column(sa.Integer(), primary_key=True) # This is defined last so it overrides all others with the same name.
user_id = sa.Column(sa.Integer(), sa.ForeignKey('???'))
item_id = sa.Column(sa.Integer(), sa.ForeignKey('???'))
为了避免这种情况,我将我的 Mixins 与初始表定义分开。 IE。当我希望另一个表引用该表时,我会使用 Mixin。
以下内容接近我认为您希望实现的目标。
import sqlalchemy as sa
from sqlalchemy import orm
class UserMixin(object):
user_id = sa.Column(sa.Integer(), ForeignKey("myuser.id"), index=True)
user = orm.relationship("MyUser")
class ItemMixin(object):
item_id = sa.Column(sa.Integer(), ForeignKey("myitem.id"), index=True)
item = orm.relationship("MyItem")
class OrdersMixin(UserMixin, ItemMixin):
order_id = sa.Column(sa.Integer(), sa.ForeignKey('myorders.id'))
user_id = sa.Column(sa.Integer(), sa.ForeignKey('myorders.user_id'))
item_id = sa.Column(sa.Integer(), sa.ForeignKey('myorders.item_id'))
请注意,在 Mixins 中,我为每一列指定了一个唯一的名称,这样就不会发生冲突,在 OrdersMixin 中,即使我使用的是 UserMixin 和 ItemMixin,我正在覆盖 user_id 和 @987654335 @ 列,否则使用 OrdersMixin 的任何内容都会有指向三个不同表的外键,这会混淆自动查询生成器。但它仍然会添加user 和item 关系(因为它们被定义为MyOrders 表中原始表的外键,我认为这种关系会起作用)。
然后我会把你的桌子改成这样。
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class MyUser(Base):
__tablename__ = "myuser"
id = sa.Column(sa.Integer(),primary_key=True)
first_name = sa.Column(sa.Unicode(255))
last_name = sa.Column(sa.Unicode(255))
class MyItem(Base):
__tablename__ = "myitem"
id = sa.Column(sa.Integer(),primary_key=True)
name = sa.Column(sa.Unicode(255))
short_description = sa.Column(sa.Unicode(255))
class MyOrders(Base, UserMixin, OrdersMixin):
__tablename__ = "myorders"
id = sa.Column(sa.Integer(),primary_key=True)
原始表定义拥有单独定义它们的列(事实来源),而 Mixins(这种)很适合定义引用,因此后续引用不需要单独定义它们中的每一个。不能将 Mixin 定义为既是参考又是事实来源。鉴于此,与其像OrdersMixin 那样每次都覆盖列,不如只定义一次规范(表格)和一次作为参考(Mixin)。