Changeset 6486
- Timestamp:
- 10/13/07 21:12:40 (9 months ago)
- Files:
-
- django/branches/queryset-refactor/django/db/models/base.py (modified) (1 diff)
- django/branches/queryset-refactor/django/db/models/query.py (modified) (8 diffs)
- django/branches/queryset-refactor/django/db/models/sql/datastructures.py (modified) (1 diff)
- django/branches/queryset-refactor/django/db/models/sql/query.py (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/queryset-refactor/django/db/models/base.py
r6382 r6486 339 339 qn = connection.ops.quote_name 340 340 op = is_next and '>' or '<' 341 where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \341 where = ['(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \ 342 342 (qn(field.column), op, qn(field.column), 343 qn(self._meta.db_table), qn(self._meta.pk.column), op) 343 qn(self._meta.db_table), qn(self._meta.pk.column), op)] 344 344 param = smart_str(getattr(self, field.attname)) 345 q = self.__class__._default_manager.filter(**kwargs).order_by((not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name) 346 q.extra(where=where, params=[param, param, 347 getattr(self, self._meta.pk.attname)]) 345 order_char = not is_next and '-' or '' 346 q = self.__class__._default_manager.filter(**kwargs).order_by( 347 order_char + field.name, order_char + self._meta.pk.name) 348 q = q.extra(where=where, params=[param, param, 349 getattr(self, self._meta.pk.attname)]) 348 350 try: 349 351 return q[0] django/branches/queryset-refactor/django/db/models/query.py
r6484 r6486 254 254 return self._clone(klass=ValuesQuerySet, _fields=fields) 255 255 256 # FIXME: Not converted yet!257 256 def dates(self, field_name, kind, order='ASC'): 258 257 """ … … 266 265 # Let the FieldDoesNotExist exception propagate. 267 266 field = self.model._meta.get_field(field_name, many_to_many=False) 268 assert isinstance(field, DateField), "%r isn't a DateField." % field_name 269 return self._clone(klass=DateQuerySet, _field=field, _kind=kind, _order=order) 267 assert isinstance(field, DateField), "%r isn't a DateField." \ 268 % field_name 269 return self._clone(klass=DateQuerySet, _field=field, _kind=kind, 270 _order=order) 270 271 271 272 ################################################################## … … 390 391 391 392 def iterator(self): 392 try: 393 select, sql, params = self._get_sql_clause() 394 except EmptyResultSet: 395 raise StopIteration 396 397 qn = connection.ops.quote_name 398 399 # self._select is a dictionary, and dictionaries' key order is 400 # undefined, so we convert it to a list of tuples. 401 extra_select = self._select.items() 393 extra_select = self.query.extra_select.keys() 394 extra_select.sort() 402 395 403 396 # Construct two objects -- fields and field_names. … … 407 400 if self._fields: 408 401 if not extra_select: 409 fields = [self.model._meta.get_field(f, many_to_many=False) for f in self._fields] 402 fields = [self.model._meta.get_field(f, many_to_many=False) 403 for f in self._fields] 410 404 field_names = self._fields 411 405 else: … … 414 408 for f in self._fields: 415 409 if f in [field.name for field in self.model._meta.fields]: 416 fields.append(self.model._meta.get_field(f, many_to_many=False)) 410 fields.append(self.model._meta.get_field(f, 411 many_to_many=False)) 417 412 field_names.append(f) 418 elif not self._select.has_key(f): 419 raise FieldDoesNotExist('%s has no field named %r' % (self.model._meta.object_name, f)) 413 elif not self.query.extra_select.has_key(f): 414 raise FieldDoesNotExist('%s has no field named %r' 415 % (self.model._meta.object_name, f)) 420 416 else: # Default to all fields. 421 417 fields = self.model._meta.fields 422 418 field_names = [f.attname for f in fields] 423 419 424 columns = [f.column for f in fields] 425 select = ['%s.%s' % (qn(self.model._meta.db_table), qn(c)) for c in columns] 420 self.query.add_local_columns([f.column for f in fields]) 426 421 if extra_select: 427 select.extend(['(%s) AS %s' % (quote_only_if_word(s[1]), qn(s[0])) for s in extra_select]) 428 field_names.extend([f[0] for f in extra_select]) 429 430 cursor = connection.cursor() 431 cursor.execute("SELECT " + (self._distinct and "DISTINCT " or "") + ",".join(select) + sql, params) 432 433 has_resolve_columns = hasattr(self, 'resolve_columns') 434 while 1: 435 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 436 if not rows: 437 raise StopIteration 438 for row in rows: 439 if has_resolve_columns: 440 row = self.resolve_columns(row, fields) 441 yield dict(zip(field_names, row)) 422 field_names.extend([f for f in extra_select]) 423 424 for row in self.query.results_iter(): 425 yield dict(zip(field_names, row)) 442 426 443 427 def _clone(self, klass=None, **kwargs): … … 448 432 class DateQuerySet(QuerySet): 449 433 def iterator(self): 450 from django.db.backends.util import typecast_timestamp 451 from django.db.models.fields import DateTimeField 452 453 qn = connection.ops.quote_name 454 self._order_by = () # Clear this because it'll mess things up otherwise. 434 self.query = self.query.clone(klass=sql.DateQuery) 435 self.query.select = [] 436 self.query.add_date_select(self._field.column, self._kind, self._order) 455 437 if self._field.null: 456 self._where.append('%s.%s IS NOT NULL' % \ 457 (qn(self.model._meta.db_table), qn(self._field.column))) 458 try: 459 select, sql, params = self._get_sql_clause() 460 except EmptyResultSet: 461 raise StopIteration 462 463 table_name = qn(self.model._meta.db_table) 464 field_name = qn(self._field.column) 465 466 if connection.features.allows_group_by_ordinal: 467 group_by = '1' 468 else: 469 group_by = connection.ops.date_trunc_sql(self._kind, '%s.%s' % (table_name, field_name)) 470 471 sql = 'SELECT %s %s GROUP BY %s ORDER BY 1 %s' % \ 472 (connection.ops.date_trunc_sql(self._kind, '%s.%s' % (qn(self.model._meta.db_table), 473 qn(self._field.column))), sql, group_by, self._order) 474 cursor = connection.cursor() 475 cursor.execute(sql, params) 476 477 has_resolve_columns = hasattr(self, 'resolve_columns') 478 needs_datetime_string_cast = connection.features.needs_datetime_string_cast 479 dates = [] 480 # It would be better to use self._field here instead of DateTimeField(), 481 # but in Oracle that will result in a list of datetime.date instead of 482 # datetime.datetime. 483 fields = [DateTimeField()] 484 while 1: 485 rows = cursor.fetchmany(GET_ITERATOR_CHUNK_SIZE) 486 if not rows: 487 return dates 488 for row in rows: 489 date = row[0] 490 if has_resolve_columns: 491 date = self.resolve_columns([date], fields)[0] 492 elif needs_datetime_string_cast: 493 date = typecast_timestamp(str(date)) 494 dates.append(date) 438 self.query.add_filter(('%s__isnull' % self._field.name, True)) 439 return self.query.results_iter() 495 440 496 441 def _clone(self, klass=None, **kwargs): … … 498 443 c._field = self._field 499 444 c._kind = self._kind 500 c._order = self._order501 445 return c 502 446 503 # XXX; Everything below here is done.504 447 class EmptyQuerySet(QuerySet): 505 448 def __init__(self, model=None): … … 517 460 c._result_cache = [] 518 461 return c 462 463 def iterator(self): 464 # This slightly odd construction is because we need an empty generator 465 # (it should raise StopIteration immediately). 466 yield iter([]).next() 519 467 520 468 # QOperator, QAnd and QOr are temporarily retained for backwards compatibility. django/branches/queryset-refactor/django/db/models/sql/datastructures.py
r6116 r6486 58 58 return 'COUNT(%s)' % col 59 59 60 class Date(object): 61 """ 62 Add a date selection column. 63 """ 64 def __init__(self, col, lookup_type, date_sql_func): 65 self.col = col 66 self.lookup_type = lookup_type 67 self.date_sql_func= date_sql_func 68 69 def relabel_aliases(self, change_map): 70 c = self.col 71 if isinstance(c, (list, tuple)): 72 self.col = (change_map.get(c[0], c[0]), c[1]) 73 74 def as_sql(self, quote_func=None): 75 if not quote_func: 76 quote_func = lambda x: x 77 if isinstance(self.col, (list, tuple)): 78 col = '%s.%s' % tuple([quote_func(c) for c in self.col]) 79 else: 80 col = self.col 81 return self.date_sql_func(self.lookup_type, col) 82 django/branches/queryset-refactor/django/db/models/sql/query.py
r6121 r6486 12 12 from django.utils import tree 13 13 from django.db.models.sql.where import WhereNode, AND, OR 14 from django.db.models.sql.datastructures import Count 15 from django.db.models.fields import FieldDoesNotExist 14 from django.db.models.sql.datastructures import Count, Date 15 from django.db.models.fields import FieldDoesNotExist, Field 16 16 from django.contrib.contenttypes import generic 17 17 from datastructures import EmptyResultSet … … 55 55 NONE = None 56 56 57 # FIXME: Add quote_name() calls around all the tables. 57 58 class Query(object): 58 59 """ … … 78 79 self.tables = [] # Aliases in the order they are created. 79 80 self.where = WhereNode(self) 81 self.group_by = [] 80 82 self.having = [] 81 self.group_by = []82 83 self.order_by = [] 83 84 self.low_mark, self.high_mark = 0, None # Used for offset/limit … … 104 105 return sql % params 105 106 106 def clone(self, **kwargs):107 def clone(self, klass=None, **kwargs): 107 108 """ 108 109 Creates a copy of the current instance. The 'kwargs' parameter can be 109 110 used by clients to update attributes after copying has taken place. 110 111 """ 111 obj = self.__class__(self.model, self.connection) 112 if not klass: 113 klass = self.__class__ 114 obj = klass(self.model, self.connection) 112 115 obj.table_map = self.table_map.copy() 113 116 obj.alias_map = copy.deepcopy(self.alias_map) … … 199 202 if where: 200 203 result.append('WHERE %s' % where) 201 result.append(' AND'.join(self.extra_where)) 204 if self.extra_where: 205 if not where: 206 result.append('WHERE') 207 else: 208 result.append('AND') 209 result.append(' AND'.join(self.extra_where)) 210 211 if self.group_by: 212 grouping = self.get_grouping() 213 result.append('GROUP BY %s' % ', '.join(grouping)) 202 214 203 215 ordering = self.get_ordering() … … 313 325 qn = self.connection.ops.quote_name 314 326 result = [] 315 if self.select :327 if self.select or self.extra_select: 316 328 for col in self.select: 317 329 if isinstance(col, (list, tuple)): 318 330 result.append('%s.%s' % (qn(col[0]), qn(col[1]))) 319 331 else: 320 result.append(col.as_sql( ))332 result.append(col.as_sql(quote_func=qn)) 321 333 else: 322 334 table_alias = self.tables[0] … … 332 344 return result 333 345 346 def get_grouping(self): 347 """ 348 Returns a tuple representing the SQL elements in the "group by" clause. 349 """ 350 qn = self.connection.ops.quote_name 351 result = [] 352 for col in self.group_by: 353 if isinstance(col, (list, tuple)): 354 result.append('%s.%s' % (qn(col[0]), qn(col[1]))) 355 elif hasattr(col, 'as_sql'): 356 result.append(col.as_sql(qn)) 357 else: 358 result.append(str(col)) 359 return result 360 334 361 def get_ordering(self): 335 362 """ … … 340 367 opts = self.model._meta 341 368 result = [] 342 for field in handle_legacy_orderlist(ordering):369 for field in ordering: 343 370 if field == '?': 344 371 result.append(self.connection.ops.random_function_sql()) 372 continue 373 if isinstance(field, int): 374 if field < 0: 375 order = 'DESC' 376 field = -field 377 else: 378 order = 'ASC' 379 result.append('%s %s' % (field, order)) 345 380 continue 346 381 if field[0] == '-': … … 684 719 self.low_mark, self.high_mark = 0, None 685 720 721 def can_filter(self): 722 """ 723 Returns True if adding filters to this instance is still possible. 724 725 Typically, this means no limits or offsets have been put on the results. 726 """ 727 return not (self.low_mark or self.high_mark) 728 729 def add_local_columns(self, columns): 730 """ 731 Adds the given column names to the select set, assuming they come from 732 the root model (the one given in self.model). 733 """ 734 table = self.model._meta.db_table 735 self.select.extend([(table, col) for col in columns]) 736 686 737 def add_ordering(self, *ordering): 687 738 """ 688 739 Adds items from the 'ordering' sequence to the query's "order by" 689 clause. 740 clause. These items are either field names (not column names) -- 741 possibly with a direction prefix ('-' or '?') -- or ordinals, 742 corresponding to column positions in the 'select' list. 690 743 """ 691 744 self.order_by.extend(ordering) … … 696 749 """ 697 750 self.order_by = [] 698 699 def can_filter(self):700 """701 Returns True if adding filters to this instance is still possible.702 703 Typically, this means no limits or offsets have been put on the results.704 """705 return not (self.low_mark or self.high_mark)706 751 707 752 def add_count_column(self): … … 714 759 if not self.distinct: 715 760 select = Count() 716 # Distinct handling is now done in Count(), so don't do it at this717 # level.718 self.distinct = False719 761 else: 720 762 select = Count((self.table_map[self.model._meta.db_table][0], 721 763 self.model._meta.pk.column), True) 764 # Distinct handling is done in Count(), so don't do it at this 765 # level. 766 self.distinct = False 722 767 self.select = [select] 723 768 self.extra_select = {} … … 874 919 self.do_query(self.model._meta.db_table, values, where) 875 920 921 class DateQuery(Query): 922 """ 923 A DateQuery is a normal query, except that it specifically selects a single 924 date field. This requires some special handling when converting the results 925 back to Python objects, so we put it in a separate class. 926 """ 927 def results_iter(self): 928 """ 929 Returns an iterator over the results from executing this query. 930 """ 931 resolve_columns = hasattr(self, 'resolve_columns') 932 if resolve_columns: 933 from django.db.models.fields import DateTimeField 934 fields = [DateTimeField()] 935 else: 936 from django.db.backends.util import typecast_timestamp 937 needs_string_cast = self.connection.features.needs_datetime_string_cast 938 939 for rows in self.execute_sql(MULTI): 940 for row in rows: 941 date = row[0] 942 if resolve_columns: 943 date = self.resolve_columns([date], fields)[0] 944 elif needs_string_cast: 945 date = typecast_timestamp(str(date)) 946 yield date 947 948 def add_date_select(self, column, lookup_type, order='ASC'): 949 """ 950 Converts the query into a date extraction query. 951 """ 952 alias = self.join((None, self.model._meta.db_table, None, None)) 953 select = Date((alias, column), lookup_type, 954 self.connection.ops.date_trunc_sql) 955 self.select = [select] 956 self.order_by = order == 'ASC' and [1] or [-1] 957 if self.connection.features.allows_group_by_ordinal: 958 self.group_by = [1] 959 else: 960 self.group_by = [select] 961 876 962 def find_field(name, field_list, related_query): 877 963 """
