Django Extend User Model Example

Hi Dev,
This article will provide example of how to extend django user model. step by step explain extending user model using a proxy model. if you have question about django extend user model example then I will give simple example with solution. if you have question about extending user model using a custom model extending abstractbaseuser then I will give simple example with solution. Alright, let’s dive into the steps.
Here, i will show you different strategies you can utilize to elongate the Django User Model. Nothing to worry about, you don’t have to do everything from scratch.
Four different ways to extend the existing Django user model so follow my below steps.
- Extending User Model Using a Proxy Model
- Extending User Model Using a One-To-One Link
- Extending User Model Using a Custom Model Extending AbstractBaseUser
- Extending User Model Using a Custom Model Extending AbstractUser
First of all in your mind raise a question What is Proxy Model: proxy model is a method in which you are not creating a new table in the database. It is used to change the behavior of a current model (e.g. adding new methods, etc.) without affecting the existing database.
And, When should I use a Proxy Model? you can use a Proxy model when you don’t need to store extra information in the database, but simply to change the model’s query manager or to add extra methods.
Let's See the below example:
from django.contrib.auth.models import User from .managers import PersonManager class Person(User): objects = PersonManager() class Meta: proxy = True ordering = ('first_name', ) def write_something(self): ...
Above example we have defined a Proxy Model named Person. in Meta class, we are adding the property proxy = True, which tells Django this is a Proxy Model.
In above case, you can redefine the default ordering as shown in the example. I have assigned a custom Manager to the model, and also defined a new method write_something.
Step 2: Extending User Model Using a One-To-One Link:In this second section we can learn about One-To-One link, the Django model is going to have its own database table and will hold a One-To-One relationship with the subsisting User Model through a OneToOneField
We will be creating a new Django Model to store some extra information that relates to the User Model.
models.pyfrom django.db import models from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) bio = models.TextField(max_length=500, blank=True) location = models.CharField(max_length=30, blank=True) birth_date = models.DateField(null=True, blank=True)
Now we will define signals so that our Profile model will be created/updated automatically when the User instance is created or updated.
from django.db import models from django.contrib.auth.models import User from django.db.models.signals import post_save from django.dispatch import receiver class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) bio = models.TextField(max_length=500, blank=True) location = models.CharField(max_length=30, blank=True) birth_date = models.DateField(null=True, blank=True) @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: Profile.objects.create(user=instance) @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): instance.profile.save()
So, whenever a save event occurs, we are hooking the create_user_profile and save_user_profile methods to the User model. this kind of signal is called post_save.
How to use in django templates
<h2>{{ user.get_full_name }}</h2> <ul> <li>Username: {{ user.username }}</li> <li>Location: {{ user.profile.location }}</li> <li>Birth Date: {{ user.profile.birth_date }}</li> </ul>views.py
How about inside a view method?
def update_profile(request, user_id): user = User.objects.get(pk=user_id) user.profile.bio = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit...' user.save()
You will never have to call the Profile’s preserve method. Everything is done through the User model.
What if I’m using Django Forms?
forms.pyclass UserForm(forms.ModelForm): class Meta: model = User fields = ('first_name', 'last_name', 'email') class ProfileForm(forms.ModelForm): class Meta: model = Profile fields = ('url', 'location', 'company')views.py
class ProfileUpdateView(LoginRequiredMixin, TemplateView): user_form = UserForm profile_form = ProfileForm template_name = 'common/profile-update.html' def post(self, request): post_data = request.POST or None user_form = UserForm(post_data, instance=request.user) profile_form = ProfileForm(post_data, instance=request.user.profile) if user_form.is_valid() and profile_form.is_valid(): user_form.save() profile_form.save() messages.success(request, 'Your profile was successfully updated!') return HttpResponseRedirect(reverse_lazy('profile')) context = self.get_context_data( user_form=user_form, profile_form=profile_form ) return self.render_to_response(context) def get(self, request, *args, **kwargs): return self.post(request, *args, **kwargs)profile.html
<form method="post"> {% csrf_token %} {{ user_form.as_p }} {{ profile_form.as_p }} <button type="submit">Save changes</button> </form>
Sometimes, there are quandaries that can be caused, like firing hundreds or thousands of queries. This quandary can be mitigated utilizing the select_related method.
users = User.objects.all().select_related('profile')Step 3: Extending User Custom Model using AbstractBaseUser:
So, in this section extending user model using AbstractBaseUser, what is custom user model extending AbstractBaseUser : it is an entirely new User model that inherits from AbstractBaseUser. There are special things you need to take care of i.e update some references in settings.py at the beginning of the project.
There was a situation for me where I had to use an email address as the authentication token instead of a username. Also, there was no need for the is_staff flag, as I wasn’t using the Django Admin.
See the below model I had to define:
models.pyfrom __future__ import unicode_literals from django.db import models from django.core.mail import send_mail from django.contrib.auth.models import PermissionsMixin from django.contrib.auth.base_user import AbstractBaseUser from django.utils.translation import ugettext_lazy as _ from .managers import UserManager class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(_('email address'), unique=True) first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=30, blank=True) date_joined = models.DateTimeField(_('date joined'), auto_now_add=True) is_active = models.BooleanField(_('active'), default=True) is_staff = models.BooleanField(_('staff'), default=True) avatar = models.ImageField(upload_to='avatars/', null=True, blank=True) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] class Meta: verbose_name = _('user') verbose_name_plural = _('users') def get_full_name(self): ''' Returns the first_name plus the last_name, with a space in between. ''' full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): ''' Returns the short name for the user. ''' return self.first_name def email_user(self, subject, message, from_email=None, **kwargs): ''' Sends an email to this User. ''' send_mail(subject, message, from_email, [self.email], **kwargs)
Okay, let’s move ahead. I had to define my own UserManager because the existing manager defines the create_user and create_superuser methods.
So, here’s my UserManager looks like:
UserManagerfrom django.contrib.auth.base_user import BaseUserManager class UserManager(BaseUserManager): use_in_migrations = True def _create_user(self, email, password, **extra_fields): """ Creates and saves a User with the given email and password. """ if not email: raise ValueError('The given email must be set') email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_user(self, email, password=None, **extra_fields): extra_fields.setdefault('is_superuser', False) return self._create_user(email, password, **extra_fields) def create_superuser(self, email, password, **extra_fields): extra_fields.setdefault('is_superuser', True) if extra_fields.get('is_superuser') is not True: raise ValueError('Superuser must have is_superuser=True.') return self._create_user(email, password, **extra_fields)
Basically I’ve clean up of the existing UserManager, removing the is_staff property and the username.
Now finally we have to update our settings.py. In settings.py defining AUTH_USER_MODEL property.
AUTH_USER_MODEL = 'core.User'
This way we are telling Django to use our custom model instead of the default one. In the example above, I’ve created the custom model inside an app named core.
How should I reference this model?
from django.db import models from testapp.core.models import User class Course(models.Model): slug = models.SlugField(max_length=100) name = models.CharField(max_length=100) tutor = models.ForeignKey(User, on_delete=models.CASCADE)
This is perfectly okay. But if you are creating a reusable app, that will be publicly available, it is strongly advised to use the following method:
from django.db import models from django.conf import settings class Course(models.Model): slug = models.SlugField(max_length=100) name = models.CharField(max_length=100) tutor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)Step 4: Extending User Custom Model Using Extending AbstractUser:
In this last one is we can learn about What is a Custom User Model Extending AbstractUser? : It is a new User model that inherits from AbstractUser. There are special things you need to take care of i.e update some references in settings.py at the beginning of the project.
The class django.contrib.auth.models.AbstractUser provides the full implementation of the default User as an abstract model which is a very straightforward way.
models.pyfrom django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): bio = models.TextField(max_length=500, blank=True) location = models.CharField(max_length=30, blank=True) birth_date = models.DateField(null=True, blank=True)
After this we have to update our settings.py defining the AUTH_USER_MODEL property as:
AUTH_USER_MODEL = 'core.User'
I hope it will help you....