如何通过对相关对象进行过滤来获取具有不同项目的SQL Alchemy对象

Ava*_*gut 0 python sqlalchemy distinct flask-sqlalchemy

我正在尝试对相关对象进行以下过滤的不同项目的SQL Alchemy查询,其等效于以下查询:

SELECT distinct items.item_id, items.item_name
FROM items
INNER JOIN categories as cat on items.category_id = cat.category_id
INNER JOIN stores on cat.store_id = stores.store_id
WHERE store.store_id = 123    
Run Code Online (Sandbox Code Playgroud)

我已经创建了以下包含外键的模型,但是当我在下面运行查询时,它不能正确过滤。

items_query = (db.session.query(Store, Item)
               .filter(Store.store_id == 123)
               ).all()



#SQL Alchemy Models 
class Store(db.Model):
    __tablename__ = 'stores'
    store_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    store_name = db.Column(db.String(100), unique=True, nullable=False)

    def __repr__(self):
        return '<Store>'+str(self.store_name)

class Category(db.Model):
    __tablename__ = 'categories'
    category_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    category_name = db.Column(db.String(100), unique=True, nullable=False)
    store_id = db.Column(db.Integer, db.ForeignKey('stores.store_id'))
    store = db.relationship('Store', backref=db.backref('categories', lazy='dynamic'))

    def __repr__(self):
        return '<Category>'+str(self.category_name)

class Item(db.Model):
    __tablename__ = 'items'
    item_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    item_name = db.Column(db.String(150), unique=True, nullable=False)
    category_id = db.Column(db.Integer, db.ForeignKey('categories.category_id'))
    category = db.relationship('Category', backref=db.backref('items', lazy='dynamic'))

    def __repr__(self):
        return '<Item>'+str(self.item_name)
Run Code Online (Sandbox Code Playgroud)

谁能帮助我更好地构成查询?

Ilj*_*ilä 5

(db.session.query(Store, Item)
 .filter(Store.store_id == 123)
 ).all()
Run Code Online (Sandbox Code Playgroud)

您将在和之间获得隐式交叉联接,这显然不是您想要的。StoreItem

首先使用关系明确建立所需的联接

query = db.session.query(Item.item_id, Item.item_name).\
    join(Item.category).\
    join(Category.store)
Run Code Online (Sandbox Code Playgroud)

或简写形式:

query = db.session.query(Item.item_id, Item.item_name).\
    join("category", "store")
Run Code Online (Sandbox Code Playgroud)

然后应用您的WHERE子句:

query = query.filter(Store.store_id == 123)
Run Code Online (Sandbox Code Playgroud)

然后distinct()

query = query.distinct()
Run Code Online (Sandbox Code Playgroud)

把它们加起来:

query = db.session.query(Item.item_id, Item.item_name).\
    join("category", "store").\
    filter(Store.store_id == 123).\
    distinct().\
    all()
Run Code Online (Sandbox Code Playgroud)

同样,由于对您有唯一的约束,Item.item_name并且Item由于一对多关系的方向,每个联接不应该产生多行,因此该联接distinct()是不必要的。