Python 用于从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

我正在开发一个报告类型的应用程序,我经常需要使用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来执行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