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
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
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
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/
Interesting. Options 1 and 2 seem database bad. Option #3 is frowned upon. Not happy with Django today.
[...] Extending the Django User Model [...]