如何解析作为 过滤器 方法中的参数给出的子句?
运行
filters_clause = Record.start> =' 2017-07-17'
打印(filters_clause)
给出一个字符串
records.start> =:start_1
必须使用实际值而不是:start_1 ,并且该值必须已由 process_bind_param 函数传递。我必须使用哪种方法来获取类似的字符串: records.start> =' 1500321600.0' ?
#!/usr/bin/env python
# coding=utf-8
from __future__ import ( division, absolute_import,
print_function, unicode_literals )
import time
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker, attributes
from sqlalchemy.types import TypeDecorator
from sqlalchemy import create_engine, MetaData, Column, Integer, String
Base = declarative_base()
class EpochTime(TypeDecorator):
impl = Integer
def process_bind_param(self, value, dialect):
if isinstance(value, unicode):
if value.isdigit():
return value
if len(value) == 10:
value = time.mktime(time.strptime(value, "%Y-%m-%d"))
elif len(value) == 13:
value = time.mktime(time.strptime(value, "%Y-%m-%d %H"))
elif len(value) == 16:
value = time.mktime(time.strptime(value, "%Y-%m-%d %H:%M"))
return value
def process_result_value(self, value, dialect):
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(value))
class Record(Base):
__tablename__ = 'records'
id = Column(Integer, primary_key=True)
name = Column(String)
start = Column(EpochTime)
engine = create_engine('sqlite://')
session = scoped_session(sessionmaker())
session.configure(bind=engine)
Base.metadata.create_all(engine)
record = Record(name = 'Record 1', start = '2017-07-16')
session.add(record)
record = Record(name = 'Record 2', start = '2017-07-17')
session.add(record)
record = Record(name = 'Record 3', start = '2017-07-18')
session.add(record)
session.commit()
filters_clause = Record.start>='2017-07-17'
s = session.query(Record).filter(filters_clause)
res = s.all()
names = [i.name for i in Record.__table__.c]
rows = [[row.__dict__.get(i) for i in names] for row in res]
for row in rows:
print(row)
print(0, s)
print(1, filters_clause)
答案 0 :(得分:1)
我认为你想要的是literal_binds
:
print(filters_clause.compile(engine, compile_kwargs={"literal_binds": True}))
# records.start >= 1500274800.0
如果使用literal_binds
,请注意SQL注入。
答案 1 :(得分:0)
我认为你不能简单地使用vanilla sqlalchemy实现这一目标。 您可以尝试使用自定义功能,例如:
import re
def represent_filter(expression):
expression = expression.compile()
params = expression.params
prefixed_names = [':' + param for param in params]
pattern = re.compile('(%s)' % '|'.join(prefixed_names))
def substitute_param_value(match):
return params[match.group()[1:]]
return pattern.sub(substitute_param_value, expression.string)
然后使用它调用represent_filter(filters_clause)
,它将返回records.start >= 2017-07-17
。
您可以强制使用 represent_filter 函数来引用替换值,使用repr(str(params[match.group()[1:]]))
代替params[match.group()[1:]]
。
另一种方法是遍历给定的表达式(在您的情况下filters_clause
是BinaryExpression
,也有一元表达式),检查左侧和右侧并构建您自己的表示。如果您只想恢复该值(您提供给过滤器的日期),则它位于filters_clause.right.effective_value
。