如何在flask / sqlalchemy中实现“包含任何”?

时间:2015-12-03 01:53:28

标签: flask sqlalchemy flask-sqlalchemy

SQLAlchemy中的contains操作只接受一个Model对象而不是对象列表。如果我想创建一个接受包含任何一组对象的过滤器,那么使用包含并将它们与union组合来创建多个过滤器是否有更多SQL风格的方式?

例如,请参阅以下代码:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
db = SQLAlchemy(app)
class User(db.Model):
    id              = db.Column(db.Integer, primary_key = True)
    name            = db.Column(db.String(100))
    son             = db.relationship('Son', backref = 'parent', lazy = 'dynamic')
    def __repr__(self):
        return '<"%s">' % self.name
class Son(db.Model):
    id              = db.Column(db.Integer, primary_key = True)
    name            = db.Column(db.String(1000))
    user_id         = db.Column(db.Integer, db.ForeignKey('user.id'))
    def __repr__(self):
        return '<"%s">' % self.name

db.create_all()

son1 = Son(name = '1 a 1')
son2 = Son(name = '1 b 1')
son3 = Son(name = '1 c 1')
son4 = Son(name = '2 a 2')
son5 = Son(name = '2 b 2')
user0 = User(name = 'w1')
user1 = User(name = 'w2')
user2 = User(name = 'w3')
user0.son.append(son1)
user0.son.append(son2)
user1.son.append(son3)
user1.son.append(son4)
user2.son.append(son5)

db.session.add(son1)
db.session.add(son2)
db.session.add(son3)
db.session.add(son4)
db.session.add(son5)
db.session.add(user0)
db.session.add(user1)
db.session.add(user2)

db.session.commit()
son_query = Son.query.filter(Son.name.ilike('%a%'))
son_query_all = son_query.all()
print son_query.all()
user_query = User.query.filter(User.son.contains(son_query_all[0])).union(*[User.query.filter(User.son.contains(query)) for query in son_query_all[1:]])
print user_query.all()

该示例首先创建两个模型:UserSon,然后创建3个User个实例和5个Son个实例。 user0包含son1son2user1包含son3son4user2包含son5。请注意,son1son4的名称都与%a%类似。现在,我想选择包含名称为User的{​​{1}}个实例的所有Son个实例。

当前方法是选择%a%中的所有Son个实例,然后选择包含各个所需son_query_all个实例的User个实例,然后使用{组合选择结果{1}}。 SQLAlchemy是否有更多SQL风格的方式来选择相同的方式?例如,是否有类似Son的内容,以便最后一个查询可以更改为

union

请注意,我当然可以使用contains_anyuser_query = User.query.filter(User.son.contains_any(son_query_all)) 操作为同一目的定义自定义contains_any函数。我的问题是,是否有一种更有效的方式而不仅仅是union所有contains - ed?

1 个答案:

答案 0 :(得分:1)

解决此类过滤的正确方法是使用JOIN。基本上,您将Son表加入User表并按加入的实体字段进行过滤。

在SQLAlchemy中,您可以这样表达:

User.query.join(Son).filter(Son.name.ilike('%a%'))

它将生成以下SQL:

SELECT * FROM user 
JOIN son ON user.id = son.user_id 
WHERE lower(son.name) LIKE lower('%a%')