【问题标题】:Inheritance issue in SQLAlchemySQLAlchemy 中的继承问题
【发布时间】:2012-03-15 20:30:17
【问题描述】:

我需要一些帮助来理解 SQLAlchemy 中的继承是如何工作的。我为具有一些基本功能的用户创建了一个基类。然后是一些特定的用户(admin、cooluser、uncooluser)。每个都有独特的功能,所以我决定在 SQLAlchemy 中使用继承。问题是我需要能够随时将用户升级为cooluser或uncooluser,并将cooluser降级为用户。

class User(Base):
    __tablename__ = 'tbl_users'
    __table_args__ = {'mysql_engine': 'InnoDB'}

    user_id = Column(Integer, primary_key = True, unique = True, nullable = False)
    user_name = Column(String(100), nullable = False, unique = True)
    password = Column(String(100), nullable = False)
    user_type = Column('user_type', String(50))
    first_name = Column(String(50), nullable = False)
    last_name = Column(String(50), nullable = False)
    address = Column(String(50), nullable = False)
    city = Column(String(20), nullable = False)
    postal_code = Column(String(10), nullable = False)
    country_id = Column(Integer, ForeignKey(Contries.country_id))

    country = relationship('Country', backref = 'users')

    query = Session.query_property()

    __mapper_args__ = {'polymorphic_on': user_type, 'polymorphic_identity': 'User'}
class CoolUser(User):
    __tablename__ = 'tbl_cool_user'
    __table_args__ = {'mysql_engine': 'InnoDB'}
    __mapper_args__ = {'polymorphic_identity': 'CoolUser'}

    cool_user_id = Column(Integer, ForeignKey(User.user_id, ondelete = 'CASCADE'), primary_key = True)
    cool_user_balance = Column(Numeric(15, 3))

我可以创建 CoolUser 而不在 'tbl_users' 中创建新行,而是使用现有行吗?可以更改一些设置,以便当 CoolUser 被删除时,它只删除“tbl_cool_user”中的条目,而不是“tbl_user”?

我错过了 SQLAlchemy 中的继承点吗?

【问题讨论】:

    标签: python inheritance sqlalchemy


    【解决方案1】:

    我错过了 SQLAlchemy 中的继承点吗?

    我认为您总体上滥用了 inheritance 概念,甚至在 SA 实施细节中也没有。
    在经典的 Animal (Cat, Dog (Terier)) 类型的层次结构中,您是否曾想象过 Cat 会上/下为 Dog,甚至是特定类型的 Dog?我不这么认为。另外,我可以想象一些CoolUser 也可能同时是Administrator。你将如何解决这种类型的关系?

    因此,根据您的要求,继承并不是用来解决这种状态变化模型的概念。我建议谷歌搜索User-Role 类型的关系和实现。您仍然需要解决存储角色特定数据的问题。


    正如@aquavitae 提到的:在SA 中,您可以修改并更改user_type。但请注意,在这种情况下会发生以下情况:

    • 当您从数据库加载对象时,其类将反映新类型 (GOOD)
    • 当您将对象降级(从 CoolUser 到 User)时,与 CoolUser 对应的行将不会被删除(我认为它很糟糕,但可能没问题)
    • 当您升级对象(从 User 到 CoolUser)时,不会为 CoolUser 表创建新行,并且您的所有值都将为 NULL。因此,设置/添加存储在未创建行中的任何属性都会引发一个很好的错误。当查询特定子类时,您将不会收到该对象,因为INNER JOIN 用于检索该对象。 (坏)
    • 总之,不要把猫变成狗

    【讨论】:

    • +1 我也应该在我的回答中加入所有这些警告!在这个用例中,最好使用过滤器简单地查询用户。
    • 谢谢。我想我将不得不重新考虑整个事情。我认为继承是子表的原因是因为每个用户(CoolUserUnCoolUserAdmin)都必须登录、注销等。但我想我错了……
    • 我建议您为面向登录的任务创建一个单独的表(称为User),并为您拥有的数据模型创建一个层次结构(如Person (->CoolPerson, ->UncoolPerson, ->Distributor)),然后有一个外部键入Person.user_id(您甚至可以使用相同的 ID 值)。在这种情况下,Administrator 可能仍然是role(或只是User 表上的一个标志),并且仅与User 表相关,而对Person 及其后代一无所知。跨度>
    【解决方案2】:

    我认为您不应该在同一个表中使用“polymorphic_on”和“polymorphic_identity”。您需要做的是创建一个包含所有用户的基表User(即使用 mapper_args 'polymorphic_on'),然后从该表中继承CoolUser(使用'polymorphic_identity'):

    class User(Base):
        ...
        __mapper_args__ = {'polymorphic_on': user_type}
    
    class CoolUser(User):
        ...
        __mapper_args__ = {'polymorphic_identity': 'CoolUser'}
    

    然后你可以随意更改user_type

    【讨论】:

    【解决方案3】:

    你必须使用Concrete Table Inheritance。基表中的所有公共属性并创建 2 个不同的 CoolUserUnCoolUser

    【讨论】:

    • 感谢您的回复,但我仍然很困惑。如何将User 的类型更改为CoolUser?如果我创建新的CoolUser,它会在CoolUser 表中复制User 吗?
    • 请检查示例并尝试polymorphic_on。如果您遇到任何错误,请写下该错误以便我们解决。
    • 某个型号的数据库已经存在,无法更改,因为已经有其他软件连接。我试图做的是制作python代码,使其符合该模型。我将不得不重新考虑整个事情......不过我很感激你的帮助。
    猜你喜欢
    • 1970-01-01
    • 2010-11-23
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    • 2011-04-05
    • 1970-01-01
    相关资源
    最近更新 更多