我已经存在一个数据库,想要使用SQLAlchemy访问它。因为,数据库结构由另一段代码(实际上是Django ORM)管理而且我不想重复自己,描述每个表结构,我正在使用autoload
内省。我坚持使用简单的具体表继承。
Payment FooPayment
+ id (PK) <----FK------+ payment_ptr_id (PK)
+ user_id + foo
+ amount
+ date
这是代码,表SQL描述为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}
实际的表有额外的列,但这与问题完全无关,因此在尝试最小化代码时,我将所有内容简化为核心。
问题是,当我运行时:
payment = session.query(FooPayment).filter(Payment.amount >= 200.0).first()
print payment.date
生成的SQL没有意义(注意缺少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
当我尝试访问payment.date
时,我收到以下错误:Concrete Mapper|FooPayment|payments_foo does not implement attribute u'date' at the instance level.
我尝试将隐式外键引用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。 感谢您的任何建议。
答案 0 :(得分:4)
您的表结构类似于联合表继承中使用的表结构,但它们肯定不对应于具体的表继承,其中父类的所有字段都在子类表中重复。现在你有一个子类,其字段少于父类,并且引用了父类的实例。切换到联合表继承(并在您的条件中使用FooPayment.amount
或放弃继承以支持简单聚合(引用)。
按其他模型中的字段过滤不会自动添加连接条件。虽然显然应该在连接中使用什么条件作为示例,但通常无法确定此类条件。这就是为什么你必须定义引用Payment的关系属性并在filter中使用它的has()
方法来获得正确的连接条件。