This is an old question and some of the comments seemed helpful, but nobody provided an actual answer with code so I thought I'd oblige.
Code
The following code will allow you to run Wife.objects.create(husband=h) just the same as if you were running Husband.objects.create(wife=w)
# models.py
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
class Wife(models.Model):
name = models.CharField(max_length=200, blank=True)
class Husband(models.Model):
wife = models.OneToOneField(Wife, related_name='husband', blank=True, null=True, on_delete=models.SET_NULL)
name = models.CharField(max_length=200, blank=True)
@receiver(post_save, sender=Wife)
def save_husband(sender, instance, created, **kwargs):
"""
This receiver lets you run Wife.objects.create(husband=husband)
When this function triggers, the Wife object ("instance") does have a valid husband attribute that corresponds to
a real Husband object.
However, without this receiver callback, this relationship has not been stored in the database.
To do that, we need to tell the Husband object who its Wife is.
"""
try:
husband = instance.husband
husband.wife = instance
husband.save()
except ObjectDoesNotExist:
pass # In case you run Wife.objects.create() without a Husband parameter
Bonus Code
If you're feeling real fancy, the following will make Wife and Husband even more equal. It will make unmarried_wife.husband return None instead of throwing a RelatedObjectDoesNotExist error. It will also let you run Wife creation with an integer pk like Wife.objects.create(husband_id=pk) instead of having to do Wife.objects.create(husband=Husband.objects.get(id=pk))
class Wife(models.Model):
name = models.CharField(max_length=200, blank=True)
# BONUS: Adding these properties lets you do other things on the Wife model that ordinarily you could only do on the Husband model
@property
def husband_id(self):
"""lets you run wife.husband_id and get an integer or None"""
try:
return self.husband_obj.id
except ObjectDoesNotExist:
return None
@husband_id.setter
def husband_id(self, pk):
"""lets you run Wife.objects.create(husband_id=pk) and have it work"""
self.husband = Husband.objects.get(id=pk)
@property
def husband(self):
"""
makes it so that w.husband returns 'None' instead of throwing an exception if w is an unmarried Wife,
similar to how running h.wife return None if h is an unmarried Husband.
"""
try:
return self.husband_obj
except ObjectDoesNotExist:
return None
@husband.setter
def husband(self, obj):
self.husband_obj = obj
class Husband(models.Model):
# note that I've changed the related_name to 'husband_obj' so that I can assign
# the getter/setter properties in the Wife class
wife = models.OneToOneField(Wife, related_name='husband_obj', blank=True, null=True, on_delete=models.SET_NULL)
name = models.CharField(max_length=200, blank=True)
@receiver(post_save, sender=Wife)
def reverse_save_husband(sender, instance, created, **kwargs):
"""
Same as before
"""
try:
husband = instance.husband
husband.wife = instance
husband.save()
except (ObjectDoesNotExist, AttributeError):
pass # In case you run Wife.objects.create() without a Husband parameter
Additional Note:
I changed the on_delete behavior to SET_NULL because I don't believe in Widow Burning :)
But that particular change is not necessary; the rest of the example will work fine even if you go with CASCADE.