Message info
 
To: From:Django Subject:[Django] #17728: Filtering of annotated querysets broken with timezone-aware datetimes Date:Sun, 19 Feb 2012 21:09:02 -0000
 

#17728: Filtering of annotated querysets broken with timezone-aware datetimes
----------------------------------------------+------------------------
Reporter: gg | Owner: nobody
Type: Bug | Status: new
Component: Database layer (models, ORM) | Version: 1.4-beta-1
Severity: Normal | Keywords: regression
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
----------------------------------------------+------------------------
There appears to be a regression with timezone-aware datetimes that causes
them to not match "exact" queries properly when added as an annotation.

This is easiest explained with an example. Say we have a series of
"events" which are grouped into "sessions". We wish to find the start time
of the session (i.e. the time of the session's earliest event)

models.py:

{{{
from django.db import models

from django.contrib.auth.models import User

class Event(models.Model):
time = models.DateTimeField()
session = models.ForeignKey('Session', related_name='events',
null=True)

class Session(models.Model):
user = models.ForeignKey(User, related_name='km_sessions', null=True)

}}}


With USE_TZ = False (or with Django 1.3) it works as expected:


{{{
>>> from datetime import datetime
>>> from django.db import models
>>> from django.conf import settings
>>> print settings.USE_TZ
False
>>> from aggregate_fields.models import Session, Event
>>> now = datetime.now()
>>> s = Session.objects.create()
>>> e = Event.objects.create(time=now, session=s)
>>> now_tz = Event.objects.get(pk=e.pk).time # ensure we're querying with
the as-saved datetime
>>> now == now_tz # timezone are disabled, so these should be equivalent
True
>>>
Session.objects.annotate(start=models.Min('events__time')).filter(start=now_tz)
[<Session: Session object>]
>>> now_tz in
Session.objects.annotate(start=models.Min('events__time')).values_list('start',
flat=True)
True
>>>
Session.objects.annotate(start=models.Min('events__time')).filter(start=now_tz).count()
1
>>> Session.objects.annotate(start=models.Min('events__time')).count()
1
>>>
Session.objects.annotate(start=models.Min('events__time')).filter(start__lt=now_tz).count()
0
>>> Event.objects.filter(time=now_tz).count()
1
>>> Event.objects.get(time=now_tz)
<Event: Event object>
}}}

But with USE_TZ = False the results are inconsistent:

{{{
>>> from datetime import datetime
>>> from django.db import models
>>> from django.conf import settings
>>> print settings.USE_TZ
True
>>> from aggregate_fields.models import Session, Event
>>> now = datetime.now()
>>> s = Session.objects.create()
>>> e = Event.objects.create(time=now, session=s)
RuntimeWarning: DateTimeField received a naive datetime (2012-02-19
15:03:55.892547) while time zone support is active.
RuntimeWarning)
>>> now_tz = Event.objects.get(pk=e.pk).time # ensure we're querying with
the timezone-aware datetime
>>> now == now_tz # these shouldn't be comparable
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>>
Session.objects.annotate(start=models.Min('events__time')).filter(start=now_tz)
[]
>>> now_tz in
Session.objects.annotate(start=models.Min('events__time')).values_list('start',
flat=True)
True
>>>
Session.objects.annotate(start=models.Min('events__time')).filter(start=now_tz).count()
0
>>> Session.objects.annotate(start=models.Min('events__time')).count()
1
>>>
Session.objects.annotate(start=models.Min('events__time')).filter(start__lt=now_tz).count()
1
>>> Event.objects.filter(time=now_tz).count()
1
>>> Event.objects.get(time=now_tz)
<Event: Event object>
}}}

When the QuerySet is annotated with the start time, it seems to not use
the timezone in the subsequent filtering, though it is present when the
list of values is reconstituted as Python objects.

These tests were done on SQLite, in case this is a databse-specific
problem. I don't have another DB easily accessible to me at the moment,
but I can set up a test later, if needed.

--
Ticket URL: <https://code.djangoproject.com/ticket/17728>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

--
You received this message because you are subscribed to the Google Groups "Django updates" group.
To post to this group, send email to django-updates@googlegroups.com.
To unsubscribe from this group, send email to django-updates+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-updates?hl=en.