以关键字为变量的烧瓶 sqlalchemy 查询
Posted
技术标签:
【中文标题】以关键字为变量的烧瓶 sqlalchemy 查询【英文标题】:flask sqlalchemy query with keyword as variable 【发布时间】:2013-10-30 15:05:43 【问题描述】:假设我有一个这样的模型:
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()
要获得去南加州大学的用户列表,这是我的查询:
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 表达式,但是如何根据变量将多个表达式链接在一起?
希望这更有意义。
谢谢!
【问题讨论】:
是的,我们可以帮助您构建该功能。当您尝试自己构建它时遇到了什么问题? 尝试将变量(例如:kv = 'hometown')分配为关键字 arg 时,出现此错误:nvalidRequestError: Entity 'filter_by
。所以dict = 'hometown': 'New York', 'university': 'USC'
和User.query.filter_by(dict).all()
。但是,我对此并不积极。
【参考方案1】:
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')
【讨论】:
宾果游戏!谢谢老兄-这正是我想要的。感谢您的帮助! 你如何通过这样做来实现“in_”? @Ricky 不幸的是,我有一段时间没有使用 SQLAlchemy,所以我不知道。你最好问一个新问题。【参考方案2】: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可以免费获得上面的sn-p)
【讨论】:
这是否适用于嵌套属性?例如, product.category.name ?如果没有,有办法吗? 你的意思是一个类别在哪里是产品的外键?在那种情况下,不 :) 可能有办法做到这一点,是的。【参考方案3】:正如@opyate 所指出的,如果您有非模型查询参数,例如page
用于分页,filter_by(**request.args)
不能很好地工作,也可以使用以下替代方法:
假设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)
我已尝试在我的烧瓶应用程序上实现此功能,并且运行顺利。
当然,一个缺点是如果有多个值(例如 page
)不是模型的一部分,那么它们中的每一个都必须在 get_list
中单独定义,但可以这样做通过列表理解
【讨论】:
以上是关于以关键字为变量的烧瓶 sqlalchemy 查询的主要内容,如果未能解决你的问题,请参考以下文章
create_engine 中的烧瓶 SQLAlchemy KeyError 'False'
用于生产和开发的烧瓶 postgresql sqlalchemy 配置