41

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
  • 101,766
  • 154
  • 423
  • 727

9 Answers9

47

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
  • 50,371
  • 21
  • 151
  • 145
Ezequiel Marquez
  • 1,118
  • 15
  • 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
  • 6
    `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
37

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
  • 1,948
  • 2
  • 20
  • 27
17

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
  • 11,487
  • 4
  • 34
  • 50
  • 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
15

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

Daniel Rucci
  • 2,742
  • 2
  • 31
  • 42
vicvicvic
  • 5,775
  • 4
  • 33
  • 54
10

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
  • 7,773
  • 9
  • 67
  • 100
  • 3
    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
4

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
  • 61
  • 3
1

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_
  • 11,180
  • 7
  • 61
  • 94
Sachin G.
  • 1,652
  • 17
  • 22
1

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,113
  • 18
  • 35
1

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

from django.contrib.auth.models import User
request.user.profile