Python 用于从JSON类值生成SQLAlchemy查询的工具?
我正在开发一个报告类型的应用程序,我经常需要使用JSON指定的过滤器,将其转换为SQLAlchemy查询,然后将结果发送回浏览器(例如过滤器Python 用于从JSON类值生成SQLAlchemy查询的工具?,python,json,sqlalchemy,Python,Json,Sqlalchemy,我正在开发一个报告类型的应用程序,我经常需要使用JSON指定的过滤器,将其转换为SQLAlchemy查询,然后将结果发送回浏览器(例如过滤器start\u date:1234,end\u date:5678,小部件\u id:[1,2,3]需要转换为查询…其中start\u date>=1234和end\u date查看您的示例,您的JSON字符串实际上不包含运算符,因此不清楚它是否是=,>=,之一。我编写了类似的东西。我称它为Python代理。它提供了一个Javascript API来执行RP
start\u date:1234,end\u date:5678,小部件\u id:[1,2,3]
需要转换为查询…其中start\u date>=1234和end\u date查看您的示例,您的JSON
字符串实际上不包含运算符
,因此不清楚它是否是=,>=,之一。我编写了类似的东西。我称它为Python代理。它提供了一个Javascript API来执行RPCPython,通过JSON
这是我的开源项目的一部分
相关文件包括:
Javascript方面:
用法:
示例配置:
然而,它是一个完整框架的一部分,可惜没有很好的文档记录。需要一个最新的Linux平台和一些设置
但也许你可以从中得到一些想法
下面是从CLI样式(argv)字符串生成查询的一些其他代码。它执行dynamcic运算符选择
def _get_query(self, argv):
mapper = models.class_mapper(self._obj)
args, kwargs = _query_args(argv[1:], self._environ)
q = _session.query(self._obj)
if args:
grps, left = divmod(len(args), 3)
if grps:
for name, op, val in _by_three(args[:grps*3]):
col = getattr(self._obj, name)
opm = {"=": col.__eq__,
">": col.__gt__,
"<": col.__lt__,
"match": col.match,
"contains": col.contains,
"in": col.in_,
"like": col.like}.get(op)
if opm:
if op == "like":
val = val.replace("*", "%")
val = val.replace(".", "_")
if "%" not in val:
val = "%" + val + "%"
if op == "in":
val = val.split(",")
q = q.filter(opm(val))
for name in args[grps*3:]:
if name.startswith("="):
q = q.order_by(name[1:])
if kwargs:
for name, value in kwargs.items():
col = getattr(self._obj, name)
value = CLI.clieval(value)
q = q.filter(col.__eq__(value))
return q
def\u get\u查询(self,argv):
映射器=模型。类映射器(自身对象)
args,kwargs=\u query\u args(argv[1:],self.\u环境)
q=\u session.query(self.\u obj)
如果参数为:
grps,左=divmod(len(args),3)
如果GRP:
对于名称、op、val(参数[:grps*3]):
col=getattr(self.\u obj,name)
opm={“=”:列,
“>”:上校,
“我有一些可能感兴趣的简单代码():
def create_attr_过滤器(请求,映射类):
“”“创建一个基于
在请求参数上(`queryable`、`eq`、`ne`,…)。
论据:
要求
请求。
映射类
SQLAlchemy映射类。
"""
映射={
“情商”:“情商”,
“ne”:“ne”,
“lt”:“lt”,
‘lte’:‘乐’,
“gt”:“gt”,
"gte":"ge",,
‘like’:‘like’,
“ilike”:“ilike”
}
过滤器=[]
如果request.params中的“queryable”:
queryable=request.params['queryable'].split(',')
对于request.params中的k:
如果len(request.params[k])为0,则为无
对不起,我想这些例子不是很清楚:我可以想象这个工具会定义一些方法来确定应该使用哪个操作符(例如,Django的ORM在
中使用像\uu和\uge
这样的后缀)。我意识到我可以构建自己的东西,但这似乎是一个潜在的常见问题,因此我想知道是否存在任何现有的解决方案。(另外,我认为您混淆了“运算符”和“操作数”)2)一个错误:很好的观点-修正了它。1)我认为没有任何工具能够100%准确地自动确定操作符。我确实看到开始日期可能意味着=
,但它同样可能是=
,
,中的任何一个,显然,启发式方法是确定应该使用的操作符的糟糕方法ld可以被使用…但是,幸运的是,它们不是唯一的方法。正如我提到的,Django ORM使用后缀,我相信还有很多其他合理的方法可以做到。啊,我明白了。如果我理解的话,我只能基于平等进行过滤…不?@DavidWolever我更新了我的答案,加入了一些其他可以做到这一点的代码。
q = session.query(myClass)
for attr, value in web_dict.items():
q = q.filter(getattr(myClass, attr).like("%%%s%%" % value))
klass, attr, oper, value = MyClass, "startDate", "__ge__", 1234
q = q.filter(getattr(getattr(klass, attr), oper)(value))
def _get_query(self, argv):
mapper = models.class_mapper(self._obj)
args, kwargs = _query_args(argv[1:], self._environ)
q = _session.query(self._obj)
if args:
grps, left = divmod(len(args), 3)
if grps:
for name, op, val in _by_three(args[:grps*3]):
col = getattr(self._obj, name)
opm = {"=": col.__eq__,
">": col.__gt__,
"<": col.__lt__,
"match": col.match,
"contains": col.contains,
"in": col.in_,
"like": col.like}.get(op)
if opm:
if op == "like":
val = val.replace("*", "%")
val = val.replace(".", "_")
if "%" not in val:
val = "%" + val + "%"
if op == "in":
val = val.split(",")
q = q.filter(opm(val))
for name in args[grps*3:]:
if name.startswith("="):
q = q.order_by(name[1:])
if kwargs:
for name, value in kwargs.items():
col = getattr(self._obj, name)
value = CLI.clieval(value)
q = q.filter(col.__eq__(value))
return q
def create_attr_filter(request, mapped_class):
"""Create an ``and_`` SQLAlchemy filter (a ClauseList object) based
on the request params (``queryable``, ``eq``, ``ne``, ...).
Arguments:
request
the request.
mapped_class
the SQLAlchemy mapped class.
"""
mapping = {
'eq' : '__eq__',
'ne' : '__ne__',
'lt' : '__lt__',
'lte' : '__le__',
'gt' : '__gt__',
'gte' : '__ge__',
'like' : 'like',
'ilike': 'ilike'
}
filters = []
if 'queryable' in request.params:
queryable = request.params['queryable'].split(',')
for k in request.params:
if len(request.params[k]) <= 0 or '__' not in k:
continue
col, op = k.split("__")
if col not in queryable or op not in mapping.keys():
continue
column = getattr(mapped_class, col)
f = getattr(column, mapping[op])(request.params[k])
filters.append(f)
return and_(*filters) if len(filters) > 0 else None