2017-07-06 63 views
0

我正在用SQLAlchemy和Postgres创建一个应用程序。我非常青睐这个,所以我的任何反馈将不胜感激。但是,我的直接问题是在以下模型上构建查询。多连接SQLAlchemy查询

from app import db 
from sqlalchemy import or_, and_ 


# Items Table 
class Item(db.Model): 

    __tablename__ = "items" 

    id = db.Column(db.Integer, primary_key=True) 
    itemName = db.Column(db.String, unique=True, nullable=False) 
    measurement = db.Column(db.String, nullable=False) 
    defaultPrice = db.Column(db.Float, nullable=False) 
    minimumOrder = db.Column(db.Float, nullable=False) 
    maximumOrder = db.Column(db.Float, nullable=False) 
    orders = db.relationship('Order', back_populates='item') 
    prices = db.relationship('Price', back_populates='item') 

    def __init__(self, itemName, measurement, defaultPrice, 
       minimumOrder, maximumOrder): 
     self.itemName = itemName 
     self.measurement = measurement 
     self.defaultPrice = defaultPrice 
     self.minimumOrder = minimumOrder 
     self.maximumOrder = maximumOrder 

    def __repr__(self): 
     return '<Item {0}>'.format(self.id) 


# Users Table 
class User(db.Model): 

    __tablename__ = 'users' 

    id = db.Column(db.Integer, primary_key=True) 
    fullName = db.Column(db.String, unique=True, nullable=False) 
    userName = db.Column(db.String, unique=True, nullable=False) 
    password = db.Column(db.String, nullable=False) 
    role = db.Column(db.String, nullable=False) 
    orders = db.relationship('Order', back_populates='user') 
    prices = db.relationship('Price', back_populates='user') 

    def __init__(self, fullName, userName, password, role): 
     self.fullName = fullName 
     self.userName = userName 
     self.password = password 
     self.role = role 

    def __repr__(self): 
     return '<User {0}>'.format(self.userName) 


# Availability/Price Table 
class Price(db.Model): 

    __tablename__ = 'prices' 

    id = db.Column(db.Integer, primary_key=True) 
    userId = db.Column(db.Integer, db.ForeignKey('users.id')) 
    user = db.relationship('User', back_populates='prices') 
    itemId = db.Column(db.Integer, db.ForeignKey('items.id')) 
    item = db.relationship('Item', back_populates='prices') 
    available = db.Column(db.Boolean) 
    priceMeasurement = db.Column(db.String) 
    price = db.Column(db.Float) 

    def __init__(self, userId, itemId, priceMeasurement, price): 
     self.userId = userId 
     self.itemId = itemId 
     self.priceMeasurement = priceMeasurement 
     self.price = price 

    def __repr__(self): 
     return '<Price {0}>'.format(self.price) 


# Orders Table 
class Order(db.Model): 

    __tablename__ = 'orders' 

    id = db.Column(db.Integer, primary_key=True) 
    userId = db.Column(db.Integer, db.ForeignKey('users.id')) 
    user = db.relationship('User', back_populates='orders') 
    itemId = db.Column(db.Integer, db.ForeignKey('items.id')) 
    item = db.relationship('Item', back_populates='orders') 
    orderQuantity = db.Column(db.Float) 
    orderMeasurement = db.Column(db.String) 
    orderPrice = db.Column(db.Float) 
    orderDelivery = db.Column(db.Date) 
    orderPlaced = db.Column(db.Date) 

    def __init__(self, userId, itemId, orderQuantity, 
       orderMeasurement, orderPrice, orderDelivery, orderPlaced): 
     self.userId = userId 
     self.itemId = itemId 
     self.orderQuantity = orderQuantity 
     self.orderMeasurement = orderMeasurement 
     self.orderPrice = orderPrice 
     self.orderDelivery = orderDelivery 
     self.orderPlaced = orderPlaced 

    def __repr__(self): 
     return '<Order {0}>'.format(self.orderDelivery) 

我想从查询什么是返回类似于一个表,下面的查询返回:

