2017-07-11 62 views
0

我想使用SQLAlchemy的@aggregated裝飾器爲類Receipt定義屬性('gross_amount)'。該gross_amount屬性是所有與Receipt實例關聯的Item實例的Item.gross_amount與外部ID的總和。如何正確使用SQLAlchemy的'@aggregated'類屬性修飾器

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表本專欄中,我得到一個SQLAlchemy的錯誤,每當我執行SELECT對數據庫:

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

上午什麼我在這裏做錯了嗎?任何病人的幫助將不勝感激!

回答

-1

您收到此錯誤的原因是因爲您添加的新列(gross_amount)尚未在數據庫的receipts表中創建。

含義,您當前的數據庫表只有一個創建的列(id)。要使聚合列工作,它需要包含一個名爲gross_amount的附加列。

此附加列必須允許null值。

一到去這樣做的方法就是通過SQL直接在PostgreSQL的:

ALTER TABLE receipts ADD gross_amount int; 

或者,如果有沒有數據,也可以刪除並通過SQLAlchemy中重新創建表。它應該自動創建這個額外的列。

我不知道你所說的最後部分意思:

當我定義的收入表此列,任何 Receipt.gross_amount任何情況下只是指向gross_amount 值定義在收據表中。

這就是它應該指向的地方。我不確定你的意思。你的意思是它沒有包含任何值,即使Item中有這個收據項目的值?如果是這樣,我會仔細檢查是否是這種情況(並且根據their examples here,在查看結果之前刷新數據庫會話)。

+0

這不提供問題的答案。一旦你有足夠的[聲譽](https://stackoverflow.com/help/whats-reputation),你將可以[對任何帖子發表評論](https://stackoverflow.com/help/privileges/comment);相反,[提供不需要提問者澄清的答案](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-c​​an- I-DO-代替)。 - [來自評論](/ review/low-quality-posts/18633934) – thewaywewere

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另一種方法,其基本上可以讓您在不添加額外列的情況下執行orm和數據庫級查詢:

@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')