Recently, a friend of mine found himself trapped in the frustrating maze of trying to set up Django authentication without using a username. As he scoured the internet, jumping from one site to another in search of solutions, his code turned into a tangled nightmare of mismatched user forms and misguided workarounds.
Little did he know, the internet had done exactly what Sheldon Cooper once described: “…while you were sleeping, I was weaving an UN-un-ravelable web.” In this case, the UN-un-ravelable web was the web of authentication programming that seemed impossible to untangle.
Luckly, there was a working backup before the authentication change.
To remove the username field and use the email address as the primary login identifier, you’ll need to make adjustments across several parts of your Django project. This article will guide you through the steps, including where to place the necessary code in your project structure.
Step 1: Modify the CustomUserCreationForm
The first step is to create or modify the CustomUserCreationForm to remove the username field and ensure that the email field is used as the unique identifier. This form is used when creating new user accounts.
Location: forms.py in your app directory
# my_app/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class CustomUserCreationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('email', 'password1', 'password2') # Removed the username field
def save(self, commit=True):
user = super(CustomUserCreationForm, self).save(commit=False)
user.username = self.cleaned_data['email'] # Use email as the username
user.email = self.cleaned_data['email']
if commit:
user.save()
return userExplanation: In this code snippet, the username field has been removed from the form, and the email field is now the primary identifier. The save method ensures that the user’s email address is also used as their username, which is necessary because Django’s default User model requires a username field.
This small step is missed in many tutorials (and I would say) is where my friend ended up in a rabbit hole.
Step 2: Use Email as the Unique Identifier
Since the default User model in Django requires a username, you cannot simply eliminate this field without causing issues. However, by setting the username field to the email address, you effectively make the email both the username and the email, fulfilling the model’s requirement while achieving the desired outcome.
Location: This logic is already included in the save method of your CustomUserCreationForm in forms.py.
Step 3: Modify the Authentication Backend
Next, modify the authentication system to allow users to log in with their email instead of a username. By default, Django’s authentication backend uses the username to authenticate users. You’ll need to adjust this slightly by ensuring the username field is populated with the email address.
Location: settings.py in your project’s root directory
# my_project/settings.py
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # Keep the default backend
)Explanation: In your settings.py file, verify that the default authentication backend is listed. For most use cases, using the default backend with the adjustments made in the form is sufficient. However, for more advanced customization, you could write a custom authentication backend that explicitly checks the email instead of the username.
Step 4: Update the Login Form
To ensure that users can log in using their email address, you need to modify your login view and template to accept an email instead of a username.
Location: views.py in your app directory
# my_app/views.py
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import AuthenticationForm
from django.shortcuts import render, redirect
def login_view(request):
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
email = form.cleaned_data.get('username') # Change 'username' to 'email'
password = form.cleaned_data.get('password')
user = authenticate(request, username=email, password=password) # Authenticate using email
if user is not None:
login(request, user)
return redirect('flow')
else:
form = AuthenticationForm()
return render(request, 'registration/login.html', {'form': form})Explanation: In this view, the form is adjusted to accept an email address where it would typically ask for a username. The authenticate function is also modified to use the email as the identifier. This ensures that when users log in, their email address is used instead of a username.
Step 5: Adjust Your Templates
Ensure that your templates reflect these changes. Your login template should prompt the user for their email address rather than a username.
Location: templates/registration/login.html in your app directory
<!-- my_app/templates/registration/login.html -->
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>Explanation: In your template, you don’t need to make many changes since the form already includes the necessary fields. However, ensure that the form fields and labels are correctly named and aligned with the changes made in the form and views.
Summary
To summarize, here are the key steps involved in removing the username field and using an email address as the primary login identifier in a Django application:
- Custom Form Creation: Create or modify the
CustomUserCreationForminforms.pyto use the email instead of a username. - User Model: Ensure that the email is set as the primary identifier by using it as the username in the form’s save method.
- Authentication: Adjust the authentication backend in
settings.pyand modify your login view inviews.pyto use email as the login identifier. - Templates: Update your login templates to reflect the changes.
By following these steps and placing the code in the correct locations within your Django project, you can streamline your application’s authentication process, making it more user-friendly and aligned with modern web practices. This setup not only simplifies user account management but also enhances security by reducing the likelihood of username conflicts.
Thank you for following along with this tutorial. We hope you found it helpful and informative. If you have any questions, or if you would like to suggest new Python code examples or topics for future tutorials/articles, please feel free to join and comment. Your feedback and suggestions are always welcome!
You can find the same tutorial on Medium.com.