SQLAlchemy 声明式具体自动加载表继承
我已经有一个现有的数据库,并且想使用 SQLAlchemy 访问它。因为,数据库结构由另一段代码(实际上是 Django ORM)管理,并且我不想重复自己描述每个表结构,我正在使用 autoload
内省。我坚持简单的具体表继承。
Payment FooPayment
+ id (PK) <----FK------+ payment_ptr_id (PK)
+ user_id + foo
+ amount
+ date
下面是代码,其中表 SQL 描述作为文档字符串:
class Payment(Base):
"""
CREATE TABLE payments(
id serial NOT NULL,
user_id integer NOT NULL,
amount numeric(11,2) NOT NULL,
date timestamp with time zone NOT NULL,
CONSTRAINT payment_pkey PRIMARY KEY (id),
CONSTRAINT payment_user_id_fkey FOREIGN KEY (user_id)
REFERENCES users (id) MATCH SIMPLE)
"""
__tablename__ = 'payments'
__table_args__ = {'autoload': True}
# user = relation(User)
class FooPayment(Payment):
"""
CREATE TABLE payments_foo(
payment_ptr_id integer NOT NULL,
foo integer NOT NULL,
CONSTRAINT payments_foo_pkey PRIMARY KEY (payment_ptr_id),
CONSTRAINT payments_foo_payment_ptr_id_fkey
FOREIGN KEY (payment_ptr_id)
REFERENCES payments (id) MATCH SIMPLE)
"""
__tablename__ = 'payments_foo'
__table_args__ = {'autoload': True}
__mapper_args__ = {'concrete': True}
实际的表有附加列,但这与问题完全无关,因此为了尽量减少代码,我将所有内容简化到了核心。
问题是,当我运行此命令时:
payment = session.query(FooPayment).filter(Payment.amount >= 200.0).first()
print payment.date
生成的 SQL 毫无意义(注意缺少连接条件):
SELECT payments_foo.payment_ptr_id AS payments_foo_payment_ptr_id,
... /* More `payments_foo' columns and NO columns from `payments' */
FROM payments_foo, payments
WHERE payments.amount >= 200.0 LIMIT 1 OFFSET 0
当我尝试访问 payment.date 时,出现以下错误:
Concrete Mapper|FooPayment| payments_foo 未在实例级别实现属性 u'date'。
我尝试添加隐式外键引用 id = Column(' payment_ptr_id', Integer,foreignKey(' payments_ payment. id'), Primary_key=True)
到 FooPayment
没有任何成功。尝试 print session.query(Payment).first().user
可以完美工作(我省略了 User
类并注释了该行),因此 FK 内省有效。
如何对 FooPayment
执行简单查询并从结果实例中访问 Payment
的值?
我正在使用 SQLAlchemy 0.5.3、PostgreSQL 8.3、psycopg2 和 Python 2.5.2。 感谢您的任何建议。
I've an already existing database and want to access it using SQLAlchemy. Because, the database structure's managed by another piece of code (Django ORM, actually) and I don't want to repeat myself, describing every table structure, I'm using autoload
introspection. I'm stuck with a simple concrete table inheritance.
Payment FooPayment
+ id (PK) <----FK------+ payment_ptr_id (PK)
+ user_id + foo
+ amount
+ date
Here is the code, with table SQL descritions as docstrings:
class Payment(Base):
"""
CREATE TABLE payments(
id serial NOT NULL,
user_id integer NOT NULL,
amount numeric(11,2) NOT NULL,
date timestamp with time zone NOT NULL,
CONSTRAINT payment_pkey PRIMARY KEY (id),
CONSTRAINT payment_user_id_fkey FOREIGN KEY (user_id)
REFERENCES users (id) MATCH SIMPLE)
"""
__tablename__ = 'payments'
__table_args__ = {'autoload': True}
# user = relation(User)
class FooPayment(Payment):
"""
CREATE TABLE payments_foo(
payment_ptr_id integer NOT NULL,
foo integer NOT NULL,
CONSTRAINT payments_foo_pkey PRIMARY KEY (payment_ptr_id),
CONSTRAINT payments_foo_payment_ptr_id_fkey
FOREIGN KEY (payment_ptr_id)
REFERENCES payments (id) MATCH SIMPLE)
"""
__tablename__ = 'payments_foo'
__table_args__ = {'autoload': True}
__mapper_args__ = {'concrete': True}
The actual tables have additional columns, but this is completely irrelevant to the question, so in attempt to minimize the code I've simplified everything just to the core.
The problem is, when I run this:
payment = session.query(FooPayment).filter(Payment.amount >= 200.0).first()
print payment.date
The resulting SQL is meaningless (note the lack of join condidion):
SELECT payments_foo.payment_ptr_id AS payments_foo_payment_ptr_id,
... /* More `payments_foo' columns and NO columns from `payments' */
FROM payments_foo, payments
WHERE payments.amount >= 200.0 LIMIT 1 OFFSET 0
And when I'm trying to access payment.date
I get the following error: Concrete Mapper|FooPayment|payments_foo does not implement attribute u'date' at the instance level.
I've tried adding implicit foreign key reference id = Column('payment_ptr_id', Integer, ForeignKey('payments_payment.id'), primary_key=True)
to FooPayment
without any success. Trying print session.query(Payment).first().user
works (I've omited User
class and commented the line) perfectly, so FK introspection works.
How can I perform a simple query on FooPayment
and access Payment
's values from resulting instance?
I'm using SQLAlchemy 0.5.3, PostgreSQL 8.3, psycopg2 and Python 2.5.2.
Thanks for any suggestions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的表结构与联合表继承中使用的类似,但它们肯定不对应于具体的表继承,其中父类的所有字段都在子类的表中重复。现在,您有一个子类,其字段少于父类,并且具有对父类实例的引用。切换到联合表继承(并在您的条件中使用
FooPayment.amount
或放弃继承以支持简单聚合(参考)。按其他模型中的字段过滤不会自动添加联接条件。尽管对于您的示例来说,在 join 中应该使用什么条件是显而易见的,但通常无法确定这种条件,这就是为什么您必须定义引用 Payment 的关系属性并在中使用其
has()
方法。过滤以获得正确的连接条件。Your table structures are similar to what is used in joint table inheritance, but they certainly don't correspond to concrete table inheritance where all fields of parent class are duplicated in the table of subclass. Right now you have a subclass with less fields than parent and a reference to instance of parent class. Switch to joint table inheritance (and use
FooPayment.amount
in your condition or give up with inheritance in favor of simple aggregation (reference).Filter by a field in other model doesn't automatically add join condition. Although it's obvious what condition should be used in join for your example, it's not possible to determine such condition in general. That's why you have to define relation property referring to Payment and use its
has()
method in filter to get proper join condition.