2014-10-08 56 views
1

我是一個嘗試將sqlalchemy與flask一起使用的noob,並且正在從基本查詢中排序結果。在sqlalchemy中外連接兩個表時按順序排序

我有一個父表和兩個加入了大量的一對多關聯表:

class Product(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    (...) 
    qty_stock = db.Column(db.Integer) 
    requested_products = db.relationship('RequestedProducts') 
    ordered_products = db.relationship('OrderedProducts') 

class OrderedProducts(db.Model): 
    __tablename__ = 'orderedproducts' 
    order_id = db.Column(db.Integer, db.ForeignKey('order.id'), primary_key=True) 
    product_id = db.Column(db.Integer, db.ForeignKey('product.id'), primary_key=True) 
    quantity = db.Column(db.Integer, default=1) 
    qty_delivered = db.Column(db.Integer, default=0) 
    product = db.relationship('Product', backref='order_assocs') 

class RequestedProducts(db.Model): 
    __tablename__ = 'requestedproducts' 
    request_id = db.Column(db.Integer, db.ForeignKey('request.id'), primary_key=True) 
    product_id = db.Column(db.Integer, db.ForeignKey('product.id'), primary_key=True) 
    quantity = db.Column(db.Integer, default=1) 
    qty_supplied = db.Column(db.Integer, default=0) 
    product = db.relationship('Product', backref='request_assocs') 

在我看來類有每個產品顯示庫存量,要求的產品的數量,數量4個表列訂購產品和淨庫存數量,這基本上是(庫存數量 - 請求+訂購)。這是淨的股票價值,我試圖讓工作查詢:

products = Product.query.filter_by(active_flg=True) 
    .filter_by(category_id=int(g.category_id)) 
    .outerjoin(Product.requested_products) 
    .outerjoin(Product.ordered_products) 
    .group_by(Product.id) 
#Count requested amount for each product 
reqs = func.coalesce((func.sum(RequestedProducts.quantity) - func.sum(RequestedProducts.qty_supplied)), 0) 
#Count ordered amount for each product 
ords = func.coalesce((func.sum(OrderedProducts.quantity) - func.sum(OrderedProducts.qty_delivered)), 0) 
result = (Product.qty_stock - reqs + ords) 
products = products.order_by(result.desc()) 

現在,功能按預期工作,唯一的問題是與ORDER_BY功能 - 順序打亂。我發現原因可能是雙外連接。有沒有人有一個想法如何處理?另外,我真的是sqlalchemy和燒瓶的初學者,所以我會非常感謝任何建議或更好的解決方案(可執行我的有限技能)。謝謝!

+0

你用什麼數據庫? – van 2014-10-09 05:03:22

+0

用於開發的Sqlite,服務器上的MySQL。排序問題發生在兩者上。 – Hinek 2014-10-09 05:42:04

+0

奇怪,我複製了你的代碼,它在'sqlite'上正常工作。在這個註釋中:你是否不想在你的視圖中看到部分和('reqs','ords'和'result')? – van 2014-10-09 06:07:55

回答

2

如果你已經真的使用混合屬性作爲局部和,那麼將它們組合起來應該很容易。

class Product(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String) 
    qty_stock = db.Column(db.Integer) 
    requested_products = db.relationship('RequestedProducts') 
    ordered_products = db.relationship('OrderedProducts') 

    @hybrid_property 
    def diff_orders(self): 
     return sum(op.quantity - op.qty_delivered 
        for op in self.ordered_products) 

    @diff_orders.expression 
    def diff_orders(cls): 
     return (db.select([db.func.coalesce(
      db.func.sum(
       db.func.coalesce(
        OrderedProducts.quantity - OrderedProducts.qty_delivered, 0) 
      ), 0)]) 
      .where(OrderedProducts.product_id == cls.id) 
      .label("diff_orders") 
     ) 

    @hybrid_property 
    def diff_requests(self): 
     return sum(op.quantity - op.qty_supplied 
        for op in self.requested_products) 

    @diff_requests.expression 
    def diff_requests(cls): 
     return (db.select([db.func.coalesce(
      db.func.sum(
       db.func.coalesce(
        RequestedProducts.quantity - RequestedProducts.qty_supplied, 0) 
      ), 0)]) 
      .where(RequestedProducts.product_id == cls.id) 
      .label("diff_requests") 
     ) 

在這種情況下,可以使用類似於:

products = db.session.query(
    Product, 
    # Product.diff_orders, 
    # Product.diff_requests, 
    # Product.qty_stock + Product.diff_requests - Product.diff_orders, 
).order_by((Product.qty_stock + Product.diff_requests - Product.diff_orders).desc()) 
for x in products: 
    print(x) 
+0

它工作!我仍然在學習基礎知識,所以我不知道你可以在模型類中定義這些表達式。你的解釋和耐心非常有幫助!非常感謝!! – Hinek 2014-10-10 08:56:23

+0

coalesce做什麼?我很困惑,爲什麼這是可行的!但是謝謝你! – 2016-03-10 11:11:09

+0

@AlexWaters:只需谷歌它,你會得到這個:https://msdn.microsoft.com/en-us/library/ms190349.aspx – van 2016-03-10 18:17:35