SELECT * FROM items 
JOIN prices ON prices.itemId=items.id 
WHERE prices.userId = 1 AND prices.available = True 
LEFT JOIN (
SELECT * FROM orders WHERE orderDelivery = '2017-07-05') as orders 
ON orders.itemId=items.id 

在SQLAlchemy的查询。我会将userId和orderDelivery变量传递给来自路由和会话的查询 - @app.route('/user/order/<order_date>') | session['userID']:在登录时建立。

感谢

+1

也许[this](https://stackoverflow.com/questions/27392661/sqlalchemy-left-join-using-subquery)可以帮助你,或者[this](https://stackoverflow.com/questions/30311354)/SQLAlchemy的接合用用,子查询-问题)。请检查[官方文档](http://docs.sqlalchemy.org/en/latest/orm/query.html)主题为“高级加入定位和自适应” –

回答

2

如果我理解正确的,你想查询的(Item, Price, Order) entitites,其中订单来自子查询的元组。这在对象关系教程Selecting Entities from Subqueries下进行了解释。

In [5]: from datetime import date 

In [6]: orders_sq = db.session.query(Order).\ 
    ...:  filter(Order.orderDelivery == date(2017, 7, 5)).\ 
    ...:  subquery() 

In [7]: orders_alias = db.aliased(Order, orders_sq) 

In [8]: query = db.session.query(Item, Price, orders_alias).\ 
    ...:  join(Price).\ 
    ...:  outerjoin(orders_alias, Item.orders).\ 
    ...:  filter(Price.userId == 1, 
    ...:   Price.available) 

以及在针对SQLite的编译生成的SQL:

In [9]: print(query) 
SELECT items.id AS items_id, items."itemName" AS "items_itemName", items.measurement AS items_measurement, items."defaultPrice" AS "items_defaultPrice", items."minimumOrder" AS "items_minimumOrder", items."maximumOrder" AS "items_maximumOrder", prices.id AS prices_id, prices."userId" AS "prices_userId", prices."itemId" AS "prices_itemId", prices.available AS prices_available, prices."priceMeasurement" AS "prices_priceMeasurement", prices.price AS prices_price, anon_1.id AS anon_1_id, anon_1."userId" AS "anon_1_userId", anon_1."itemId" AS "anon_1_itemId", anon_1."orderQuantity" AS "anon_1_orderQuantity", anon_1."orderMeasurement" AS "anon_1_orderMeasurement", anon_1."orderPrice" AS "anon_1_orderPrice", anon_1."orderDelivery" AS "anon_1_orderDelivery", anon_1."orderPlaced" AS "anon_1_orderPlaced" 
FROM items JOIN prices ON items.id = prices."itemId" LEFT OUTER JOIN (SELECT orders.id AS id, orders."userId" AS "userId", orders."itemId" AS "itemId", orders."orderQuantity" AS "orderQuantity", orders."orderMeasurement" AS "orderMeasurement", orders."orderPrice" AS "orderPrice", orders."orderDelivery" AS "orderDelivery", orders."orderPlaced" AS "orderPlaced" 
FROM orders 
WHERE orders."orderDelivery" = ?) AS anon_1 ON items.id = anon_1."itemId" 
WHERE prices."userId" = ? AND prices.available = 1 

也或者你可以简单的语句传递到Query.from_statement有一些修正和变化:

In [45]: query2 = db.session.query(Item, Price, Order).\ 
    ...:  from_statement(db.text(""" 
    ...: SELECT * FROM items 
    ...: JOIN prices ON prices.itemId=items.id 
    ...: LEFT JOIN (
    ...: SELECT * FROM orders WHERE orderDelivery = :orderDelivery) as orders 
    ...: ON orders.itemId=items.id 
    ...: WHERE prices.userId = :userId AND prices.available 
    ...: """)).\ 
    ...:  params(userId=1, orderDelivery='2017-07-05') 

但我d建议使用前一种方法,因为它更像数据库不可知论者。

+0

对于延迟抱歉 - 这是完美的。比我最初的SQL查询返回一个非常宽的表更具有意义。 –

+0

呵呵,它下面还是宽的,但实体对象隐藏了许多列。 –