我正在尝试使用SQLAlchemy的@aggregated装饰器为类(Receipt)定义属性('gross_amount)'。此gross_amount
属性是外部ID与Item.gross_amount
实例关联的所有Item
实例的Receipt
的总和。
I.E。,收据由物品组成,我想定义一个收据'gross_amount'值,它只是收据上所有物品的总金额。
我已在此文档http://sqlalchemy-utils.readthedocs.io/en/latest/aggregates.html
所以它看起来像这样......
from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.sql import func
from sqlalchemy import orm
class Receipt(Base):
__tablename__ = "receipts"
__table_args__ = {'extend_existing': True}
id = Column(Integer, index = True, primary_key = True, nullable = False)
@aggregated('itemz', Column(Integer))
def gross_amount(self):
return func.sum(Item.gross_amount)
itemz = orm.relationship(
'Item',
backref='receipts'
)
class Item(Base):
__tablename__ = "items"
id = Column(Integer, index = True, primary_key = True, nullable = False)
'''
FE relevant
'''
gross_amount = Column(Integer)
receipt_id = Column(Integer, ForeignKey("receipts.id"), nullable=False)
在我的迁移中,我应该在receipts
表中找到gross_amount
的列吗?
1)当我在receipts
表中定义此列时,任何实例的任何Receipt.gross_amount
都指向receipts
表中定义的gross_amount值。
2)当我不在receipts
表中定义此列时,每当我对数据库执行SELECT
时,我都会收到SQLAlchemy错误:
ProgrammingError: (psycopg2.ProgrammingError) column receipts.gross_amount does not exist
FWIW,我的SQLAlchemy
包是最新通过PIP分发的...
SQLAlchemy==1.1.11
SQLAlchemy-Utils==0.32.14
我现在运行此操作的本地数据库是PostgreSQL 9.6.2
我在这里做错了什么?非常感谢任何患者的帮助!
答案 0 :(得分:0)
是的,您需要将列添加到表中:
CREATE TABLE receipts (
id INTEGER NOT NULL,
gross_amount INTEGER, -- <<< See, it's here :)
PRIMARY KEY (id)
);
INSERT INTO receipts VALUES(1,7);
INSERT INTO receipts VALUES(2,7);
CREATE TABLE items (
id INTEGER NOT NULL,
gross_amount INTEGER,
receipt_id INTEGER NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY(receipt_id) REFERENCES receipts (id)
);
使用此自包含代码段进行测试:
from sqlalchemy import Column, Integer, ForeignKey, create_engine, orm
from sqlalchemy.orm import sessionmaker
from sqlalchemy.sql import func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy_utils import aggregated
Base = declarative_base()
class Receipt(Base):
__tablename__ = "receipts"
__table_args__ = {'extend_existing': True}
id = Column(Integer, index = True, primary_key = True, nullable = False)
@aggregated('itemz', Column(Integer))
def gross_amount(self):
return func.sum(Item.gross_amount)
itemz = orm.relationship('Item', backref='receipts')
class Item(Base):
__tablename__ = "items"
id = Column(Integer, index = True, primary_key = True, nullable = False)
gross_amount = Column(Integer)
receipt_id = Column(Integer, ForeignKey("receipts.id"), nullable=False)
def __init__(self, amount):
self.gross_amount=amount
engine = create_engine('sqlite:///xxx.db', echo=True)
Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)()
receipt = Receipt()
receipt.itemz.append(Item(5))
receipt.itemz.append(Item(2))
session.add(receipt)
session.commit()
print (receipt.gross_amount)
当然,还有另一种称为hybrid_property
的方法,它基本上允许您在不添加额外列的情况下执行数据库级和数据库级查询:
@hybrid_property
def gross_sum(self):
return sum(i.gross_amount for i in self.itemz)
@gross_sum.expression
def gross_sum(cls):
return select([func.sum(Item.gross_amount)]).\
where(Item.receipt_id==cls.id).\
label('gross_sum')
答案 1 :(得分:-1)
您收到此错误的原因是您尚未在数据库的gross_amount
表中创建新添加的列(receipts
)。
意思是,您当前的数据库表只有一个已创建的列(id
)。要使聚合列起作用,它需要包含一个名为gross_amount
的其他列。
此附加列必须允许null
值。
这样做的一种方法是直接在PostgreSQL中使用SQL:
ALTER TABLE receipts ADD gross_amount int;
或者,如果还没有数据,您可以通过SQLAlchemy删除并重新创建表。它应该自动创建这个额外的列。
我不确定你最后一部分是什么意思:
当我在收据表中定义此列时,任何 任何实例的Receipt.gross_amount只指向gross_amount 收据表中定义的值。
它应该指向的地方。我不确定你的意思。您的意思是它不包含任何值,即使Item
中的收据项有值吗?如果是这样,我会仔细检查是否是这种情况(并且根据their examples here,在查看结果之前刷新数据库会话。)