# Topic covered
* Django default User Model
* Custom User Model
    * AbstractUser vs AbstractBaseUser
* Validating objects
    * full_clean()
    * Model.clean_fields()
    * Model.clean()
    * Model.validate_unique()

https://openclassrooms.com/en/courses/7107341-intermediate-django/7262933-customize-the-user-model

Django default User Model

By convention, data on an individual user is stored in a model called User. Django provides a default User model. This model has many special methods and features, particularly concerning authentication and permissions, that make it seamlessly integrate into the Django framework.

# from django.contrib.auth.models import User
  • username, first_name, last_name, email
  • password - this is stored as a hash in the database. Never store raw passwords.
  • is_staff - a boolean; dictates whether a user can log in to the Django admin site.
  • is_active - a boolean; it is considered Django best practice to mark users as inactive by setting this attribute toFalse instead of deleting them.
  • is_superuser - a boolean; superusers are automatically granted all permissions, such as access to the admin site.

superuser - The most powerful user with permissions to create, read, update and delete data in the Django admin, which includes model records and other users.

staff - A user marked as staff can access the Django admin. But permissions to create, read, update and delete data in the Django admin must be given explicitly to a user.

active - All users are marked as active if they’re in good standing. Users marked as inactive aren't able to authenticate themselves. A common state if there’s a pending post-registration step (e.g. confirm email) or a user is banned, and you don’t want to delete his data.

Custom User Model

If the fields in default User model don't fit - we can create own custom user model.

Even if you think that the default User model is good enough, you should always implement a custom User model in your project, even if it is identical to the default one.

This is because it is difficult and complicated to migrate to a custom User model after your Django site has been set up and your initial migrations have been run. It requires lots of tricky migrations and an in-depth understanding of SQL. Plans change, and clients alter specifications. Save yourself a headache and set up a custom User model at the start of your project.

Two ways to create by using - AbstractUser or AbstractBaseUser

AbstractUser

The AbstractUser class contains all the fields and methods that the default User does.

If you think the functionality of the default User class alone will meet your needs, then using it as a custom User model is as simple as this:

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    account_number =  CharField(max_length=10, unique=True)

AbstractBaseUser

AbstractBaseUser is used if you don't want to use every field provided by the default User class.

The AbstractBaseUser class contains no fields apart from the password . It also comes with a suite of methods to handle authentication (as does AbstractUser ).

There is also some additional configuration required for it to integrate with the Django authentication system

  • USERNAME_FIELD - you must set this to the field you want to use when logging in.
  • EMAIL_FIELD - set to the field that contains a user’s primary email, defaults to ‘email’ if not specified.
  • REQUIRED_FIELDS - set this to any fields that must be specified when using the python manage.py createsuperuser command.
  • is_active - defaults to True for AbstractBaseUser, but you can add your own field if you want to handle active and inactive users.

Want to use an email instead of username to log in

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    email = models.EmailField(unique=True)
    username = None

    USERNAME_FIELD = 'email'

Validating objects

https://docs.djangoproject.com/en/3.1/ref/models/instances/#validating-objects

There are three steps involved in validating a model:

  • Validate the model fields - Model.clean_fields()
  • Validate the model as a whole - Model.clean()
  • Validate the field uniqueness - Model.validate_unique()

All three steps are performed when you call a model’s full_clean() method.

Model.full_clean(exclude=None, validate_unique=True)

This full_clean() calls Model.clean_fields(), Model.clean(), and Model.validate_unique() (if validate_unique is True), in that order and raises a ValidationError that has a message_dict attribute containing errors from all three stages.

Model.clean_fields(exclude=None)

This method will validate all fields on your model. The optional exclude argument lets you provide a list of field names to exclude from validation. It will raise a ValidationError if any fields fail validation.

Model.clean()

This method should be used to provide custom model validation and to modify attributes on your model if desired.

Model.validate_unique(exclude=None)

This method is similar to clean_fields(), but validates all uniqueness constraints on your model instead of individual field values. The optional exclude argument allows you to provide a list of field names to exclude from validation. It will raise a ValidationError if any fields fail validation.

Note that if you provide an exclude argument to validate_unique(), any unique_together constraint involving one of the fields you provided will not be checked.