2

I'm completing my first project in Django, I'm still struggling when I need to find documentation about the problem that I cannot manage to solve, then I thought to post a question here. In my django project I installed the app "users" for the authentication, I have the following views.py in the folder "users":

from django.shortcuts import render, redirect
from django.contrib.auth import login
from django.contrib.auth.forms import UserCreationForm


    def register(request):
        """Register a new user:"""
        if request.method != 'POST':
            # Display blank reigistration form.
            form = UserCreationForm()
        else:
            # Process completed form.
            form = UserCreationForm(data=request.POST)
            
            if form.is_valid():
                new_user = form.save()
                # Log the user in and then redirect to home page.
                login(request, new_user)
                return redirect('learning_journals:index')
    
    
        # Display a blank or invalid form
        context = {'form':form}
        return render(request, 'registration/register.html', context)

Models.py is empty at the moment. Everything is perfect and everything works well, both the form and the backend. Users can access with no problem.

When a user signs in, is obliged to use a case sensitive username. I would like the user to be able to log in with a case insensitive username, but I have no idea how to start and make this possible.

Thank you very much in advance for your help. Please let me know if you would like more info about my project.

python -m django --version ---> 3.2.9

Bye!

Red
  • 63
  • 6

1 Answers1

2

You should make a custom authentication backend, you can do this with:

# app_name/backends.py

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend

UserModel = get_user_model()

class CaseInsensitiveModelBackend(ModelBackend):
    
    def authenticate(self, request, username=None, password=None, **kwargs):
        if username is None:
            username = kwargs.get(UserModel.USERNAME_FIELD)
        if username is None or password is None:
            return
        try:
            user = UserModel._default_manager.get(username__iexact=username)
        except UserModel.DoesNotExist:
            UserModel().set_password(password)
            return
        if user.check_password(password) and self.user_can_authenticate(user):
            return user

then you specify the AUTHENTICATION_BACKENDS setting [Django-doc] as:

# settings.py

# …

AUTHENTICATION_BACKENDS = ['app_name.backends.CaseInsensitiveModelBackend']

# …
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Thank you Willem, you really helped me so much. Just to recap to avoid mistakes. I need to create a new file, backends.py, in the "users" folder, I add that code to the file. Then in settings.py I add the variable AUTHENTICATION_BACKENDS, I restart the server, and the users can now sign in with a case insensitive username, and case sensitive password. correct? – Red Jan 14 '22 at 16:47
  • @Renato: you can not use case insensitive passwords. For that you will need to use `tolower()` for the `UserCreationForm`, and also modify this in the `authenticate` method of the `CaseInsensitiveModelBackend`, especially since passwords are hashed. – Willem Van Onsem Jan 14 '22 at 16:49
  • Willem in fact I wrote "case sensitive password" just to be precise :). Is the recap correct? – Red Jan 14 '22 at 16:51
  • @Renato: ah, yes, that should work. You need to create the `backends.py` file in one of your apps (it does not really matter which one, but if you have one for registering and authentication, that makes most sense). Then of course you replace `app_name` with the name of the app in the settings. – Willem Van Onsem Jan 14 '22 at 16:53
  • Something is wrong with the code: "UserModel" is not definedPylancereportUndefinedVariable And the second error is on the last elif: Expected expressionPylance Then on the last return it just says: Unexpected indentationPylance – Red Jan 14 '22 at 17:04
  • @Renato: yes, sorry, you need to call `get_user_model()` to import the user model. – Willem Van Onsem Jan 14 '22 at 17:06
  • I added this: from django.contrib.auth import get_user_model, and then after def I added UserModel = get_user_model(). I still have the error message on elif, Expected expressionPylance. If I change it with else:, the system accepts any password as good, it doesn't matter if they are wrong. Sorry I don't mean to be a pain. – Red Jan 14 '22 at 17:17
  • @Renato: sorry, that was a mistake as well :s. Updated. – Willem Van Onsem Jan 14 '22 at 17:18
  • From another newby... can you explain what the kwargs is in the line: username = kwargs.get(UserModel.USERNAME_FIELD) ? I just don't quite get the two if statements fully... thanks! – Fred May 24 '22 at 03:39