ソースを参照

[cleanup] build_filter_conditions and [fix] replace % with %% in condition to prevent python format string error

version-14
Anand Doshi 9年前
コミット
b402df175e
1個のファイルの変更87行の追加49行の削除
  1. +87
    -49
      frappe/model/db_query.py

+ 87
- 49
frappe/model/db_query.py ファイルの表示

@@ -201,56 +201,88 @@ class DatabaseQuery(object):
"""build conditions from user filters"""
if isinstance(filters, dict):
filters = [filters]

for f in filters:
if isinstance(f, basestring):
conditions.append(f)
else:
f = self.get_filter_tuple(f)

tname = ('`tab' + f[0] + '`')
if not tname in self.tables:
self.append_table(tname)

# prepare in condition
if f[2] in ['in', 'not in']:
opts = f[3]
if not isinstance(opts, (list, tuple)):
opts = f[3].split(",")
opts = [frappe.db.escape(t.strip()) for t in opts]
f[3] = '("{0}")'.format('", "'.join(opts))
conditions.append('ifnull({tname}.{fname}, "") {operator} {value}'.format(
tname=tname, fname=f[1], operator=f[2], value=f[3]))
else:
df = frappe.get_meta(f[0]).get("fields", {"fieldname": f[1]})
df = df[0] if df else None

if df and df.fieldtype=="Date":
value, default_val = '"{0}"'.format(frappe.db.escape(getdate(f[3]).strftime("%Y-%m-%d"))), \
"'0000-00-00'"

elif df and df.fieldtype=="Datetime":
value, default_val = '"{0}"'.format(frappe.db.escape(get_datetime(f[3]).strftime("%Y-%m-%d %H:%M:%S.%f"))), \
"'0000-00-00 00:00:00'"

elif df and df.fieldtype=="Time":
value, default_val = '"{0}"'.format(frappe.db.escape(get_time(f[3]).strftime("%H:%M:%S.%f"))), \
"'00:00:00'"

elif f[2] == "like" or (isinstance(f[3], basestring) and
(not df or df.fieldtype not in ["Float", "Int", "Currency", "Percent", "Check"])):
if f[2] == "like" and isinstance(f[3], basestring):
# because "like" uses backslash (\) for escaping
f[3] = f[3].replace("\\", "\\\\")

value, default_val = '"{0}"'.format(frappe.db.escape(f[3])), '""'
else:
value, default_val = flt(f[3]), 0

conditions.append('ifnull({tname}.{fname}, {default_val}) {operator} {value}'.format(
tname=tname, fname=f[1], default_val=default_val, operator=f[2],
value=value))

def get_filter_tuple(self, f):
conditions.append(self.prepare_filter_condition(f))

def prepare_filter_condition(self, f):
"""Returns a filter condition in the format:

ifnull(`tabDocType`.`fieldname`, fallback) operator "value"
"""

f = self.get_filter(f)

tname = ('`tab' + f.doctype + '`')
if not tname in self.tables:
self.append_table(tname)

# prepare in condition
if f.operator in ('in', 'not in'):
values = f.value
if not isinstance(values, (list, tuple)):
values = values.split(",")

values = (frappe.db.escape(v.strip()) for v in values)
values = '("{0}")'.format('", "'.join(values))

condition = 'ifnull({tname}.{fname}, "") {operator} {value}'.format(
tname=tname, fname=f.fieldname, operator=f.operator, value=values)

else:
df = frappe.get_meta(f.doctype).get("fields", {"fieldname": f.fieldname})
df = df[0] if df else None

if df and df.fieldtype=="Date":
value = getdate(f.value).strftime("%Y-%m-%d")
fallback = "'0000-00-00'"

elif df and df.fieldtype=="Datetime":
value = get_datetime(f.value).strftime("%Y-%m-%d %H:%M:%S.%f")
fallback = "'0000-00-00 00:00:00'"

elif df and df.fieldtype=="Time":
value = get_time(f.value).strftime("%H:%M:%S.%f")
fallback = "'00:00:00'"

elif f.operator == "like" or (isinstance(f.value, basestring) and
(not df or df.fieldtype not in ["Float", "Int", "Currency", "Percent", "Check"])):
value = f.value
fallback = '""'

if f.operator == "like" and isinstance(value, basestring):
# because "like" uses backslash (\) for escaping
value = value.replace("\\", "\\\\")

else:
value = flt(f.value)
fallback = 0

# put it inside double quotes
if isinstance(value, basestring):
value = '"{0}"'.format(frappe.db.escape(value))

condition = 'ifnull({tname}.{fname}, {fallback}) {operator} {value}'.format(
tname=tname, fname=f.fieldname, fallback=fallback, operator=f.operator,
value=value)

# replace % with %% to prevent python format string error
return condition.replace("%", "%%")

def get_filter(self, f):
"""Returns a _dict like

{
"doctype": "DocType",
"fieldname": "fieldname",
"operator": "=",
"value": "value"
}

"""
if isinstance(f, dict):
key, value = f.items()[0]
f = self.make_filter_tuple(key, value)
@@ -262,9 +294,14 @@ class DatabaseQuery(object):
f = (self.doctype, f[0], f[1], f[2])

elif len(f) != 4:
frappe.throw("Filter must have 4 values (doctype, fieldname, condition, value): " + str(f))
frappe.throw("Filter must have 4 values (doctype, fieldname, operator, value): " + str(f))

return list(f)
return frappe._dict({
"doctype": f[0],
"fieldname": f[1],
"operator": f[2],
"value": f[3]
})

def build_match_conditions(self, as_condition=True):
"""add match conditions if applicable"""
@@ -313,7 +350,8 @@ class DatabaseQuery(object):
conditions = "({conditions}) or ({shared_condition})".format(
conditions=conditions, shared_condition=self.get_share_condition())

return conditions
# replace % with %% to prevent python format string error
return conditions.replace("%", "%%")

else:
return self.match_filters


読み込み中…
キャンセル
保存