Django custom user model: email authentication (2024)

Django offers a built-in User model with utilities for authentication, password hashing, etc. As your app develops, it is fully to be expected that the default User model will not exactly fit your needs. Replacing it in a later phase is a hassle, so it is recommended to roll your custom user model from the start. Actually it is the official recommendation.

In a lot of cases, there is no use for the username field: using only the user’s email for registration will make the user experience a bit better. Another quirk of Django’s user are the first_name and last_name fields. Coming from a country where ‘interjections’ are a thing, this will not suffice. A simple optional name field would be much better.

This post will detail how to create a custom user with email authentication and how to integrate this in your admin interface, and your project as a whole. We will then replace the custom views with django-allauth and add Oauth (3rd party / social login).

  1. Basic Django setup
  2. About custom user models
  3. Create the model and manager
  4. Use the custom user
  5. Custom views for account management
  6. Using Allauth for account management

Here is a brief rundown to get started. We will name the project “customuser”.

pipenv install
pipenv shell
pipenv install django
django-admin.py startproject customuser . # mind the dot
python manage.py runserver

This should give you a test server on: http://127.0.0.1:8000/.

Note that we did not yet apply any migrations. It is best to first make migrations for your custom user. Not having the custom user model when you start your project will likely lead to conflicts!

An example project can be found on github: https://github.com/snirp/django-email-authentication

Django documents three ways to extend or replace the default User:

  • Extend with a one-to-one field to User
  • Substitute by subclassing from AbstractUser: this preserves the fields and authentication methods
  • Substitute by subclassing from AbstractBaseUser: this will not preserve the default fields, also impacting existing methods.

The third option is most involved, but it is the one we will choose, because it offers the freedom to customize registration with email rather than username.

First order of business: a new app named users to hold our custom user model. Name it however you please.

python manage.py startapp users

And add the following to settings.py. This indicates that we want to use a yet-to-be-created model users.User for authentication, replacing the default django.contrib.auth.models.User.

INSTALLED_APPS = [
...
'users',
]
AUTH_USER_MODEL = 'users.User'

When you need to refer to the custom user from other parts of your code, you can do that in any of the following ways:

  • from users import User
  • from customuser.settings import AUTH_USER_MODEL
  • use the get_user_model() method from django.contrib.auth

The third method is preferred — certain for code that you intend to re-use — as it deals with both the default and custom user models.

The following model in users/models.py takes care of the custom User model.

Our User subclasses AbstractBaseUser, giving it the methods, but none of the default fields. We define our own fields, with the following being special cases:

  • USERNAME_FIELD: The name of the field that will serve as unique identifier (which will be the email field for us).
  • EMAIL_FIELD: The name of the field that will be returned when get_email_field_name() is called on a User instance.
  • REQUIRED_FIELDS: Required fields besides the password and USERNAME_FIELD when signing up.
  • is_staff: required by the admin.
  • is_superuser: used by the PermissionsMixin to grant all permissions.
  • is_active: indicates whether the user is considered “active”.

The UserManager subclasses the BaseUserManager and overrides the methods create_user and create_superuser. These custom methods are needed because the default methods expect a username to be provided. The admin app and manage.py will call these methods.

Apply the migrations and create a superuser. You should be prompted for an Email: (and not a username) and no errors should occur.

python manage.py makemigrations users
python manage.py migrate
python manage.py createsuperuser
Email:
python manage.py runserver

The admin interface isn’t aware of the custom User model yet, so let’s take care of that in users/admin.py:

After running the server, try to log into 127.0.0.1:8000/admin with the newly created superuser account. Try adding, editing and removing a few more user accounts for good measure.

You can also play around with the User model in the shell:

python manage.py shell
>>> from users.models import User
>>> u = User.objects.all()[0]
>>> u.set_password("newPassword")
>>> u.save()
>>> u.get_absolute_url()
# '/users/1/'

It is worth taking the following from the Django docs into consideration concerning custom user models:

Think carefully before handling information not directly related to authentication in your custom user model.

It may be better to store app-specific user information in a model that has a relation with the user model. That allows each app to specify its own user data requirements without risking conflicts with other apps. On the other hand, queries to retrieve this related information will involve a database join, which may have an effect on performance.

