【问题标题】:Inheritance + Foreign Keys继承+外键
【发布时间】:2012-06-09 19:34:53
【问题描述】:

我一直在为此绞尽脑汁,似乎无法弄清楚如何解决这个问题。请注意,我从模型中删除了很多不相关的字段

我正在编写我的 SQL-Alchemy 模型,遇到了以下问题:

由于多个计费系统,每个系统具有完全不同的属性,并且由于订阅属性的类型不同(即用户名、节点位置等),我不得不走多态继承之路。

class Subscription(Base):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    secret = db.Column(postgresql.BYTEA)
    type = db.Column(SubscriptionType.db_type())
    status = db.Column(StatusType.db_type())
    subscription_id = db.Column(db.Integer)

    __tablename__ = 'subscription'
    __table_args__ = {'schema':'public'}

    __mapper_args__ = {'polymorphic_on' : type}

    def __repr__(self):
        return '<Subscription: %r>' % self.id

class Product1(Subscription):
    __mapper_args__ = {'polymorphic_identity' : SubscriptionType.product1}    
    id = db.Column(db.Integer, db.ForeignKey('public.subscription.id'), 
        primary_key = True)
    billing_system = db.Column(
        db.Integer, 
        db.ForeignKey('public.billing_system.id')
    )

class BillingSystem(Base):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    type = db.Column(BillingSystemType.db_type())

    __tablename__ = 'billing_system'
    __table_args__ = {'schema':'public'}

    __mapper_args__ = {'polymorphic_on' : type}

    def __repr__(self):
        return '<Subscription: %r>' % self.id

class BillingSystem1(BillingSystem):
    __mapper_args__ = {'polymorphic_identity' : BillingSystemType.billingsystem1}    
    id = db.Column(db.Integer, db.ForeignKey('public.billing_system.id'), 
        primary_key = True)
    billing_system = db.Column(
        db.Integer, 
        db.ForeignKey('public.billing_system.id')
    )
    foo = db.Column(db.Integer)
    bar = db.Column(db.Integer)

 class BillingSystem2(BillingSystem):
    __mapper_args__ = {'polymorphic_identity' : BillingSystemType.billingsystem2}    
    id = db.Column(db.Integer, db.ForeignKey('public.billing_system.id'), 
        primary_key = True)
    billing_system = db.Column(
        db.Integer, 
        db.ForeignKey('public.billing_system.id')
    )
    bing = db.Column(db.Integer)
    boo = db.Column(db.Integer)


    __tablename__ = 'billing_system_product2'
    __table_args__ = {'schema':'public'}

一切正常,除了一件事。

假设我运行以下命令:

>>> a = Product1()
>>> b = BillingSystem.objects.get(1)
>>> a.billing_system = b
>>> session.add(a)
>>> session.commit()

我会收到以下错误。

sqlalchemy.exc.ProgrammingError: (ProgrammingError) can't adapt type 'BillingSystem1' 'INSERT INTO

我明白它在说什么,我已经尝试了以下方法。

>>> a.billing_system = b.id

这仅存储 ID,当我尝试检索关联对象时,我会收到一个整数。这涉及到我必须做一个额外的查询。我希望这不是要走的路。

我还尝试将所有计费系统 ID 的外键添加到 Product1 模型

class BillingSystem1(BillingSystem):
    __mapper_args__ = {'polymorphic_identity' : BillingSystemType.billingsystem1}    
    id = db.Column(db.Integer, db.ForeignKey('public.billing_system.id'), 
        primary_key = True)
    billing_system = db.Column(
        db.Integer, 
        db.ForeignKey('public.billing_system.id'),
        db.ForeignKey('public.billing_system1.id'),
        db.ForeignKey('public.billing_system2.id'),
    )
    foo = db.Column(db.Integer)
    bar = db.Column(db.Integer)

这也根本不起作用,我收到了同样的 ProgrammingError 异常,指出类型无法适应。

我翻遍了手册,但找不到操作方法,但我需要某种形式的神奇选项来让这种情况发生:

>>> a = BillingSystem.query.get(1)
>>> type(a)
BillingSystem

代替:

>>> a = BillingSystem.query.get(1)
>>> type(a)
BillingSystem1

是否有人能够阐明如何查询我的多态模型集以获取 ID,并且只获取基本模型的类?

我觉得这会解决我的问题,我只是不知道如何解决。

感谢您抽出宝贵时间阅读本文,我真的很想找出我哪里出错了(我也醒得太久了,所以这没有帮助)。

干杯, 里斯

【问题讨论】:

  • 这对您来说可能不会是一个超级有用的答案,但似乎为了确定我是否可以帮助您,我将不得不阅读大量您的代码并找出一些小细节。在这个网站上获得答案的最好方法是减少代码,直到它非常简单但仍然给出同样的错误。那你可以问一个很具体的问题:“为什么这4行代码的第3行会报错?”作为额外的奖励,当您完成此过程时,您通常实际上解决了问题。祝你好运!
  • 休息一下,您的建议很有帮助!谢谢你:)

标签: python sql sqlalchemy flask flask-sqlalchemy


【解决方案1】:
class Subscription(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    secret = db.Column(postgresql.BYTEA)
    type = db.Column(SubscriptionType.db_type())
    status = db.Column(StatusType.db_type())
    subscription_id = db.Column(db.Integer)

    billing_system_id = db.Column(
        db.Integer, 
        db.ForeignKey('public.billing_system.id')
    )
    billing_system = db.relationship('BillingSystem', backref='subscriptions')

所以我所做的是:

1 ) 将 Subscription.billing_system_id 外键移至基本订阅模型 2 ) 添加在 Subscription.billing_system 关系中

所以现在我正在这样做:

>>> o = BillingSystem.query.get(1)
>>> a = Product1()
>>> a.billing_system_id = o.id

结果:

>>> a.billing_system.subscriptions
[<cPanel Hosting Reseller: 2>]
>>> a.billing_system_id
2

因此,除非我在这里做错了什么,否则它似乎有效。我只是无法传递实际的 BillingSystem 对象,我实际上必须设置 ID。虽然保存模型时它仍然是参考强制执行的,所以我看不出有太多问题。

感谢您的帮助:)

【讨论】:

    猜你喜欢
    • 2013-08-14
    • 2012-01-18
    • 1970-01-01
    • 2010-11-10
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多