Opened 11 years ago

Closed 11 years ago

Last modified 11 years ago

#19537 closed Bug (fixed)

Widget CheckboxInput show_hidden_initial _has_changed bug

Reported by: dibrovsd@… Owned by: Claude Paroz
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 Claude Paroz)

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 Claude Paroz 11 years ago.

Download all attachments as: .zip

Change History (11)

comment:1 by Claude Paroz, 11 years ago

Resolution: invalid
Status: newclosed

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 by dibrovsd@…, 11 years ago

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 11 years ago by Claude Paroz (previous) (diff)

comment:3 by dibrovsd@…, 11 years ago

Component: UncategorizedForms
Resolution: invalid
Status: closednew

reopen tiket

comment:4 by Claude Paroz, 11 years ago

Description: modified (diff)

by Claude Paroz, 11 years ago

Attachment: 19537-1.diff added

comment:5 by Claude Paroz, 11 years ago

Owner: changed from nobody to Claude Paroz
Status: newassigned
Triage Stage: UnreviewedAccepted

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

comment:6 by dibrovsd@…, 11 years ago

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 by dibrovsd@…, 11 years ago

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 by Claude Paroz, 11 years ago

Triage Stage: AcceptedReady 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 by Claude Paroz <claude@…>, 11 years ago

Resolution: fixed
Status: assignedclosed

In d11038acb2ea2f59a1d00a41b553f578b5f2c59c:

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

Thanks dibrovsd@… for the report.

comment:10 by Claude Paroz <claude@…>, 11 years ago

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