Can Django automatically create a related one-to-one model?

I have two models in different apps: ModelA and ModelB. They have a one-to-one relationship. Is there a way django can automatically create and save ModelB when ModelA is saved?

class ModelA(models.Model):
    name = models.CharField(max_length=30)

class ModelB(models.Model):
    thing = models.OneToOneField(ModelA, primary_key=True)
    num_widgets = IntegerField(default=0)

When I save a new ModelA I want a entry for it to be saved automatically in ModelB. How can I do this? Is there a way to specify that in ModelA? Or is this not possible, and I would just need to create and save ModelB in the view?

Edited to say the models are in different apps.


Take a look at the AutoOneToOneField in django-annoying. From the docs:

from annoying.fields import AutoOneToOneField

class MyProfile(models.Model):
    user = AutoOneToOneField(User, primary_key=True)
    home_page = models.URLField(max_length=255)
    icq = models.CharField(max_length=255)

(django-annoying is a great little library that includes gems like the render_to decorator and the get_object_or_None and get_config functions)


Like m000 pointed out:

... The catch in the question is that the models belong to different apps. This matches the use case for signals: "allow decoupled applications get notified when actions occur elsewhere in the framework". Other proposed solutions work but introduce an unnecessary A->B dependency, essentially bundling the two apps. Signals allows A to remain decoupled from B.

Your models exist in different apps. Often you use apps you didn't write, so to allow updates you need a decoupled way to create logically related models. This is the preferred solution in my opinion and we use it in a very large project.

By using signals:

In your models.py:

from django.db.models import signals


def create_model_b(sender, instance, created, **kwargs):
    """Create ModelB for every new ModelA."""
    if created:
        ModelB.objects.create(thing=instance)

signals.post_save.connect(create_model_b, sender=ModelA, weak=False,
                          dispatch_uid='models.create_model_b')

You can create a separate app to hold this models.py file if both of the apps are off-the-shelf.


The most straightforward way is to override the save method of ModelA:

class ModelA(models.Model):
    name = models.CharField(max_length=30)

    def save(self, force_insert=False, force_update=False):
        is_new = self.id is None
        super(ModelA, self).save(force_insert, force_update)
        if is_new:
            ModelB.objects.create(thing=self)

I know it's a bit late, but I came up with a cleaner and more elegant solution. Consider this code:

class ModelA(models.Model):
    name = models.CharField(max_length=30)

    @classmethod
    def get_new(cls):
        return cls.objects.create().id



class ModelB(models.Model):
    thing = models.OneToOneField(ModelA, primary_key=True, default=ModelA.get_new)
    num_widgets = IntegerField(default=0)

Of course you can use lambda as well, as long as you return integer id of related object :)


I assembled a few different answers (because none of them worked straight out of the box for me) and came up with this. Thought it's pretty clean so I'm sharing it.

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=ModelA)
def create_modelb(sender, instance, created, **kwargs):
    if created:
        if not hasattr(instance, 'modelb'):
            ModelB.objects.create(thing=instance)

It's using Signal as @Dmitry suggested. And as @daniel-roseman commented in @jarret-hardie's answer, Django Admin does try to create the related object for you sometimes (if you change the default value in the inline form), which I ran into, thus the hasattr check. The nice decorator tip is from @shadfc's answer in Create OneToOne instance on model creation