[Django]-Creating a extended user profile

31👍

You can implement it using post_save on the user:

from django.db.models.signals import post_save
from models import UserProfile
from django.contrib.auth.models import User

def create_profile(sender, **kwargs):
    user = kwargs["instance"]
    if kwargs["created"]:
        profile = users.models.UserProfile()
        profile.setUser(sender)
        profile.save()

post_save.connect(create_profile, sender=User)

Edit:
Another possible solution, which is tested and works (I’m using it on my site):

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
def create_profile(sender, **kwargs):
    user = kwargs["instance"]
    if kwargs["created"]:
        up = UserProfile(user=user, stuff=1, thing=2)
        up.save()
post_save.connect(create_profile, sender=User)
👤Agos

6👍

You can get the extended profile to be created when first accessed for each user instead:

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    additional_info_field = models.CharField(max_length=50)

User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

then use

from django.contrib.auth.models import User
user = User.objects.get(pk=1)
user.profile.additional_info_field

ref: http://www.codekoala.com/blog/2009/quick-django-tip-user-profiles/

6👍

This helped me: primary_key=True

class UserProfile(models.Model):
    user = models.OneToOneField(User, unique=True, primary_key=True, related_name="user")
    phone = models.CharField(('phone'),max_length=30, blank=False, null=True)
    user_building = models.ManyToManyField(Building, blank=True)
    added_by = models.ForeignKey(User, blank=True, null=True, related_name="added")

5👍

When you call profile.setUser(), I think you want to pass instance rather than sender as the parameter.

From the documentation of the user_registered signal, sender refers to the User class; instance is the actual user object that was registered.

1👍

According to my latest research, creating a separate file, e.g., singals.py, does not work.

You’d better connect ‘create_profile’ to ‘post_save’ in your models.py directly, otherwise this piece of code won’t be executed since it’s in a separate file and no one imports it.

My final code for your reference:

# models.py

# Here goes the definition of class UserProfile.
class UserProfile(models.Model):
    ...

# Use signal to automatically create user profile on user creation.

# Another implementation:
# def create_user_profile(sender, **kwargs):
#     user = kwargs["instance"]
#     if kwargs["created"]:
#         ...
def create_user_profile(sender, instance, created, **kwargs):
    """
    :param sender: Class User.
    :param instance: The user instance.
    """
    if created:
        # Seems the following also works:
        #   UserProfile.objects.create(user=instance)
        # TODO: Which is correct or better?
        profile = UserProfile(user=instance)
        profile.save()

post_save.connect(create_user_profile,
                  sender=User,
                  dispatch_uid="users-profilecreation-signal")

0👍

Update for 2018:

This question has collected a lot of views, maybe it is time for an update.

This is the latest version for latest Django.

from django.dispatch import receiver
from django.db.models.signals import post_save
from django.conf import settings
from models import UserProfile

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user_profile(sender, instance=None, created=False, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

Leave a comment