#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.

Reply via email to