Opened 3 years ago

Closed 3 years ago

#32396 closed Bug (duplicate)

UsernameField normalisation throws TypeError if the username is empty

Reported by: Łukasz Rzepa Owned by:
Component: contrib.auth Version: 3.1
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Hi guys, this is my first ticket so excuse me if it's not perfect.

I'm working on a project where we use custom User using email as a USERNAME_FIELD. We allow users to have custom usernames but we don't require them so username field has null=True.

While editing one of the staff users through the admin panel I've stumbled upon an error when leaving the username field empty:

TypeError
normalize() argument 2 must be str, not None

To register User model to admin I'm using:

@admin.register(User)
class UserAdminView(UserAdmin):
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'password1', 'password2'),
        }),
    )

The source of the problem is the fact that unicodedata.normalize() in

class UsernameField(forms.CharField):
    def to_python(self, value):
        return unicodedata.normalize('NFKC', super().to_python(value))

needs a second argument to be a string. As super().to_python(value) is actually forms.CharField.to_python() '' value is returned as self.empty_value with defaults to '' but for a situation where CharField has null=True. In this case it's determined in django.db.models.fields.CharField.formfield() that

        if self.null and not connection.features.interprets_empty_strings_as_nulls:
            defaults['empty_value'] = None

and our self.empty_value becomes None which is in effect passed to normalize as a second argument.

My proposition is to fix it like this:

class UsernameField(forms.CharField):
    def to_python(self, value):
        value = super().to_python(value)
        return None if value is None else unicodedata.normalize('NFKC', value)

and allow the field null condition to be validated on the model level.

If you find this fix reasonable I'd be happy to open a PR with the suggested change.

My project is using Django 2.2 but it's the same for 3.1.

Change History (3)

comment:1 by Łukasz Rzepa, 3 years ago

Owner: changed from nobody to Łukasz Rzepa
Status: newassigned

comment:2 by Łukasz Rzepa, 3 years ago

Owner: Łukasz Rzepa removed
Status: assignednew

comment:3 by Carlton Gibson, 3 years ago

Resolution: duplicate
Status: newclosed

Hi, thanks for the report — nice and clear.

I'm going to close this as a duplicate of #31972. As per the docs on Custom users and the built-in auth forms you'll need to extend or customise the forms here. (Using `ModelAdmin.get_form()` I imagine.)

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