Code Changes:

Something like I already mentioned could be used when trying to login:

> diff --git a/django/contrib/auth/base_user.py
> b/django/contrib/auth/base_user.py
> index 34dd6ac2f2..748db8bf89 100644
> --- a/django/contrib/auth/base_user.py
> +++ b/django/contrib/auth/base_user.py
> @@ -4,6 +4,7 @@ not in INSTALLED_APPS.
>  """
>  import unicodedata
>
> +from django.core.exceptions import MultipleObjectsReturned
>  from django.contrib.auth import password_validation
>  from django.contrib.auth.hashers import (
>      check_password, is_password_usable, make_password,
> @@ -41,7 +42,14 @@ class BaseUserManager(models.Manager):
>          return get_random_string(length, allowed_chars)
>
>      def get_by_natural_key(self, username):
> -        return self.get(**{self.model.USERNAME_FIELD: username})
> +        username_field = self.model.USERNAME_FIELD
> +
> +        # Try case-insensitive match of username.
> +        # If there are multiple possiblities fallback to case-sensitive
> lookup
> +        try:
> +            return self.get(**{username_field + '__iexac': username})
> +        except MultipleObjectsReturned:
> +            return self.get(**{username_field: username})
>
>
>  class AbstractBaseUser(models.Model):
>


and to check if the username is already taken, something like the following
could be used:
    def validate_unique(self, exclude=None):
        errors = {}
        if exclude is None:
            exclude = []
        else:
            exclude = list(exclude)

        try:
            super().validate_unique(exclude)
        except ValidationError as e:
            errors = e.update_error_dict(errors)

        if not (self.USERNAME_FIELD in exclude or self.USERNAME_FIELD in
errors):
            # Check if username is unique case-insensitive
            if self.__class__._default_manager.filter(
                **{self.USERNAME_FIELD + '__iexact': getattr(self,
self.USERNAME_FIELD)}).exists():
                errors.update(
                    {self.USERNAME_FIELD:
self.unique_error_message(self.__class__, (self.USERNAME_FIELD,))}
                )

        if errors:
            raise ValidationError(errors)


Possible Test cases:

- Logging In
-- only 1 case-insensitive
---- Login with different case
---- (Login with same case should already have a test case)
-- multiple case-insensitive
---- Login with casing of one
---- Login with casing of none

- Register
-- Create new different
-- Create new different only in case


For the docs, would it be more than a `versionchanged` block?

---------------------------------------------------------------
Info-Screen

On Mon, Apr 17, 2017 at 4:12 PM, Tobias McNulty <tob...@caktusgroup.com>
wrote:

> I'm surprised that (as far as I can see) this idea hasn't been discussed
> in the ~11 year (!) history of this ticket. It was alluded to ~3 years go
> by mkhalil28 <https://code.djangoproject.com/ticket/2273#comment:12>, but
> was missing the backwards-compatible 'except' bit and didn't get any
> follow-up discussion. To me this seems like an appropriate corresponding
> change to #25617 <https://code.djangoproject.com/ticket/25617>.
>
> If I'm thinking through this correctly, this would provide, for all
> intents and purposes:
>
>    - case-insensitive usernames for all new sites (and new users on
>    existing sites)
>    - indefinite backwards compatibility for sites that already have
>    "duplicate" usernames in the database, when case is ignored
>    - no feature flag that needs to be maintained
>    - the added benefit of allowing sites that really want case-sensitive
>    usernames to disable this behavior, if needed (by never adding unique=True
>    to the username field)
>
> If a change like this has been considered already, I am curious to know
> why it was rejected.
>
> I am not suggesting (yet) that we re-open #2273, but I think this would at
> least be worth exploring further: What would a minimum-impact change for
> case-insensitive usernames look like, both in terms of code and
> documentation changes? #25617 + this change seem like a good start, but
> more work will certainly be required to get this into a state that's ready
> for formal review. I probably won't have time to do that myself in the near
> future, but I would be happy to serve as a reviewer.
>
> Tobias
>
>
>
> *Tobias McNulty*Chief Executive Officer
>
> tob...@caktusgroup.com
> www.caktusgroup.com
>
> On Sun, Apr 16, 2017 at 5:47 PM, Info-Screen <info-scr...@info-screen.me>
> wrote:
>
>> Wouldn't it be possible to implement case-insensitive usernames without
>> loosing backwards compatibility, by checking the username iexact and only
>> if there are multiple possibilities fall back to the old case-sensitive
>> variant?
>>
>> So something like this:
>>
>> diff --git a/django/contrib/auth/base_user.py
>> b/django/contrib/auth/base_user.py
>> index 34dd6ac2f2..748db8bf89 100644
>> --- a/django/contrib/auth/base_user.py
>> +++ b/django/contrib/auth/base_user.py
>> @@ -4,6 +4,7 @@ not in INSTALLED_APPS.
>>  """
>>  import unicodedata
>>
>> +from django.core.exceptions import MultipleObjectsReturned
>>  from django.contrib.auth import password_validation
>>  from django.contrib.auth.hashers import (
>>      check_password, is_password_usable, make_password,
>> @@ -41,7 +42,14 @@ class BaseUserManager(models.Manager):
>>          return get_random_string(length, allowed_chars)
>>
>>      def get_by_natural_key(self, username):
>> -        return self.get(**{self.model.USERNAME_FIELD: username})
>> +        username_field = self.model.USERNAME_FIELD
>> +
>> +        # Try case-insensitive match of username.
>> +        # If there are multiple possiblities fallback to case-sensitive
>> lookup
>> +        try:
>> +            return self.get(**{username_field + '__iexac': username})
>> +        except MultipleObjectsReturned:
>> +            return self.get(**{username_field: username})
>>
>>
>>  class AbstractBaseUser(models.Model):
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "Django developers (Contributions to Django itself)" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to django-developers+unsubscr...@googlegroups.com.
>> To post to this group, send email to django-developers@googlegroups.com.
>> Visit this group at https://groups.google.com/group/django-developers.
>> To view this discussion on the web visit https://groups.google.com/d/ms
>> gid/django-developers/cc07fa69-06b3-4d24-aa2c-e5201ebe936a%4
>> 0googlegroups.com
>> <https://groups.google.com/d/msgid/django-developers/cc07fa69-06b3-4d24-aa2c-e5201ebe936a%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/to
> pic/django-developers/a4I7rHuT4Dw/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> django-developers+unsubscr...@googlegroups.com.
> To post to this group, send email to django-developers@googlegroups.com.
> Visit this group at https://groups.google.com/group/django-developers.
> To view this discussion on the web visit https://groups.google.com/d/ms
> gid/django-developers/CAMGFDKQaa4RX31yJqOapRvehH8GBPObybJmLC
> J44JqT0OZpqFA%40mail.gmail.com
> <https://groups.google.com/d/msgid/django-developers/CAMGFDKQaa4RX31yJqOapRvehH8GBPObybJmLCJ44JqT0OZpqFA%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/CALnJCOGZ6g%3DRB1-hT5pYvpzakTXUS2x8Qw6a%3DJWnVxwnp-YHsA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to