假设我有一个这样的模型:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
hometown = db.Column(db.String(140))
university = db.Column(db.String(140))
要获取纽约的用户列表,这是我的查询:
User.query.filter_by(hometown='New York').all()
要获取前往USC的用户列表,这是我的查询:
User.query.filter_by(university='USC').all()
要获得纽约用户列表以及前往南加州大学的用户,这是我的疑问:
User.query.filter_by(hometown='New York').filter_by(university='USC').all()
现在,我想根据变量的值动态生成这些查询。
例如,我的变量可能如下所示:
{'hometown': 'New York'}
或者像这样:
{'university': 'USC'}
......或者甚至喜欢这样:
[{'hometown': 'New York'}, {'university': 'USC'}]
你能帮我编写一个以词典(或字典列表)作为输入的函数,然后动态构建正确的sqlalchemy查询吗?
如果我尝试为关键字使用变量,我会犯这个错误:
key = 'university'
User.query.filter_by(key='USC').all()
InvalidRequestError: Entity '<class 'User'>' has no property 'key'
其次,我不确定如何动态地将多个filter_by表达式链接在一起。
我可以明确地调出一个filter_by表达式,但是如何根据变量将几个链接在一起呢?
希望这更有意义。
谢谢!
答案 0 :(得分:36)
SQLAlchemy的filter_by
接受关键字参数:
filter_by(** kwargs)
换句话说,该函数将允许您为其提供任何关键字参数。这就是为什么你可以在代码中使用你想要的任何关键字的原因:SQLAlchemy基本上将参数视为值的字典。有关关键字参数的详细信息,请参阅Python tutorial。
这样,SQLAlchemy的开发人员可以以字典形式接收任意一组关键字参数。但是你要求相反:你能将任意一串关键字参数传递给函数吗?
事实证明,在Python中,您可以使用名为unpacking的功能。只需创建参数字典并将其传递给前面加**
的函数,如下所示:
kwargs = {'hometown': 'New York', 'university' : 'USC'}
User.query.filter_by(**kwargs)
# This above line is equivalent to saying...
User.query.filter_by(hometown='New York', university='USC')
答案 1 :(得分:1)
filter_by(**request.args)
用于分页),则 page
无法正常工作,否则会出现以下错误:
InvalidRequestError: Entity '<class 'flask_sqlalchemy.MyModelSerializable'>' has no property 'page'
我使用类似这样的东西来忽略不在模型中的查询参数:
builder = MyModel.query
for key in request.args:
if hasattr(MyModel, key):
vals = request.args.getlist(key) # one or many
builder = builder.filter(getattr(MyModel, key).in_(vals))
if not 'page' in request.args:
resources = builder.all()
else:
resources = builder.paginate(
int(request.args['page'])).items
考虑一个名为valid
的列的模型,这样的东西会起作用:
curl -XGET "http://0.0.0.0/mymodel_endpoint?page=1&valid=2&invalid=whatever&valid=1"
invalid
将被忽略,page
可用于分页,最重要的是,将生成以下SQL:WHERE mymodel.valid in (1,2)
(如果您使用此boilerplate-saving module)
,请免费获取上述代码段答案 2 :(得分:0)
如@opyate所指出的那样,如果您有非模型查询参数(例如用于分页的filter_by(**request.args)
),则page
不能很好地工作,也可以使用以下替代方法:
假设page
的形式为request.args.get()
,则:
def get_list(**filters):
page = None
if 'page' in filters:
page = filters.pop('limit')
items = Price.query.filter_by(**filters)
if page is not None:
items = items.paginate(per_page=int(page)).items
else:
items = items.all()
return {
"items": items
}
然后是get
函数
def get(self):
hometown = request.args.get('hometown')
university = request.args.get('university')
page = request.args.get('page')
return get_list(**request.args)
我已经尝试在我的flask应用程序中实现此功能,并且运行顺利。
当然,可能存在的一个缺点是,如果存在page
等多个不属于模型的值,则每个值都必须在get_list
中单独定义,但是可以通过列表理解来完成