24

I'm building my first django app. I have a user, and the user has a list of favourites. A user has exactly one list of favourites, and that list belongs exclusively to that user.

class User(models.Model):
    name = models.CharField(max_length=200)

class FavouriteList(models.Model):
    user = models.OneToOneField(User)
    favourites = models.ManyToManyField(Favourite, blank=True)

When a new user is created, I want to ensure that the user has a FavouriteList. I've looked around in the Django documentation and haven't had much luck.

Does anyone know how I can ensure that a model has a child object (e.g. FavouriteList) when it is created?

NT3RP
  • 15,262
  • 9
  • 61
  • 97
  • Possible duplicate of [Can Django automatically create a related one-to-one model?](http://stackoverflow.com/questions/1652550/can-django-automatically-create-a-related-one-to-one-model) – Ciro Santilli OurBigBook.com May 10 '16 at 21:30

4 Answers4

45

The most common way to accomplish this is to use the Django signals system. You can attach a signal handler (just a function somewhere) to the post_save signal for the User model, and create your favorites list inside of that callback.

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User

@receiver(post_save, sender=User)
def create_favorites(sender, instance, created, **kwargs):
    if created:
        Favorites.objects.create(user=instance)

The above was adapted from the Django signals docs. Be sure to read the signals docs entirely because there are a few issues that can snag you such as where your signal handler code should live and how to avoid duplicate handlers.

TankorSmash
  • 12,186
  • 6
  • 68
  • 106
shadfc
  • 6,104
  • 3
  • 25
  • 19
  • 1
    updated the docs from 1.3 to 1.11. the `dev` docs would never be out of date, but maybe that would have been the better edit – TankorSmash Apr 11 '17 at 20:18
7

An excellent django-annoying plugin solves this for you with AutoOneToOneField. I'm using it for user profiles in all django projects I work on.

kkonrad
  • 1,262
  • 13
  • 32
Alexander Lebedev
  • 5,968
  • 1
  • 20
  • 30
5

One way would be to register a post_save signal with next handler:

def user_save(sender, instance, created, **kwargs):
  if created:
     FavouriteList.objects.get_or_create(user=instance)
Dmitry Shevchenko
  • 31,814
  • 10
  • 56
  • 62
0

You can override save method of User model.

def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
    is_new = self.pk is None  # check if object is new to be saved
    super().save(force_insert, force_update, using, update_fields)
    FavouriteList.objects.create(user=self) if is_new else None
Ali Shekari
  • 262
  • 4
  • 12