22

I want to add a convenience/model method to the django.contrib.auth.models.User model. What is the best practice for doing this since, last time I checked, extending the User model was considered bad practice.

I have a separate custom UserProfile model. Should I be using that for all User-related convenience methods?

Soviut
  • 88,194
  • 49
  • 192
  • 260

5 Answers5

30

It depends what you are trying to add to the model. If you want to add more information about the user, then it is generally recommended that you use the UserProfile method: http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users

However, if you just want to add custom methods or managers to the User model, I would say that it's more logical to use a proxy model, like so:

from django.contrib.auth.models import User

class UserMethods(User):
  def custom_method(self):
    pass
  class Meta:
    proxy=True

A proxy model will operate on the same database table as the original model, so is ideal for creating custom methods without physically extending the model. Just replace any references to User in your views to UserMethods. (And of course you can use this in the admin tool by unregistering the User model and registering your proxy model in its stead.)

Any instances of the original User model that are created will be instantly accessible via the UserMethods model, and vice-versa. More here: http://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models

(NB. Proxy models require Django 1.1 and above)

Gary Chambers
  • 24,930
  • 4
  • 35
  • 31
  • Good call! Totally forgot about Proxy models. I'm running 1.1 but was thinking in a 1.0 mindset. – Soviut Nov 30 '09 at 19:35
  • 14
    Is there an easy way to change the type of request.user to the proxy type? Is that necessary, or can I call the proxy methods directly on request.user? – slacy Oct 27 '11 at 16:40
  • 3
    I had the same doubt as @slacy and found a way on this answer: https://stackoverflow.com/a/11526049/188614. Basically, you have to subclass django.contrib.auth.backends.ModelBackend, return UserMethods on get_user, and set it on AUTHENTICATION_BACKENDS. – Diego Ponciano Oct 20 '14 at 11:57
  • This link to Django documentation is now broken. Does anyone know the new URL? – CoderGuy123 Oct 28 '16 at 16:20
14

if you want to add custom methods to the User model, I would recommend monkey_patching:

create a file monkey_patching.py in any of your apps::

#app/monkey_patching.py
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)

and import it in app's __init__.py file. ie::

#app/__init__.py
import monkey_patching
suhailvs
  • 20,182
  • 14
  • 100
  • 98
4

Yes. No need to mess with the foundations when your user model has a .get_profile() function attached to it.

SapphireSun
  • 9,170
  • 11
  • 46
  • 59
  • 1
    +1, extending the User model is still not recommended, and all the plumbing for profiles is already there to utilise. – Ryan Duffield Nov 30 '09 at 14:48
  • You can add a `OneToOne` field on the profile model and call `user_instance.profile` instead of using `get_profile()`. – Eduard Luca Jan 31 '16 at 20:08
3

2013 update:

in 1.5 you can sustitute a custom User model and add whatever you want https://docs.djangoproject.com/en/dev/topics/auth/customizing/#auth-custom-user

panchicore
  • 11,451
  • 12
  • 74
  • 100
-1

I prefer to use the same UserProfile across various projects I develop and extend User for any project-specific needs. So, common functionality goes to UserProfile, and project-specific functionality goes to custom User. I have not had any adverse effects of having a subclassed User model yet, I wonder if there still exist any with Django 1.0+.

shanyu
  • 9,536
  • 7
  • 60
  • 68