Sitemap

Custom User In Django

6 min readSep 6, 2022

--

Introduction

Hello, In this post we will learn to make a Custom User Model in Django and we will also change the default login functionality of the Django Admin. We will use Email and Password to log in. Because few Customer Need a custom user Auth rather than going for a Default Auth system.

Press enter or click to view image in full size

About custom user models

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.

Create the Model Manager

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.

Use the custom user

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:

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.

Custom views for account management

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.

customuser/urls.nl

users/urls.py

Get Punit Kulkarni’s stories in your inbox

Join Medium for free to get updates from this writer.

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

users/forms.py

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.

Using Allauth for account management

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:

Conclusion

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.

--

--