Opened 5 years ago

Last modified 5 years ago

#30758 closed Bug

Postgres DateTimeRangeField crash in django admin (AttributeError: 'builtin_function_or_method' object has no attribute 'strip') — at Initial Version

Reported by: yeppus Owned by:
Component: contrib.postgres Version: dev
Severity: Normal Keywords: DateTimeRangeField
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

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

Code highlighting:

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

Code highlighting:

  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

Code highlighting:

  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()

Change History (0)

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