清理我的SQLAlchemy操作(减少重复) [英] cleaning up my SQLAlchemy operations (reducing repetition)
问题描述
jQuery DataTables
)我使用 POST
作为我的 ajax
方法。在我的 Flask
webapp中,我可以通过 request.values $来访问
POST
数据c $ c
$ b $ p $ request $ value $的数据类型/结构是 werkzeug。 datastructures.CombinedMultiDict
如果用户想对列进行排序,请求包含一个名为 action
过滤器(注意下面的打印输出是通过获取request.values中的v:print v,request.values [
pre $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $
列[8] [搜索] [正则表达式] false
操作过滤器
列[10] [名称]
列[3] [搜索] [值]
。 ..
请求中的所有列名也包含在键中。具有搜索条件的列将具有搜索字符串作为列名称键的值(而不是为没有搜索词输入的列为空)因此,如果要搜索 firstname
包含 bill
,我会在我的请求中看到以下内容:
pre $ columns [7] [searchable] true
...
列[6] [name]
名字bill
列[0] [search] [value]
列[2] [可搜索]真
列[5] [数据]手机
角色
列[10] [数据]已注册
...
列[0] [可搜索]真
电子邮件
列[7] [orderable] true
...
列[2] [search] [值]
注意角色
和 email
是空的,所以我下面的代码是非DRY
rv = request.values
如果rv.get('action')=='filter':
if len(rv.get('firstname')):
q = q.filter(User .firstname.ilike( '%{0}%'。格式(R v.get('firstname'))))
if len(rv.get('lastname')):
q = q.filter(User.lastname.ilike('%{0}%' .format(rv.get('lastname'))))
if len(rv.get('username')):
q = q.filter(User.username.ilike('%{0 ('''')):
q = q.filter(User.email.ilike(' (rv.get('email'))))
if len(rv.get('phone')):
q = q.filter(User.phone。如果len(rv.get('region')):
q = q.filter(User .region.name.ilike('%{0}%'。format(rv.get('region'))))
if len(rv.get('role')):
q = (rv.get('role'))))
if len(rv.get('is_active')):
q = q.filter(User.is_active_ =='{0}'。format(rv.get('is_active')))
if len(rv.get('is_confirmed')):
q = q.filter(User.is (rv.get('is_confirmed')))
if len(rv.get('registered_on_from')):
fdate = datetime.strptime(rv.get get('registered_on_from'),'%Y-%m-%d')
q = q.filter(User.registered_on> fdate)
if len(rv.get('registered_on_to')):
tdate = datetime.strptime(rv.get('registered_on_to'),'%Y-%m-%d')
q = q.filter(User.registered_on< tdate)
我正在构建排序功能,我发现下面的说明大大简化了我的生活(请参阅此答案 )
$ b $ pre $
q = q.order_by('{name} {dir}'.format(name = sort_col_name,dir = sort_dir) )
我很想知道是否有方法简化这组过滤查询。像上面的排序代码,因为我将不得不为其他许多模型做这个。
from sqlalchemy.sql.sqltypes import String,Boolean
$ b $ def filter_model_by_request(qry,model,rv):
如果rv.get('action ')=='filter':
mapper = inspect(model).attrs#model mapper
col_names = list(set([c.keyper for mapper])& set(rv.keys ()))
#col_names是通过将请求值和模型列名相交而生成的列表
for col_name in col_names:
col = mapper [col_name] .columns [0]
col_type = type(col.type)
如果col_type == String:#过滤字符串
qry = qry.filter(col.ilike('%{0}%'.format(rv.get (col_name))))
elif col_type ==布尔值:#筛选布尔
qry = qry.filter(col =='{0}'.format(rv.get(col_name)))
返回qry
示例调用(我使用了@ app.before_request和cURL调用来验证):
qry = db.session.query(User)
print filter_model_by_request(qry,User,request.values).count()
日期范围过滤不包含在函数中,如果你愿意的话可以添加这个特性,你的代码对于这个目的是很好的。
边注:小心日期的大/小运算符。您排除了实际要求的日期。使用< =或> =在过滤操作中包含日期。对我来说,这总是一个陷阱。
I have some server side processing of some data (client-side library = jQuery DataTables
)
I am using POST
as my ajax
method. In my Flask
webapp, I can access the POST
data with request.values
The data type / structure of request.values
is werkzeug.datastructures.CombinedMultiDict
If the user wants to sort a column, the request contains a key called action
with a value of filter
(note the below printouts are obtained with for v in request.values: print v, request.values[v]
)
...
columns[7][data] role
columns[8][search][regex] false
action filter
columns[10][name]
columns[3][search][value]
...
all the column names are also contained in the request as keys. The columns that have search terms will have the search string as a value for the column name key (as opposed to empty for columns with no search term entered. So, If I want to search for firstname
containing bill
, I would see the following in my request
columns[7][searchable] true
...
columns[6][name]
firstname bill
columns[0][search][value]
columns[2][searchable] true
...
columns[5][data] phone
role
columns[10][data] registered_on
...
columns[0][searchable] true
email
columns[7][orderable] true
...
columns[2][search][value]
Notice how role
and email
are empty. So my code below is very non-DRY
rv = request.values
if rv.get('action') == 'filter':
if len(rv.get('firstname')):
q = q.filter(User.firstname.ilike('%{0}%'.format(rv.get('firstname'))))
if len(rv.get('lastname')):
q = q.filter(User.lastname.ilike('%{0}%'.format(rv.get('lastname'))))
if len(rv.get('username')):
q = q.filter(User.username.ilike('%{0}%'.format(rv.get('username'))))
if len(rv.get('email')):
q = q.filter(User.email.ilike('%{0}%'.format(rv.get('email'))))
if len(rv.get('phone')):
q = q.filter(User.phone.ilike('%{0}%'.format(rv.get('phone'))))
if len(rv.get('region')):
q = q.filter(User.region.name.ilike('%{0}%'.format(rv.get('region'))))
if len(rv.get('role')):
q = q.filter(User.role.name.ilike('%{0}%'.format(rv.get('role'))))
if len(rv.get('is_active')):
q = q.filter(User.is_active_ == '{0}'.format(rv.get('is_active')))
if len(rv.get('is_confirmed')):
q = q.filter(User.is_confirmed == '{0}'.format(rv.get('is_confirmed')))
if len(rv.get('registered_on_from')):
fdate = datetime.strptime(rv.get('registered_on_from'), '%Y-%m-%d')
q = q.filter(User.registered_on > fdate)
if len(rv.get('registered_on_to')):
tdate = datetime.strptime(rv.get('registered_on_to'), '%Y-%m-%d')
q = q.filter(User.registered_on < tdate)
I was building the sorting functionality, and I found the following statement that greatly simplified my life (see this answer)
q = q.order_by('{name} {dir}'.format(name=sort_col_name, dir=sort_dir))
I was wondering if there was a way to simplify this set of filtering queries like the above sorting code since I will have to do this for many other models.
This should help:
from sqlalchemy import inspect
from sqlalchemy.sql.sqltypes import String,Boolean
def filter_model_by_request(qry,model,rv):
if rv.get('action') == 'filter':
mapper = inspect(model).attrs # model mapper
col_names = list(set([c.key for c in mapper]) & set(rv.keys()))
# col_names is a list generated by intersecting the request values and model column names
for col_name in col_names:
col = mapper[col_name].columns[0]
col_type = type(col.type)
if col_type == String: # filter for String
qry = qry.filter(col.ilike('%{0}%'.format(rv.get(col_name))))
elif col_type == Boolean: # filter for Boolean
qry = qry.filter(col == '{0}'.format(rv.get(col_name)))
return qry
Example call (I used it with a @app.before_request and a cURL call to verify):
qry = db.session.query(User)
print filter_model_by_request(qry,User,request.values).count()
The date range filtering is not included in the function, add this feature if you wish, your code is fine for that purpose.
side note: be careful with the bigger/smaller operators for the dates. You're excluding the actual requested dates. Use <= or >= to include dates in filtering action. It's always a pitfall for me..
这篇关于清理我的SQLAlchemy操作(减少重复)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!