Extending the Django User model

Wednesday, May 5th, 2010

There appears to be 3 ways to extend the functionality of the Django User model:

  • Through sub-classing
  • With a profile class
  • By monkey-patching

Through Sub-classing

Original Source

This solution requires that the developer extend the base User class and give the sub-class the extended fields and methods.

from django.contrib.auth.models import UserManager, User
 
class CustomUser(User):
    objects = UserManager()
 
    def get_user_name(self):
        if self.first_name or self.last_name:
            return self.first_name + " " + self.last_name
        return self.username

The disadvantage of this solution is the need for a custom authentication backend. This is further described in the original post and in the Django documentation.

With a Profile Class

Original Source

This is the Django prefered way. A custom Profile class, let’s say UserProfile, has the User model as a foreign key. In settings.py, the developer sets `AUTH_PROFILE_MODULE` to the profile class and everytime `user.get_profile()` is called, an instance of UserProfile is returned.

A clever post on StackOverflow explains how to insure that a profile exists for every new user:

from django.db.models.signals import post_save
 
class UserProfile(models.Model)
    user = models.ForeignKey(User)
    ...
 
    def get_user_name(self):
        if self.user.first_name or self.user.last_name:
            return self.user.first_name\
                    + " " + self.user.last_name
        return self.user.username
 
def create_profile(sender, instance, created, **kwargs):
    if created:
        profile, created = UserProfile.objects\
                            .get_or_create(user=instance)
 
post_save.connect(create_profile, sender=User)

This solution works well and is promoted by the Django team but it does come at the expense of an extra database query. As well, the implementing code will have to know whether to call a method on the `User` instance (e.g. `user.is_anonymous()`) or on the profile (e.g. `user.get_profile().get_user_name()`).

Monkey Patching

Original Source

The least favorable method to the ones described above requires the developer to add methods to the User class using the `add_to_class` method. The example goes like so:

from django.contrib.auth.models import User
 
def get_user_name(self):
    if self.first_name or self.last_name:
        return self.first_name + " " + self.last_name
    return self.username
User.add_to_class("get_user_name",get_user_name)

The danger with monkey patching has to do with clarity and future proofing. For instance, if a future release of Django includes the user method `get_user_name`, the above example will break it. As well, it may not be clear to another developer where the `get_user_name` method is declared when debugging.

A Spanish translation is available here: http://markon.netsons.org/2011/08/09/come-estendere-la-classe-user-in-django/

2 Responses to “Extending the Django User model”

  1. Banana9 says:

    Interesting. Options 1 and 2 seem database bad. Option #3 is frowned upon. Not happy with Django today.

  2. [...] Extending the Django User Model [...]

Leave a Reply