[Django] #27111: django.contrib.auth.forms.UserCreationForm.__init__ method expects USERNAME_FIELD to be in self.fields

28 views
Skip to first unread message

Django

unread,
Aug 23, 2016, 9:36:18 AM8/23/16
to django-...@googlegroups.com
#27111: django.contrib.auth.forms.UserCreationForm.__init__ method expects
USERNAME_FIELD to be in self.fields
-------------------------+-------------------------------------------------
Reporter: | Owner: nobody
petercampbell |
Type: Bug | Status: new
Component: Forms | Version: 1.10
Severity: Normal | Keywords: custom user, django admin,
Triage Stage: | UserCreationForm
Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
-------------------------+-------------------------------------------------
Between the latest 1.9.x release and 1.10 release the following method was
added to django.contrib.auth.forms.UserCreationForm lines 95-97

{{{#!python
def __init__(self, *args, **kwargs):
super(UserCreationForm, self).__init__(*args, **kwargs)
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus':
''})
}}}

which sets the username field to autofocus when the form is rendered.

This is quite probably a very specific use case but in my current project
I am subclassing from AbstractUser to create my own custom user:
{{{#!python
class User(AbstractBaseUser, PermissionsMixin):
"""
A custom user
"""
uuid = models.UUIDField(
_('UUID'),
max_length=36,
unique=True,
help_text=_('The unique identifier used to login to the
system.')
)
...
USERNAME_FIELD = 'uuid'
}}}
Note that this project uses a uuid field as its username field. This
project will only enable internal and external systems to connect to it
via an API (DRF) so authentication will be token based using the username
and associated password as the entry point into the system. As such I do
not want django usernames to be created manually, instead creating them
automatically as the user object is saved. The exact method of user
creation may vary but for this particular issue I am focusing on
subclassing the UserCreationForm:
{{{#!python
import uuid

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
from django.contrib.auth.forms import UserCreationForm as
DjangoUserCreationForm
from django.utils.translation import ugettext_lazy as _

from .models import User


class UserCreationForm(DjangoUserCreationForm):
"""
Custom user creation form enables the password to be set but
handles the uuid creation internally on save.
"""
class Meta(DjangoUserCreationForm.Meta):
model = User
fields = ('description',)

def save(self, commit=True):
user = super().save(commit=False)
user.uuid = uuid.uuid4()
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user


class UserAdmin(DjangoUserAdmin):
add_form = UserCreationForm
fieldsets = (
(None, {'fields': ['password', 'description']}),
(_('Permissions'), {'fields': ('is_active', 'is_staff',
'is_superuser',
'groups',
'user_permissions')}),
(_('Important dates'), {'fields': ('last_login',
'date_joined')}),
)
add_fieldsets = (
(
None, {
'classes': ('wide',),
'fields': ('password1', 'password2')
}
),
)
list_display = ('uuid', 'description', 'is_active', 'is_staff',
'is_superuser')
search_fields = ('uuid',)
ordering = ('uuid',)

admin.site.register(User, UserAdmin)
}}}
Note in my subclassed UserCreationForm.save method I set the username
value to a newly created uuid and in my subclassed UserAdmin class the
only fields available for creation are password1 and password2,
effectively disabling username input.

Going back to the __init__ method above and in this specific case in the
admin console, attempting to load the user create form results in the
USERNAME_FIELD being inaccessible (in fact the fields attribute is also
unavailable at this point), resulting in the following error:

''KeyError at /admin/users/user/add/''

//'uuid'//

which points directly to this line
(django.contrib.auth.forms.UserCreationForm.__init__ line - 97):
{{{#!python
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus':
''})
}}}
To work around this in my subclassed UserCreationForm I have added:
{{{#!python
def __init__(self, *args, **kwargs):
if hasattr(self, 'fields') and self._meta.model.USERNAME_FIELD in
self.fields:
self.fields[self._meta.model.USERNAME_FIELD].widget.attrs.update({'autofocus':
''})

super(DjangoUserCreationForm, self).__init__(*args, **kwargs)
}}}
Note that in order to ensure the __init__ method of the parent of
django.contrib.auth.forms.UserCreationForm
(django.forms.models.BaseModelForm) is called I call the super
implementation directly, which probably isn't wise but in this case works
for me - I cannot call the immediate parent as it will result in the same
error.

