Opened 3 years ago

Closed 3 years ago

#33613 closed Bug (fixed)

createsuperuser does not validate usernames that use a UniqueConstraint.

Reported by: Lucidiot Owned by: Lucidiot
Component: contrib.auth Version: 4.0
Severity: Normal Keywords:
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

With a custom User model that uses a UniqueConstraint instead of unique=True, the manage.py createsuperuser command does not validate usernames at all.

class CustomUser(AbstractBaseUser):
    custom_username = models.CharField(max_length=255)
    USERNAME_FIELD = 'custom_username'

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['custom_username'], name='unique_usernames'),
        ]

Running manage.py createsuperuser to create a user with a username that already exists then results in an IntegrityError:

IntegrityError: duplicate key value violates unique constraint "unique_usernames"
DETAIL:  Key (custom_username)=(foo) already exists.

Change History (4)

comment:1 by Mariusz Felisiak, 3 years ago

Summary: manage.py createsuperuser does not validate usernames that use a UniqueConstraintcreatesuperuser does not validate usernames that use a UniqueConstraint.
Triage Stage: UnreviewedAccepted
Type: BugCleanup/optimization

Thanks for this report. It's documented that "The field must be unique (i.e., have unique=True set in its definition)", however I agree that we could improve this, e.g.:

  • django/contrib/auth/management/commands/createsuperuser.py

    diff --git a/django/contrib/auth/management/commands/createsuperuser.py b/django/contrib/auth/management/commands/createsuperuser.py
    index 5fffa55a22..0b8c72e866 100644
    a b from django.contrib.auth.password_validation import validate_password  
    1111from django.core import exceptions
    1212from django.core.management.base import BaseCommand, CommandError
    1313from django.db import DEFAULT_DB_ALIAS
     14from django.utils.functional import cached_property
    1415from django.utils.text import capfirst
    1516
    1617
    class Command(BaseCommand):  
    277278            else "",
    278279        )
    279280
     281    @cached_property
     282    def username_is_unique(self):
     283        if self.username_field.unique:
     284            return True
     285        for unique_constraint in self.UserModel._meta.total_unique_constraints:
     286            if len(unique_constraint.fields) == 1 and self.username_field.name == unique_constraint.fields[0]:
     287                return True
     288        return False
     289
    280290    def _validate_username(self, username, verbose_field_name, database):
    281291        """Validate username. If invalid, return a string error message."""
    282         if self.username_field.unique:
     292        if self.username_is_unique:
    283293            try:
    284294                self.UserModel._default_manager.db_manager(database).get_by_natural_key(
    285295                    username

Would you like to prepare a patch? (a regression test is also required.)

comment:2 by Lucidiot, 3 years ago

Has patch: set
Owner: changed from nobody to Lucidiot
Status: newassigned

Done: PR

Should I update the documentation as well?

comment:3 by Mariusz Felisiak, 3 years ago

Triage Stage: AcceptedReady for checkin
Type: Cleanup/optimizationBug

Should I update the documentation as well?

It should be enough to change i.e. to e.g..

comment:4 by Mariusz Felisiak <felisiak.mariusz@…>, 3 years ago

Resolution: fixed
Status: assignedclosed

In 13a9cde1:

Fixed #33613 -- Made createsuperuser detect uniqueness of USERNAME_FIELD when using Meta.constraints.

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