Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#19537 closed Bug (fixed)

Widget CheckboxInput show_hidden_initial _has_changed bug

Reported by: dibrovsd@… Owned by: claudep
Component: Forms Version: 1.4
Severity: Normal Keywords: show_hidden_initial
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 claudep)

django.forms.CheckboxInput have method

def _has_changed(self, initial, data):
    # Sometimes data or initial could be None or u'' which should be the
    # same thing as False.
    return bool(initial) != bool(data)

initial may be u'False' or u'True'
bool(initial) always return True for unicode len(initial) > 1

if initial == u'False' and data == u'on' always return False
bool(u'False') = True
bool(u'on') = True
path:

def _has_changed(self, initial, data):
    initial = True if initial == u'True' else False
    return initial != bool(data)

Attachments (1)

19537-1.diff (1.2 KB) - added by claudep 3 years ago.

Download all attachments as: .zip

Change History (11)

comment:1 Changed 3 years ago by claudep

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to invalid
  • Status changed from new to closed

By default, any non-empty string is considered as a True value, even "False". You should fix the initial value passed to the form in your code.

comment:2 Changed 3 years ago by dibrovsd@…

my initial data is bool type

ok full test case is

# View is

def document(request, project_id, document_id):
	u''' Карточка документа '''

	class TestForm(forms.Form):
		bool_field = forms.BooleanField(show_hidden_initial=True, required=False)
		
	if request.method == 'POST':
		f = TestForm(data=request.POST)
		if f.is_valid():
			print f.changed_data
	else:
		# initial is bool type not unicode!
		f = TestForm(initial={u'bool_field':False})
	
	return render(request, 'docflow/document.html', {'form':f})

# Template is

<html>
<body>
<form method='post'>
	{% csrf_token %}
	{{form.as_p}}
	<input type='submit'>					
</form>
</body>
</html>		

# action1

  • load page
  • checkbox is not cheched by default
  • check checkbox and send form (change!)
  • print to console is "[]" CheckboxInput._has_changed arg "initial" == u'False' (not bool False) bool(u'False') == True of course,
    but arg "data" == u'on' bool(u'on') == True too
    True != True => False

# action2

  • load page
  • checkbox is not cheched by default
  • send form
  • print to console is "bool_field?" CheckboxInput._has_changed arg "initial" == u'False' too bool(u'False') => True,
    but arg "data" == False bool(False) == False
    widget _has_changed => true
Last edited 3 years ago by claudep (previous) (diff)

comment:3 Changed 3 years ago by dibrovsd@…

  • Component changed from Uncategorized to Forms
  • Resolution invalid deleted
  • Status changed from closed to new

reopen tiket

comment:4 Changed 3 years ago by claudep

  • Description modified (diff)

Changed 3 years ago by claudep

comment:5 Changed 3 years ago by claudep

  • Owner changed from nobody to claudep
  • Status changed from new to assigned
  • Triage Stage changed from Unreviewed to Accepted

Sorry, I didn't get it at first, thanks for giving more details. Please review the attached patch.

comment:6 Changed 3 years ago by dibrovsd@…

Checkbox patch is great!
but DateField is too

i set

  • DATE_INPUT_FORMATS = ('%d.%m.%Y',)
  • input_formats=('%d.%m.%Y',) in field
  • format='%d.%m.%Y' in widget

:-)

but hidden initial input value is u'2012-12-13' (not 13.12.2012)

in django.forms.DateInput._has_changed

# If our field has show_hidden_initial=True, initial will be a string
# formatted by HiddenInput using formats.localize_input, which is not
# necessarily the format used for this widget. Attempt to convert it.
try:
    input_format = formats.get_format('DATE_INPUT_FORMATS')[0]
    initial = datetime.datetime.strptime(initial, input_format).date()
except (TypeError, ValueError):
    pass
return super(DateInput, self)._has_changed(self._format_value(initial), data)

step by step in function

  1. formats.get_format('DATE_INPUT_FORMATS')[0] return %d.%m.%Y

but is not work for initial hidden value u'2012-12-13'
Exception pass
and initial stay u'2012-12-13'

  1. datetime.datetime.strptime(initial, input_format).date() fails

and initial stay u'2012-12-13'

  1. self._format_value(initial) return initial

self.manual_format = True
value not has attr strftime (value is unicode)
and initial stay u'2012-12-13'

  1. super(DateInput, self)._has_changed(u'2012-12-13', u'13.12.2012') return True (as string, initial and data not equal)

problem is format for input hidden initial

comment:7 Changed 3 years ago by dibrovsd@…

fix

class DateInput(forms.DateInput):
	u''' Исправление 
	https://code.djangoproject.com/ticket/19537
	'''
	
	def _has_changed(self, initial, data):		
		
		# if format initial value fixed
		try:
			input_format = formats.get_format('DATE_INPUT_FORMATS')[0]
			initial = datetime.datetime.strptime(initial, input_format).date()
		except (TypeError, ValueError):
			pass
		
		# if convert Attempt fails, try convert in format '%Y-%m-%d'
		if type(initial) == unicode: 
			try:
				initial = datetime.datetime.strptime(initial, '%Y-%m-%d').date()
			except (TypeError, ValueError):
				pass
		
		return super(DateInput, self)._has_changed(self._format_value(initial), data)

but it's dirty
need to change the format initial input

comment:8 Changed 3 years ago by claudep

  • Triage Stage changed from Accepted to Ready for checkin

OK, let's focus on CheckboxInput in this ticket. What you describe has already been reported in #18777. One thing at a time :-)

comment:9 Changed 3 years ago by Claude Paroz <claude@…>

  • Resolution set to fixed
  • Status changed from assigned to closed

In d11038acb2ea2f59a1d00a41b553f578b5f2c59c:

Fixed #19537 -- Made CheckboxInput._has_changed handle 'False' string

Thanks dibrovsd@… for the report.

comment:10 Changed 3 years ago by Claude Paroz <claude@…>

In 814c3b2e2a8da001af38f679ed2334239150a975:

[1.5.x] Fixed #19537 -- Made CheckboxInput._has_changed handle 'False' string

Thanks dibrovsd@… for the report.
Backport of d11038acb2 from master.

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