@@ -117,6 +117,9 @@ def _make_condition(self, arg):
117117 :param arg: any valid restriction object.
118118 :return: an SQL condition string. It may also be a boolean that is intended to be treated as a string.
119119 """
120+ def prep_value (v ):
121+ return str (v ) if isinstance (v , (datetime .date , datetime .datetime , datetime .time , decimal .Decimal )) else v
122+
120123 negate = False
121124 while isinstance (arg , Not ):
122125 negate = not negate
@@ -125,7 +128,7 @@ def _make_condition(self, arg):
125128
126129 # restrict by string
127130 if isinstance (arg , str ):
128- return template % arg .strip ()
131+ return template % arg .strip (). replace ( "%" , "%%" ) # escape % in strings, see issue #376
129132
130133 # restrict by AndList
131134 if isinstance (arg , AndList ):
@@ -148,15 +151,12 @@ def _make_condition(self, arg):
148151 # restrict by a mapping such as a dict -- convert to an AndList of string equality conditions
149152 if isinstance (arg , collections .abc .Mapping ):
150153 return template % self ._make_condition (
151- AndList ('`%s`=%r' % (k , (v if not isinstance (v , (
152- datetime .date , datetime .datetime , datetime .time , decimal .Decimal )) else str (v )))
153- for k , v in arg .items () if k in self .heading ))
154+ AndList ('`%s`=%r' % (k , prep_value (v )) for k , v in arg .items () if k in self .heading ))
154155
155156 # restrict by a numpy record -- convert to an AndList of string equality conditions
156157 if isinstance (arg , np .void ):
157158 return template % self ._make_condition (
158- AndList (('`%s`=' + ('%s' if self .heading [k ].numeric else '"%s"' )) % (k , arg [k ])
159- for k in arg .dtype .fields if k in self .heading ))
159+ AndList (('`%s`=%r' % (k , prep_value (arg [k ])) for k in arg .dtype .fields if k in self .heading )))
160160
161161 # restrict by a Relation class -- triggers instantiation
162162 if inspect .isclass (arg ) and issubclass (arg , Query ):
0 commit comments