Ticket #1133: query_args.patch
File query_args.patch, 9.1 KB (added by , 19 years ago) |
---|
-
django/db/models/manager.py
50 50 self.creation_counter < klass._default_manager.creation_counter: 51 51 klass._default_manager = self 52 52 53 def _get_sql_clause(self, * *kwargs):53 def _get_sql_clause(self, *args, **kwargs): 54 54 def quote_only_if_word(word): 55 55 if ' ' in word: 56 56 return word … … 66 66 where = kwargs.get('where') and kwargs['where'][:] or [] 67 67 params = kwargs.get('params') and kwargs['params'][:] or [] 68 68 69 # Convert all the args into SQL. 70 table_count = 0 71 for arg in args: 72 # check that the provided argument is a Query (i.e., it has a get_sql method) 73 if not hasattr(arg, 'get_sql'): 74 raise TypeError, "got unknown query argument '%s'" % str(arg) 75 76 tables2, join_where2, where2, params2, table_count = arg.get_sql(opts, table_count) 77 tables.extend(tables2) 78 where.extend(join_where2 + where2) 79 params.extend(params2) 80 69 81 # Convert the kwargs into SQL. 70 tables2, join_where2, where2, params2, _ = parse_lookup(kwargs.items(), opts )82 tables2, join_where2, where2, params2, _ = parse_lookup(kwargs.items(), opts, table_count) 71 83 tables.extend(tables2) 72 84 where.extend(join_where2 + where2) 73 85 params.extend(params2) … … 117 129 118 130 return select, " FROM " + ",".join(tables) + (where and " WHERE " + " AND ".join(where) or "") + (order_by and " ORDER BY " + order_by or "") + limit_sql, params 119 131 120 def get_iterator(self, * *kwargs):132 def get_iterator(self, *args, **kwargs): 121 133 # kwargs['select'] is a dictionary, and dictionaries' key order is 122 134 # undefined, so we convert it to a list of tuples internally. 123 135 kwargs['select'] = kwargs.get('select', {}).items() 124 136 125 137 cursor = connection.cursor() 126 select, sql, params = self._get_sql_clause(* *kwargs)138 select, sql, params = self._get_sql_clause(*args, **kwargs) 127 139 cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params) 128 140 fill_cache = kwargs.get('select_related') 129 141 index_end = len(self.klass._meta.fields) … … 140 152 setattr(obj, k[0], row[index_end+i]) 141 153 yield obj 142 154 143 def get_list(self, * *kwargs):144 return list(self.get_iterator(* *kwargs))155 def get_list(self, *args, **kwargs): 156 return list(self.get_iterator(*args, **kwargs)) 145 157 146 def get_count(self, * *kwargs):158 def get_count(self, *args, **kwargs): 147 159 kwargs['order_by'] = [] 148 160 kwargs['offset'] = None 149 161 kwargs['limit'] = None 150 162 kwargs['select_related'] = False 151 _, sql, params = self._get_sql_clause(* *kwargs)163 _, sql, params = self._get_sql_clause(*args, **kwargs) 152 164 cursor = connection.cursor() 153 165 cursor.execute("SELECT COUNT(*)" + sql, params) 154 166 return cursor.fetchone()[0] 155 167 156 def get_object(self, * *kwargs):157 obj_list = self.get_list(* *kwargs)168 def get_object(self, *args, **kwargs): 169 obj_list = self.get_list(*args, **kwargs) 158 170 if len(obj_list) < 1: 159 171 raise self.klass.DoesNotExist, "%s does not exist for %s" % (self.klass._meta.object_name, kwargs) 160 172 assert len(obj_list) == 1, "get_object() returned more than one %s -- it returned %s! Lookup parameters were %s" % (self.klass._meta.object_name, len(obj_list), kwargs) 161 173 return obj_list[0] 162 174 163 175 def get_in_bulk(self, *args, **kwargs): 164 id_list = args and args[0] or kwargs['id_list'] 165 assert id_list != [], "get_in_bulk() cannot be passed an empty list." 176 # Separate any list arguments: these will be added together to provide the id list 177 id_args = filter(lambda arg: isinstance(arg, list), args) 178 # Separate any non-list arguments: these are assumed to be query arguments 179 sql_args = filter(lambda arg: not isinstance(arg, list), args) 180 181 id_list = id_args and id_args[0] or kwargs.get('id_list', []) 182 assert id_list != [], "get_in_bulk() cannot be passed an empty ID list." 166 183 kwargs['where'] = ["%s.%s IN (%s)" % (backend.quote_name(self.klass._meta.db_table), backend.quote_name(self.klass._meta.pk.column), ",".join(['%s'] * len(id_list)))] 167 184 kwargs['params'] = id_list 168 obj_list = self.get_list(* *kwargs)185 obj_list = self.get_list(*sql_args, **kwargs) 169 186 return dict([(getattr(o, self.klass._meta.pk.attname), o) for o in obj_list]) 170 187 171 def get_values_iterator(self, * *kwargs):188 def get_values_iterator(self, *args, **kwargs): 172 189 # select_related and select aren't supported in get_values(). 173 190 kwargs['select_related'] = False 174 191 kwargs['select'] = {} … … 180 197 fields = [f.column for f in self.klass._meta.fields] 181 198 182 199 cursor = connection.cursor() 183 _, sql, params = self._get_sql_clause(* *kwargs)200 _, sql, params = self._get_sql_clause(*args, **kwargs) 184 201 select = ['%s.%s' % (backend.quote_name(self.klass._meta.db_table), backend.quote_name(f)) for f in fields] 185 202 cursor.execute("SELECT " + (kwargs.get('distinct') and "DISTINCT " or "") + ",".join(select) + sql, params) 186 203 while 1: … … 190 207 for row in rows: 191 208 yield dict(zip(fields, row)) 192 209 193 def get_values(self, * *kwargs):194 return list(self.get_values_iterator(* *kwargs))210 def get_values(self, *args, **kwargs): 211 return list(self.get_values_iterator(*args, **kwargs)) 195 212 196 def __get_latest(self, * *kwargs):213 def __get_latest(self, *args, **kwargs): 197 214 kwargs['order_by'] = ('-' + self.klass._meta.get_latest_by,) 198 215 kwargs['limit'] = 1 199 return self.get_object(* *kwargs)216 return self.get_object(*args, **kwargs) 200 217 201 218 def __get_date_list(self, field, *args, **kwargs): 219 # Separate any string arguments: the first will be used as the kind 220 kind_args = filter(lambda arg: isinstance(arg, str), args) 221 # Separate any non-list arguments: these are assumed to be query arguments 222 sql_args = filter(lambda arg: not isinstance(arg, str), args) 223 202 224 from django.db.backends.util import typecast_timestamp 203 kind = args and args[0] or kwargs['kind']225 kind = kind_args and kind_args[0] or kwargs.get('kind', "") 204 226 assert kind in ("month", "year", "day"), "'kind' must be one of 'year', 'month' or 'day'." 205 227 order = 'ASC' 206 228 if kwargs.has_key('order'): … … 211 233 if field.null: 212 234 kwargs.setdefault('where', []).append('%s.%s IS NOT NULL' % \ 213 235 (backend.quote_name(self.klass._meta.db_table), backend.quote_name(field.column))) 214 select, sql, params = self._get_sql_clause(* *kwargs)236 select, sql, params = self._get_sql_clause(*sql_args, **kwargs) 215 237 sql = 'SELECT %s %s GROUP BY 1 ORDER BY 1 %s' % \ 216 238 (backend.get_date_trunc_sql(kind, '%s.%s' % (backend.quote_name(self.klass._meta.db_table), 217 239 backend.quote_name(field.column))), sql, order) -
django/db/models/query.py
190 190 if kwarg_value is None: 191 191 continue 192 192 if kwarg == 'complex': 193 if not hasattr(kwarg_value, 'get_sql'): 194 raise TypeError, "got unknown query argument '%s'" % str(arg) 193 195 tables2, join_where2, where2, params2, table_count = kwarg_value.get_sql(opts, table_count) 194 196 tables.extend(tables2) 195 197 join_where.extend(join_where2) … … 212 214 else: 213 215 lookup_list = lookup_list[:-1] + [opts.pk.name, 'exact'] 214 216 if len(lookup_list) == 1: 215 _throw_bad_kwarg_error(kwarg)217 throw_bad_kwarg_error(kwarg) 216 218 lookup_type = lookup_list.pop() 217 219 current_opts = opts # We'll be overwriting this, so keep a reference to the original opts. 218 220 current_table_alias = current_opts.db_table -
tests/modeltests/or_lookups/models.py
54 54 >>> Article.objects.get_list(complex=(Q(pk=1) | Q(pk=2) | Q(pk=3))) 55 55 [Hello, Goodbye, Hello and goodbye] 56 56 57 >>> Article.objects.get_list(Q(headline__startswith='Hello')) 58 [Hello, Hello and goodbye] 59 60 >>> Article.objects.get_list(Q(headline__startswith='Hello'), Q(headline__contains='bye')) 61 [Hello and goodbye] 62 63 >>> Article.objects.get_list(Q(headline__startswith='Hello') & Q(headline__contains='bye')) 64 [Hello and goodbye] 65 66 >>> Article.objects.get_list(Q(headline__contains='bye'), headline__startswith='Hello') 67 [Hello and goodbye] 68 69 >>> Article.objects.get_list(Q(headline__contains='Hello') | Q(headline__contains='bye')) 70 [Hello, Goodbye, Hello and goodbye] 71 57 72 """