首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何正确使用SQLAlchemy的“@aggregated”类属性装饰器

如何正确使用SQLAlchemy的“@aggregated”类属性装饰器
EN

Stack Overflow用户
提问于 2017-07-11 11:26:28
回答 2查看 893关注 0票数 0

我正在尝试使用SQLAlchemy的@aggregated装饰器为Receipt类定义一个属性('gross_amount)‘。此gross_amount属性是通过外部id与Item实例关联的所有Receipt实例的Item.gross_amount总和。

也就是说,收据是由项目组成的,我想定义一个收据'gross_amount‘值,它就是收据上所有项目的总和$。

我根据这个文档http://sqlalchemy-utils.readthedocs.io/en/latest/aggregates.html对代码进行了建模

所以看起来像这样..。

代码语言:javascript
复制
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表中定义这一列时,每当我对数据库执行一个SQLAlchemy时,我就会得到一个SELECT错误:

ProgrammingError: (psycopg2.ProgrammingError) column receipts.gross_amount does not exist

仅供参考,我的SQLAlchemy包是通过PIP分发的最新版本。

代码语言:javascript
复制
SQLAlchemy==1.1.11
SQLAlchemy-Utils==0.32.14

我现在运行的本地数据库是PostgreSQL 9.6.2

我在这里做错了什么?任何病人的帮助都将不胜感激!

EN

回答 2

Stack Overflow用户

发布于 2018-01-27 00:53:02

是的,您确实需要将列添加到表中:

代码语言:javascript
复制
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)
);

使用此自包含的代码片段进行测试:

代码语言:javascript
复制
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的方法,它基本上允许您同时执行orm级和数据库级查询,而无需在数据库中添加额外的列:

代码语言:javascript
复制
@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')
票数 0
EN

Stack Overflow用户

发布于 2018-01-26 20:26:29

出现此错误的原因是您添加的新列(gross_amount)尚未在数据库的receipts表中创建。

这意味着,您当前的数据库表只有一个已创建的列(id)。要使聚合列正常工作,它需要包含一个名为gross_amount的附加列。

此附加列必须允许null值。

其中一种方法是直接在PostgreSQL中使用SQL:

代码语言:javascript
复制
ALTER TABLE receipts ADD gross_amount int;

或者,如果还没有数据,可以通过SQLAlchemy删除并重新创建表。它应该会自动创建这个额外的列。

我不知道你说的最后一部分是什么意思:

当我在receipts表中定义此列时,任何实例的任何Receipt.gross_amount都只是指向receipts表中定义的gross_amount值。

这就是它应该指向的地方。我不知道你这么说是什么意思。您的意思是,即使此收据的项目在Item中有值,它也不包含任何值?如果是这样的话,我会仔细检查是否是这种情况(并且根据their examples here,在看到结果之前刷新数据库会话)。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45024854

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档