Opened 7 months ago

Closed 7 months ago

Last modified 7 months ago

#34921 closed Bug (fixed)

Filtering an unbound DateTimeField with naive date crashes

Reported by: David Sanders Owned by: David Sanders
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by David Sanders)

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

Change History (6)

comment:1 by David Sanders, 7 months ago

PR to make warning same as get_prep_value(): https://github.com/django/django/pull/17399

comment:2 by David Sanders, 7 months ago

Description: modified (diff)

comment:3 by Mariusz Felisiak, 7 months ago

Has patch: set
Owner: changed from nobody to David Sanders
Status: newassigned
Triage Stage: UnreviewedAccepted

Thanks for the report.

comment:4 by Mariusz Felisiak, 7 months ago

Triage Stage: AcceptedReady for checkin

comment:5 by Mariusz Felisiak <felisiak.mariusz@…>, 7 months ago

Resolution: fixed
Status: assignedclosed

In b5311ee:

Fixed #34921 -- Fixed crash of warning for unbound naive datetimes.

comment:6 by Mariusz Felisiak <felisiak.mariusz@…>, 7 months ago

In 4dec7ede:

[5.0.x] Fixed #34921 -- Fixed crash of warning for unbound naive datetimes.

Backport of b5311ee23219cfb676e2e67667ecba1e5d363aa0 from main

Note: See TracTickets for help on using tickets.
Back to Top