We will next look at custom account-related operations, such as: logging in, signing up and viewing the account information. This section shows you how to do it with custom views. In most cases it would be better to use a library for these common operations, so feel free to skip ahead to the next section, where we will cover the same using the Allauth library.

The users should be able to log in, log out, sign up and view their profile. This is what that would look like in customuser/urls.py and users/urls.py.

The urls should be self-explanatory. Notice that we use the built-in views for log in and log out and that we redirect to the /accounts/login on logging out.

The other two views — for profile and signup — are custom. Let’s take a look at users/forms.py and users/views.py

The SignUpForm is derived from the built-in UserCreationForm, making use of the custom User model and replacing the username field with the email field.

Notice that the signup view also authenticates the user with their email:

user = authenticate(request, email=user.email, password=raw_password)

The UserView is a “class based view” in which we override the get_objectmethod. It would normally expect a primary key in the request to get the correct instance, but here we can get the user instance directly from the request. We can be sure that the request has a user, because we added the login_required decorator to this view in urls.py.

These are the templates used for the account management:

No rocket science here. Start the server to test the url’s and authentication views.

Checkout the custom branch of the repository to view the code at this point.

In the previous step we wrote the views for basic account management. As the requirements grow, this will result in more custom work. Fortunately there are a few libraries that are designed to handle this exact scenario. We will use the well-designed library “django-allauth”, at it works well with our custom User model.

It also handles additional requirements such as:

  • email address verification
  • enter a single password on sign up
  • add social authentication (Oauth)
  • reset passwords
pipenv install django-allauth

Configuration

Assuming you start with a default settings.py, these are the changes required by Allauth in settings.py:

AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # existing backend
'allauth.account.auth_backends.AuthenticationBackend',
)
INSTALLED_APPS = [
...
'django.contrib.sites', # make sure sites is included
'allauth',
'allauth.account',
'allauth.socialaccount',
# the social providers
'allauth.socialaccount.providers.facebook',
'allauth.socialaccount.providers.google',
'allauth.socialaccount.providers.twitter',
...
]
SITE_ID = 1ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'

Edit urls.py:

urlpatterns = [
...
path('accounts/', include('allauth.urls')),
...
]

And finally:

python manage.py migrate
python manage.py runserver

You will now have the basic functionality of our “custom” solution above and then some. The Allauth views and forms gracefully handle our User model with email authentication, after we provided this information in the settings.

Add Oauth providers

A further feature is the support of the OAuth authentication standard. This allows third party servers to perform the authentication. Users can also authorize your app to access profile data, such as the email address.

After starting your server, visit the admin pages (localhost:8000/admin/) and follow these steps:

  1. In the admin add a Site for your domain, matching settings.SITE_ID . Set the Domain name to http://127.0.0.1:8000 for development.
  2. For each OAuth based provider, add a Social Application.
  3. Go to the provider (Google, etc) to add your client app, and add a redirect URL in the form of: http://127.0.0.1:8000/accounts/google/login/callback/
  4. The provider will give you a Client ID and a Client Secret. Fill these in with the Social Application in the admin.

The official documentation has detailed instructions, and a list of social authentication providers.

Try it out

Allauth gives a range of account functionalities. Try them out:

Clone the repository to view the code at this point.

Implementing a custom user model is a non-trivial exercise, but made much easier by libraries such as Allauth. As it is recommended to start your project with a custom user model, I would advise to start Django projects from a pre-configured repository. Skip django-admin startproject and start with a template that has at least a custom user model.

Django custom user model: email authentication (2024)
Top Articles
Latest Posts
Article information

Author: Kareem Mueller DO

Last Updated:

Views: 5914

Rating: 4.6 / 5 (66 voted)

Reviews: 89% of readers found this page helpful

Author information

Name: Kareem Mueller DO

Birthday: 1997-01-04

Address: Apt. 156 12935 Runolfsdottir Mission, Greenfort, MN 74384-6749

Phone: +16704982844747

Job: Corporate Administration Planner

Hobby: Mountain biking, Jewelry making, Stone skipping, Lacemaking, Knife making, Scrapbooking, Letterboxing

Introduction: My name is Kareem Mueller DO, I am a vivacious, super, thoughtful, excited, handsome, beautiful, combative person who loves writing and wants to share my knowledge and understanding with you.