﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
30758	DateTimeRangeField with default crashes in django admin (object has no attribute 'strip').	yeppus	Nasir Hussain	"When trying to save an object that has a DateTimeRangeField in django admin the following error occurs:
AttributeError: 'builtin_function_or_method' object has no attribute 'strip'

When trying to determine if the value has changed it, maybe accidentally, assigns initial value the function ""lower"" instead of the value.

Later it tries to run .strip() on the function.

This all worked in django 1.11 and I can not find any mentioned of changed behaviour for Django 2.2.


**django/contrib/postgres/forms/ranges.py: 101**
{{{
#!div style=""font-size: 80%""
Code highlighting:
  {{{#!python
  class RangeWidget(MultiWidget):
    def __init__(self, base_widget, attrs=None):
        widgets = (base_widget, base_widget)
        super().__init__(widgets, attrs)

    def decompress(self, value):
        if value:
            return (value.lower, value.upper) ### <<-- RETURNS CALLABLE, NOT VALUE
        return (None, None)
  }}}
}}}

**django/forms/fields.py: 1060**
{{{
#!div style=""font-size: 80%""
Code highlighting:
  {{{#!python
    def has_changed(self, initial, data):
        if self.disabled:
            return False
        if initial is None:
            initial = ['' for x in range(0, len(data))]
        else:
            if not isinstance(initial, list):
                initial = self.widget.decompress(initial) ### <<-- RECEIVES CALLABLE, NOT VALUE
        for field, initial, data in zip(self.fields, initial, data):
            try:
                initial = field.to_python(initial) ### <<-- TRIES to_python with CALLABLE
            except ValidationError:
                return True
            if field.has_changed(initial, data):
                return True
        return False
  }}}
}}}

**django/forms/fields.py: 450**
{{{
#!div style=""font-size: 80%""
Code highlighting:
  {{{#!python
    def to_python(self, value):
        """"""
        Validate that the input can be converted to a datetime. Return a
        Python datetime.datetime object.
        """"""
        if value in self.empty_values:
            return None
        if isinstance(value, datetime.datetime):
            return from_current_timezone(value)
        if isinstance(value, datetime.date):
            result = datetime.datetime(value.year, value.month, value.day)
            return from_current_timezone(result)
        result = super().to_python(value) ### <<-- ENDS UP HERE SENDING CALLABLE TO PARENT
        return from_current_timezone(result)
  }}}
}}}

BaseTemporalField.to_python expects a string and runs .strip() which generates AttributeError and crashes.

{{{
Traceback (most recent call last):
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/core/handlers/exception.py"", line 34, in inner
    response = get_response(request)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/core/handlers/base.py"", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/core/handlers/base.py"", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/contrib/admin/options.py"", line 606, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/utils/decorators.py"", line 142, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/views/decorators/cache.py"", line 44, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/contrib/admin/sites.py"", line 223, in inner
    return view(request, *args, **kwargs)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/contrib/admin/options.py"", line 1637, in change_view
    return self.changeform_view(request, object_id, form_url, extra_context)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/utils/decorators.py"", line 45, in _wrapper
    return bound_method(*args, **kwargs)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/utils/decorators.py"", line 142, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/contrib/admin/options.py"", line 1522, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/contrib/admin/options.py"", line 1560, in _changeform_view
    if all_valid(formsets) and form_validated:
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/forms/formsets.py"", line 448, in all_valid
    valid &= formset.is_valid()
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/forms/formsets.py"", line 301, in is_valid
    self.errors
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/forms/formsets.py"", line 281, in errors
    self.full_clean()
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/forms/formsets.py"", line 325, in full_clean
    if not form.has_changed() and i >= self.initial_form_count():
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/contrib/admin/options.py"", line 2111, in has_changed
    return super().has_changed()
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/forms/forms.py"", line 434, in has_changed
    return bool(self.changed_data)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/utils/functional.py"", line 80, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/forms/forms.py"", line 456, in changed_data
    if field.has_changed(initial_value, data_value):
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/forms/fields.py"", line 1070, in has_changed
    initial = field.to_python(initial)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/forms/fields.py"", line 462, in to_python
    result = super().to_python(value)
  File ""/Users/joakim/.pyenv/versions/3.5.2/lib/python3.5/site-packages/django/forms/fields.py"", line 379, in to_python
    value = value.strip()
}}}"	Bug	closed	contrib.postgres	dev	Normal	fixed	DateTimeRangeField		Accepted	1	0	0	0	0	0
