#34921: Filtering an unbound DateTimeField with naive date crashes
-------------------------------------+-------------------------------------
Reporter: David Sanders | Owner: nobody
Type: Bug | Status: new
Component: Database layer | Version: dev
(models, ORM) |
Severity: Normal | Resolution:
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Description changed by David Sanders:
Old description:
> It's possible to crash the naive datetime warning in
> `DateTimeField.to_python()` by filtering an unbound datetime with a naive
> timstamp:
>
> {{{
> class EmptyModel(Model):
> pass
>
> EmptyModel.objects.annotate(unbound=Now()).filter(unbound__gte=date(2000,
> 1, 1))
> }}}
>
> The resulting exception is pasted below.
>
> The cause is the unsuccessful access of attribute `self.model` in
> `DateTimeField.to_python()`:
>
> {{{
> warnings.warn(
> "DateTimeField %s.%s received a naive datetime "
> "(%s) while time zone support is active."
> % (self.model.__name__, self.name, value),
> RuntimeWarning,
> )
> }}}
>
> `DateTime.get_prep_value()` handles this correctly by catching the
> attribute error raised and using the name "unbound" instead:
>
> {{{
> try:
> name = "%s.%s" % (self.model.__name__, self.name)
> except AttributeError:
> name = "(unbound)"
> warnings.warn(
> "DateTimeField %s received a naive datetime (%s)"
> " while time zone support is active." % (name, value),
> RuntimeWarning,
> )
> }}}
>
> Exception details:
>
> {{{
> path/to/django/db/models/query.py:1476: in filter
> return self._filter_or_exclude(False, args, kwargs)
> path/to/django/db/models/query.py:1494: in _filter_or_exclude
> clone._filter_or_exclude_inplace(negate, args, kwargs)
> path/to/django/db/models/query.py:1501: in _filter_or_exclude_inplace
> self._query.add_q(Q(*args, **kwargs))
> path/to/django/db/models/sql/query.py:1599: in add_q
> clause, _ = self._add_q(q_object, self.used_aliases)
> path/to/django/db/models/sql/query.py:1631: in _add_q
> child_clause, needed_inner = self.build_filter(
> path/to/django/db/models/sql/query.py:1499: in build_filter
> condition = self.build_lookup(lookups, reffed_expression, value)
> path/to/django/db/models/sql/query.py:1375: in build_lookup
> lookup = lookup_class(lhs, rhs)
> path/to/django/db/models/lookups.py:30: in __init__
> self.rhs = self.get_prep_lookup()
> path/to/django/db/models/lookups.py:88: in get_prep_lookup
> return self.lhs.output_field.get_prep_value(self.rhs)
> path/to/django/db/models/fields/__init__.py:1648: in get_prep_value
> value = super().get_prep_value(value)
> path/to/django/db/models/fields/__init__.py:1527: in get_prep_value
> return self.to_python(value)
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
>
> self = <django.db.models.fields.DateTimeField>, value =
> datetime.datetime(2000, 1, 1, 0, 0)
>
> def to_python(self, value):
> if value is None:
> return value
> if isinstance(value, datetime.datetime):
> return value
> if isinstance(value, datetime.date):
> value = datetime.datetime(value.year, value.month, value.day)
> if settings.USE_TZ:
> # For backwards compatibility, interpret naive datetimes
> in
> # local time. This won't work during DST change, but we
> can't
> # do much about it, so we let the exceptions percolate up
> the
> # call stack.
> warnings.warn(
> "DateTimeField %s.%s received a naive datetime "
> "(%s) while time zone support is active."
> > % (self.model.__name__, self.name, value),
> RuntimeWarning,
> )
> E AttributeError: 'DateTimeField' object has no attribute
> 'model'
>
> path/to/django/db/models/fields/__init__.py:1601: AttributeError
> }}}
New description:
It's possible to crash the naive datetime warning in
`DateTimeField.to_python()` by filtering an unbound datetime with a naive
`date`:
{{{
class EmptyModel(Model):
pass
EmptyModel.objects.annotate(unbound=Now()).filter(unbound__gte=date(2000,
1, 1))
}}}
The resulting exception is pasted below.
The cause is the unsuccessful access of attribute `self.model` in
`DateTimeField.to_python()`:
{{{
warnings.warn(
"DateTimeField %s.%s received a naive datetime "
"(%s) while time zone support is active."
% (self.model.__name__, self.name, value),
RuntimeWarning,
)
}}}
`DateTime.get_prep_value()` handles this correctly by catching the
attribute error raised and using the name "unbound" instead:
{{{
try:
name = "%s.%s" % (self.model.__name__, self.name)
except AttributeError:
name = "(unbound)"
warnings.warn(
"DateTimeField %s received a naive datetime (%s)"
" while time zone support is active." % (name, value),
RuntimeWarning,
)
}}}
Exception details:
{{{
path/to/django/db/models/query.py:1476: in filter
return self._filter_or_exclude(False, args, kwargs)
path/to/django/db/models/query.py:1494: in _filter_or_exclude
clone._filter_or_exclude_inplace(negate, args, kwargs)
path/to/django/db/models/query.py:1501: in _filter_or_exclude_inplace
self._query.add_q(Q(*args, **kwargs))
path/to/django/db/models/sql/query.py:1599: in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
path/to/django/db/models/sql/query.py:1631: in _add_q
child_clause, needed_inner = self.build_filter(
path/to/django/db/models/sql/query.py:1499: in build_filter
condition = self.build_lookup(lookups, reffed_expression, value)
path/to/django/db/models/sql/query.py:1375: in build_lookup
lookup = lookup_class(lhs, rhs)
path/to/django/db/models/lookups.py:30: in __init__
self.rhs = self.get_prep_lookup()
path/to/django/db/models/lookups.py:88: in get_prep_lookup
return self.lhs.output_field.get_prep_value(self.rhs)
path/to/django/db/models/fields/__init__.py:1648: in get_prep_value
value = super().get_prep_value(value)
path/to/django/db/models/fields/__init__.py:1527: in get_prep_value
return self.to_python(value)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <django.db.models.fields.DateTimeField>, value =
datetime.datetime(2000, 1, 1, 0, 0)
def to_python(self, value):
if value is None:
return value
if isinstance(value, datetime.datetime):
return value
if isinstance(value, datetime.date):
value = datetime.datetime(value.year, value.month, value.day)
if settings.USE_TZ:
# For backwards compatibility, interpret naive datetimes
in
# local time. This won't work during DST change, but we
can't
# do much about it, so we let the exceptions percolate up
the
# call stack.
warnings.warn(
"DateTimeField %s.%s received a naive datetime "
"(%s) while time zone support is active."
> % (self.model.__name__, self.name, value),
RuntimeWarning,
)
E AttributeError: 'DateTimeField' object has no attribute
'model'
path/to/django/db/models/fields/__init__.py:1601: AttributeError
}}}
--
--
Ticket URL: <https://code.djangoproject.com/ticket/34921#comment:2>
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 unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/0107018b56581910-fbc71b3c-9f53-4bdf-9770-c8530d930188-000000%40eu-central-1.amazonses.com.