I understand my logic might be edge case but I feel this is bug, hence why
it is reported as such.

--
Ticket URL: <https://code.djangoproject.com/ticket/27111>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Aug 23, 2016, 11:09:24 AM8/23/16
to django-...@googlegroups.com
#27111: UserCreationForm.__init__() crashes if USERNAME_FIELD not in self.fields
-------------------------------------+-------------------------------------
Reporter: petercampbell | Owner: nobody

Type: Bug | Status: new
Component: Forms | Version: 1.10
Severity: Normal | Resolution:
Keywords: custom user, django | Triage Stage: Accepted
admin, UserCreationForm |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by timgraham):

* needs_better_patch: => 0
* stage: Unreviewed => Accepted
* needs_tests: => 0
* needs_docs: => 0


Comment:

Feel free to submit a patch and we could backport to 1.10. Tests would go
in `tests/auth_tests/test_forms.py`.

--
Ticket URL: <https://code.djangoproject.com/ticket/27111#comment:1>

Django

unread,
Aug 24, 2016, 6:07:16 AM8/24/16
to django-...@googlegroups.com
#27111: UserCreationForm.__init__() crashes if USERNAME_FIELD not in self.fields
-------------------------------------+-------------------------------------
Reporter: petercampbell | Owner:
| berkerpeksag
Type: Bug | Status: assigned
Component: Forms | Version: 1.10

Severity: Normal | Resolution:
Keywords: custom user, django | Triage Stage: Accepted
admin, UserCreationForm |
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by berkerpeksag):

* owner: nobody => berkerpeksag
* status: new => assigned
* has_patch: 0 => 1
* cc: berker.peksag@… (added)


Comment:

[https://github.com/django/django/pull/7147 PR]

--
Ticket URL: <https://code.djangoproject.com/ticket/27111#comment:2>

Django

unread,
Aug 24, 2016, 1:20:36 PM8/24/16
to django-...@googlegroups.com
#27111: UserCreationForm.__init__() crashes if USERNAME_FIELD not in self.fields
-------------------------------------+-------------------------------------
Reporter: petercampbell | Owner:
| berkerpeksag
Type: Bug | Status: closed
Component: Forms | Version: 1.10
Severity: Normal | Resolution: fixed

Keywords: custom user, django | Triage Stage: Accepted
admin, UserCreationForm |
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Tim Graham <timograham@…>):

* status: assigned => closed
* resolution: => fixed


Comment:

In [changeset:"3c18f8a3d2f61669493f9ff2015ddc027eada3d6" 3c18f8a3]:
{{{
#!CommitTicketReference repository=""
revision="3c18f8a3d2f61669493f9ff2015ddc027eada3d6"
Fixed #27111 -- Fixed KeyError if USERNAME_FIELD isn't in
UserCreationForm.fields.
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/27111#comment:3>

Django

unread,
Aug 24, 2016, 1:24:36 PM8/24/16
to django-...@googlegroups.com
#27111: UserCreationForm.__init__() crashes if USERNAME_FIELD not in self.fields
-------------------------------------+-------------------------------------
Reporter: petercampbell | Owner:
| berkerpeksag
Type: Bug | Status: closed
Component: Forms | Version: 1.10

Severity: Normal | Resolution: fixed
Keywords: custom user, django | Triage Stage: Accepted
admin, UserCreationForm |
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------

Comment (by Tim Graham <timograham@…>):

In [changeset:"c4ee93128f1880c3993cf07619ff4e0524920a8e" c4ee9312]:
{{{
#!CommitTicketReference repository=""
revision="c4ee93128f1880c3993cf07619ff4e0524920a8e"
[1.10.x] Fixed #27111 -- Fixed KeyError if USERNAME_FIELD isn't in
UserCreationForm.fields.

Backport of 3c18f8a3d2f61669493f9ff2015ddc027eada3d6 from master
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/27111#comment:4>

Reply all
Reply to author
Forward
0 new messages