Ticket #17728: 17728-2.diff
File 17728-2.diff, 10.4 KB (added by , 13 years ago) |
---|
-
tests/modeltests/timezones/tests.py
25 25 from django.utils.unittest import skipIf, skipUnless 26 26 27 27 from .forms import EventForm, EventSplitForm, EventModelForm 28 from .models import Event, MaybeEvent, Timestamp28 from .models import Event, MaybeEvent, Session, SessionEvent, Timestamp 29 29 30 30 31 31 # These tests use the EAT (Eastern Africa Time) and ICT (Indochina Time) … … 231 231 'dt__max': datetime.datetime(2011, 9, 1, 23, 20, 20), 232 232 }) 233 233 234 def test_query_annotation(self): 235 # Only min and max make sense for datetimes. 236 morning = Session.objects.create(name='morning') 237 afternoon = Session.objects.create(name='afternoon') 238 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 23, 20, 20), session=afternoon) 239 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 13, 20, 30), session=afternoon) 240 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 3, 20, 40), session=morning) 241 morning_min_dt = datetime.datetime(2011, 9, 1, 3, 20, 40) 242 afternoon_min_dt = datetime.datetime(2011, 9, 1, 13, 20, 30) 243 self.assertQuerysetEqual( 244 Session.objects.annotate(dt=Min('events__dt')).order_by('dt'), 245 [morning_min_dt, afternoon_min_dt], 246 transform=lambda d: d.dt) 247 self.assertQuerysetEqual( 248 Session.objects.annotate(dt=Min('events__dt')).filter(dt__lt=afternoon_min_dt), 249 [morning_min_dt], 250 transform=lambda d: d.dt) 251 self.assertQuerysetEqual( 252 Session.objects.annotate(dt=Min('events__dt')).filter(dt__gte=afternoon_min_dt), 253 [afternoon_min_dt], 254 transform=lambda d: d.dt) 255 234 256 def test_query_dates(self): 235 257 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0)) 236 258 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 4, 30, 0)) … … 412 434 'dt__max': datetime.datetime(2011, 9, 1, 23, 20, 20, tzinfo=EAT), 413 435 }) 414 436 437 def test_query_annotation(self): 438 # Only min and max make sense for datetimes. 439 morning = Session.objects.create(name='morning') 440 afternoon = Session.objects.create(name='afternoon') 441 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 23, 20, 20, tzinfo=EAT), session=afternoon) 442 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT), session=afternoon) 443 SessionEvent.objects.create(dt=datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT), session=morning) 444 morning_min_dt = datetime.datetime(2011, 9, 1, 3, 20, 40, tzinfo=EAT) 445 afternoon_min_dt = datetime.datetime(2011, 9, 1, 13, 20, 30, tzinfo=EAT) 446 self.assertQuerysetEqual( 447 Session.objects.annotate(dt=Min('events__dt')).order_by('dt'), 448 [morning_min_dt, afternoon_min_dt], 449 transform=lambda d: d.dt) 450 self.assertQuerysetEqual( 451 Session.objects.annotate(dt=Min('events__dt')).filter(dt__lt=afternoon_min_dt), 452 [morning_min_dt], 453 transform=lambda d: d.dt) 454 self.assertQuerysetEqual( 455 Session.objects.annotate(dt=Min('events__dt')).filter(dt__gte=afternoon_min_dt), 456 [afternoon_min_dt], 457 transform=lambda d: d.dt) 458 415 459 def test_query_dates(self): 416 460 # Same comment as in test_query_date_related_filters. 417 461 Event.objects.create(dt=datetime.datetime(2011, 1, 1, 1, 30, 0, tzinfo=EAT)) -
tests/modeltests/timezones/models.py
6 6 class MaybeEvent(models.Model): 7 7 dt = models.DateTimeField(blank=True, null=True) 8 8 9 class Session(models.Model): 10 name = models.CharField(max_length=20) 11 12 class SessionEvent(models.Model): 13 dt = models.DateTimeField() 14 session = models.ForeignKey(Session, related_name='events') 15 9 16 class Timestamp(models.Model): 10 17 created = models.DateTimeField(auto_now_add=True) 11 18 updated = models.DateTimeField(auto_now=True) -
django/db/models/sql/aggregates.py
2 2 Classes to represent the default SQL aggregate functions 3 3 """ 4 4 5 class AggregateField(object): 6 """An internal field mockup used to identify aggregates in the 7 data-conversion parts of the database backend. 8 """ 9 def __init__(self, internal_type): 10 self.internal_type = internal_type 5 from django.db.models.fields import IntegerField, FloatField 11 6 12 def get_internal_type(self): 13 return self.internal_type 7 # Fake fields used to identify aggregate types in data-conversion operations. 8 ordinal_aggregate_field = IntegerField() 9 computed_aggregate_field = FloatField() 14 10 15 ordinal_aggregate_field = AggregateField('IntegerField')16 computed_aggregate_field = AggregateField('FloatField')17 18 11 class Aggregate(object): 19 12 """ 20 13 Default SQL Aggregate. -
django/db/models/sql/where.py
10 10 from django.utils import tree 11 11 from django.db.models.fields import Field 12 12 from django.db.models.sql.datastructures import EmptyResultSet, FullResultSet 13 from django.db.models.sql.aggregates import Aggregate 13 14 14 15 # Connection types 15 16 AND = 'AND' … … 30 31 the correct SQL). 31 32 32 33 The children in this tree are usually either Q-like objects or lists of 33 [table_alias, field_name, db_type, lookup_type, value_annotation, 34 params]. However, a child could also be any class with as_sql() and 35 relabel_aliases() methods. 34 [table_alias, field_name, db_type, lookup_type, value_annotation, params]. 35 However, a child could also be any class with as_sql() and relabel_aliases() methods. 36 36 """ 37 37 default = AND 38 38 … … 54 54 # emptiness and transform any non-empty values correctly. 55 55 value = list(value) 56 56 57 # The " annotation" parameter is used to pass auxilliary information57 # The "value_annotation" parameter is used to pass auxilliary information 58 58 # about the value(s) to the query construction. Specifically, datetime 59 59 # and empty values need special handling. Other types could be used 60 60 # here in the future (using Python types is suggested for consistency). 61 61 if isinstance(value, datetime.datetime): 62 annotation = datetime.datetime62 value_annotation = datetime.datetime 63 63 elif hasattr(value, 'value_annotation'): 64 annotation = value.value_annotation64 value_annotation = value.value_annotation 65 65 else: 66 annotation = bool(value)66 value_annotation = bool(value) 67 67 68 68 if hasattr(obj, "prepare"): 69 69 value = obj.prepare(lookup_type, value) 70 super(WhereNode, self).add((obj, lookup_type, annotation, value),71 connector)72 return73 70 74 super(WhereNode, self).add( (obj, lookup_type, annotation, value),75 connector)71 super(WhereNode, self).add( 72 (obj, lookup_type, value_annotation, value), connector) 76 73 77 74 def as_sql(self, qn, connection): 78 75 """ … … 133 130 def make_atom(self, child, qn, connection): 134 131 """ 135 132 Turn a tuple (table_alias, column_name, db_type, lookup_type, 136 value_annot , params) into valid SQL.133 value_annotation, params) into valid SQL. 137 134 138 135 Returns the string for the SQL fragment and the parameters to use for 139 136 it. 140 137 """ 141 lvalue, lookup_type, value_annot , params_or_value = child142 if hasattr(lvalue, 'process'):138 lvalue, lookup_type, value_annotation, params_or_value = child 139 if isinstance(lvalue, Constraint): 143 140 try: 144 141 lvalue, params = lvalue.process(lookup_type, params_or_value, connection) 145 142 except EmptyShortCircuit: 146 143 raise EmptyResultSet 144 elif isinstance(lvalue, Aggregate): 145 params = lvalue.field.get_db_prep_lookup(lookup_type, params_or_value, connection) 147 146 else: 148 params = Field().get_db_prep_lookup(lookup_type, params_or_value, 149 connection=connection, prepared=True) 147 raise TypeError("'make_atom' expects a Constraint or an Aggregate " 148 "as the first item of its 'child' argument.") 149 150 150 if isinstance(lvalue, tuple): 151 151 # A direct database column lookup. 152 152 field_sql = self.sql_for_columns(lvalue, qn, connection) … … 154 154 # A smart object with an as_sql() method. 155 155 field_sql = lvalue.as_sql(qn, connection) 156 156 157 if value_annot is datetime.datetime:157 if value_annotation is datetime.datetime: 158 158 cast_sql = connection.ops.datetime_cast_sql() 159 159 else: 160 160 cast_sql = '%s' … … 168 168 if (len(params) == 1 and params[0] == '' and lookup_type == 'exact' 169 169 and connection.features.interprets_empty_strings_as_nulls): 170 170 lookup_type = 'isnull' 171 value_annot = True171 value_annotation = True 172 172 173 173 if lookup_type in connection.operators: 174 174 format = "%s %%s %%s" % (connection.ops.lookup_cast(lookup_type),) … … 177 177 extra), params) 178 178 179 179 if lookup_type == 'in': 180 if not value_annot :180 if not value_annotation: 181 181 raise EmptyResultSet 182 182 if extra: 183 183 return ('%s IN %s' % (field_sql, extra), params) … … 206 206 params) 207 207 elif lookup_type == 'isnull': 208 208 return ('%s IS %sNULL' % (field_sql, 209 (not value_annot and 'NOT ' or '')), ())209 (not value_annotation and 'NOT ' or '')), ()) 210 210 elif lookup_type == 'search': 211 211 return (connection.ops.fulltext_search_sql(field_sql), params) 212 212 elif lookup_type in ('regex', 'iregex'):