42

When adding additional fields to a user profile, such as location, gender, employer, etc., should I be adding additional columns to django.contrib.auth.models.User and saving it there? Or should I be creating a new table to save user profile information?

Also, when a user uploads a profile picture, should I be saving this in the same table? (Note this is not a production server, I'm just doing this on my local runserver to figure things out). Thank you

David542
  • 104,438
  • 178
  • 489
  • 842

9 Answers9

48

You have to make a model for the user profile:

class UserProfile(models.Model):  
    user = models.ForeignKey(User, unique=True)
    location = models.CharField(max_length=140)  
    gender = models.CharField(max_length=140)  
    employer = models.ForeignKey(Employer)
    profile_picture = models.ImageField(upload_to='thumbpath', blank=True)

    def __unicode__(self):
        return u'Profile of user: %s' % self.user.username

Then configure in settings.py:

AUTH_PROFILE_MODULE = 'accounts.UserProfile'
thanksd
  • 54,176
  • 22
  • 157
  • 150
Ezequiel Marquez
  • 1,148
  • 16
  • 26
  • Thanks, this got it working for me. But how would I access fields of User in admin.py? I'm trying to set up a ModelAdmin for UserProfile and tried accessing User fields like this: 'user__last_name'. But I get this error: 'user__last_name' is not a callable or an attribute of 'UserAdmin' or found in the model 'UserProfile'. How can I access these elements? – Matt May 17 '12 at 01:28
  • 10
    Perhaps it's worth mentioning that OneToOne with the User is a better than ForeignKey(unique=True) approach in such case. – Dmitry Jan 18 '13 at 04:55
  • 12
    -1 for using ForeignKey instead of OneToOne, @Dmitry has a better answer. Also AUTH_PROFILE_MODULE is a legacy setting not needed for Django 1.5+ – Tom Aug 12 '14 at 16:32
  • 7
    `AUTH_PROFILE_MODULE` is deprecated. – Flimm Dec 29 '15 at 11:30
  • May I know `class UserProfile` should defined in which file? Currently, our `class MyUser(AbstractBaseUser)` defined in file `models.py`. Should `UserProfile` be placed in the same file? – Cheok Yan Cheng Aug 20 '18 at 09:37
39

Conceptually, OneToOneField is similar to a ForeignKey with unique=True, but the “reverse” side of the relation will directly return a single object. This is the recommended way of extending User class.

class UserProfile(models.Model):  
    user = models.OneToOneField(User)
    ...
Dmitry
  • 2,068
  • 2
  • 21
  • 30
18

Current Django is 1.9 and here are some updates to the outdated accepted answer

  1. use models.OneToOneField(User)
  2. add related_name='profile'
  3. use .__str__() and .format() for Python 3

like so

class UserProfile(models.Model):  
    user = models.OneToOneField(User, related_name='profile')
    location = models.CharField(max_length=140)  
    gender = models.CharField(max_length=140)  
    ...

    def __str__(self):
        return 'Profile of user: {}'.format(self.user.username)

Using related_name you can access a user's profile easily, for example for request.user

request.user.profile.location
request.user.profile.gender

No need for additional lookups.

C14L
  • 12,153
  • 4
  • 39
  • 52
  • it working but when i login to my Django admin it show error user have no profile. My function are work correctly but i cam't access to my admin panel – usman imtiaz Apr 27 '20 at 08:34
16

Django provides a way of storing additional information about users in a separate table (called user profile).

Daniel Rucci
  • 2,822
  • 2
  • 32
  • 42
vicvicvic
  • 6,025
  • 4
  • 38
  • 55
11

Starting with Django 1.5 you can replace the default User with your custom user object using a simple settings entry:

AUTH_USER_MODEL = 'myapp.MyUser'

For slightly more details, check this Django documentation entry.

Nicu Surdu
  • 8,172
  • 9
  • 68
  • 108
  • 4
    Everyone should take note of the "auth" part. Avatars and bios should not be in the AUTH_USER_MODEL. Unless you want to integrate something like kerberos into your user authentication I would stick with django.contrib.auth. A one-to-one model with User should remain the way to do things in Django 1.5+ It seems like location, gender, employer are not valid authentication parameters and should not be added to a custom user model. – Tom Aug 12 '14 at 16:35
  • Upvoted for link to the official, (and as of now) current, docs. I appreciate that, because this is one of those issues where it seems like the Internet's vast capacity for storing the history of once-good answers about a framework results in a confusing mish-mash of hodge-podgery. :) – John Lockwood Jun 04 '16 at 14:23
  • 1
    @JohnLockwood just re-updated the link so it should be good for the years to come :P – Nicu Surdu Mar 07 '19 at 10:19
5

There's a solution I found here. Basically you just extend the default form UserCreationForm but keeping the same name. It works seamlessly with the way Django's docs tell you to do UserProfiles.

hitokiri82
  • 71
  • 1
  • 3
2

Answer can be updated to add signal receiver which will create the profile if it does not exist and update if it is already there.

@receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
    instance.profile.save()

This https://simpleisbetterthancomplex.com/tutorial/2016/11/23/how-to-add-user-profile-to-django-admin.html post also includes how to edit, list the custom profile in admin panel.

markwalker_
  • 12,078
  • 7
  • 62
  • 99
Sachin G.
  • 1,870
  • 19
  • 24
2

The current 2 top answers are outdated

If you reference User directly (for example, by referring to it in a foreign key), your code will not work in projects where the AUTH_USER_MODEL setting has been changed to a different user model. [..] Instead of referring to User directly [..] when you define a foreign key or many-to-many relations to the user model, you should specify the custom model using the AUTH_USER_MODEL setting.

from django.conf import settings
from django.db import models

class UserProfile(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="userprofile",
    )

https://docs.djangoproject.com/en/3.2/topics/auth/customizing/#referencing-the-user-model

Klaas van Schelven
  • 2,374
  • 1
  • 21
  • 35
2

If you want to get user profile data from user objects.

from django.contrib.auth.models import User
request.user.profile
Neeraj Kumar
  • 133
  • 1
  • 4