Code

Opened 15 months ago

Closed 15 months ago

Last modified 11 months ago

#19611 closed Bug (duplicate)

User Admin breaks on submit with form validation error

Reported by: gcc Owned by: nobody
Component: contrib.auth Version: 1.5
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: yes Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

Internal Server Error: /admin/users/ischooluser/4/
...
  File "/home/installuser/Dropbox/projects/ischool/user_manager/django/django-1.5/django/utils/encoding.py", line 99, in force_text
    s = s.__unicode__()
  File "/home/installuser/Dropbox/projects/ischool/user_manager/django/django-1.5/django/forms/forms.py", line 411, in __str__
    return self.as_widget()
  File "/home/installuser/Dropbox/projects/ischool/user_manager/django/django-1.5/django/forms/forms.py", line 458, in as_widget
    return widget.render(name, self.value(), attrs=attrs)
  File "/home/installuser/Dropbox/projects/ischool/user_manager/django/django-1.5/django/contrib/auth/forms.py", line 34, in render
    hasher = identify_hasher(encoded)
  File "/home/installuser/Dropbox/projects/ischool/user_manager/django/django-1.5/django/contrib/auth/hashers.py", line 135, in identify_hasher
    if len(encoded) == 32 and '$' not in encoded:
Exception: Failed to render template: admin/change_form.html: Failed to render template: admin/includes/fieldset.html: object of type 'NoneType' has no len()

This happens when you click the Save button on the user edit form, but the form doesn't validate, so it tries to display again.

ReadOnlyPasswordHashWidget doesn't include any hidden fields, so there's no data bound to the field, but the form is still bound (because this is a POST request), so ReadOnlyPasswordHashField's bound_data returns None instead of the current password value:

> /home/installuser/Dropbox/projects/ischool/user_manager/django/django-1.5/django/contrib/auth/forms.py(32)render()
-> if encoded == '' or encoded == UNUSABLE_PASSWORD:
(Pdb) p encoded
None
(Pdb) up
> /home/installuser/Dropbox/projects/ischool/user_manager/django/django-1.5/django/forms/forms.py(458)as_widget()
-> return widget.render(name, self.value(), attrs=attrs)
(Pdb) l
453  	
454  	        if not only_initial:
455  	            name = self.html_name
456  	        else:
457  	            name = self.html_initial_name
458  ->	        return widget.render(name, self.value(), attrs=attrs)
459  	
460  	    def as_text(self, attrs=None, **kwargs):
461  	        """
462  	        Returns a string of HTML for representing this as an <input type="text">.
463  	        """
(Pdb) p self
<django.forms.forms.BoundField object at 0xb2d7f56c>
<bound method BoundField.value of <django.forms.forms.BoundField object at 0xb2d7f56c>>
(Pdb) p self.form.is_bound
True
(Pdb) p self.form.data
<QueryDict: {u'username': [u'smith'], u'first_name': [u''], u'last_name': [u''], u'account_type': [u''], u'_save': [u'Save'], u'last_login_0': [u'2012-01-24'], u'is_active': [u'on'], u'initial-date_joined_1': [u'11:44:56'], u'initial-date_joined_0': [u'2012-01-12'], u'last_login_1': [u'10:36:09'], u'is_staff': [u'on'], u'date_joined_0': [u'2012-01-12'], u'date_joined_1': [u'11:44:56'], u'groups': [u'2'], u'csrfmiddlewaretoken': [u'40e524bcd2d4864f044fe107266d55ba'], u'email': [u'john@smithy.example.com'], u'initial-last_login_0': [u'2012-01-24'], u'initial-last_login_1': [u'10:36:09']}>
(Pdb) p self.name
'password'
(Pdb) p self.form.initial
{'username': u'smith', 'first_name': u'', 'last_name': u'', 'account_type': 1, 'is_active': True, 'is_superuser': False, 'is_staff': True, 'last_login': datetime.datetime(2012, 1, 24, 8, 36, 9, tzinfo=<UTC>), 'groups': [2], 'user_permissions': [], 'password': u'sha1$03d63$4ae1e7f3426c5c8bb4e008dea8d178f88a0c62ed', 'email': u'john@smithy.example.com', 'date_joined': datetime.datetime(2012, 1, 12, 9, 44, 56, tzinfo=<UTC>)}
(Pdb) p self.form.initial.get('password')
u'sha1$03d63$4ae1e7f3426c5c8bb4e008dea8d178f88a0c62ed'
(Pdb) p self.field.bound_data
<bound method ReadOnlyPasswordHashField.bound_data of <django.contrib.auth.forms.ReadOnlyPasswordHashField object at 0xb418672c>>
(Pdb) p self.field.bound_data(self.data, self.form.initial.get(self.name, self.field.initial))
None
(Pdb) p self.data
None
(Pdb) p self.form.initial.get(self.name, self.field.initial)
u'sha1$03d63$4ae1e7f3426c5c8bb4e008dea8d178f88a0c62ed'
(Pdb) c

Since this widget has no input fields, and therefore sends no data on POST, I propose modifying it to always return the initial data:

diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py
index 9279c52..8246a3b 100644
--- a/django/contrib/auth/forms.py
+++ b/django/contrib/auth/forms.py
@@ -52,6 +54,13 @@ class ReadOnlyPasswordHashField(forms.Field):
         kwargs.setdefault("required", False)
         super(ReadOnlyPasswordHashField, self).__init__(*args, **kwargs)
 
+    def bound_data(self, data, initial):
+        """
+        This widget has no fields, so data will always be None, so return
+        the initial value always.
+        """
+        return initial
+
 
 class UserCreationForm(forms.ModelForm):
     """

Attachments (0)

Change History (3)

comment:1 Changed 15 months ago by slurms

  • Easy pickings set
  • Needs documentation unset
  • Needs tests set
  • Patch needs improvement unset

Could you provide an example configuration to reproduce the error with? I can't seem to reproduce this on current Django master.

comment:2 Changed 15 months ago by anonymous

  • Resolution set to duplicate
  • Status changed from new to closed

Duplicate of #19349

comment:3 Changed 11 months ago by anonymous

  • Version changed from 1.4 to 1.5

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.