# # models.py # from django.db import connection, models class PrefetchIDMixin(object): def prefetch_id(self): # cursor = connection.cursor() cursor.execute( "SELECT nextval('{0}_{1}_{2}_seq'::regclass)".format( self._meta.app_label.lower(), self._meta.object_name.lower(), self._meta.pk.name, ) ) row = cursor.fetchone() cursor.close() self.pk = row[0] class Master(PrefetchIDMixin, models.Model): name = models.CharField(max_length=20) main_thing = models.OneToOneField('Detail', related_name='main_thing_of') class Detail(models.Model): name = models.CharField(max_length=20) master = models.ForeignKey('Master') def __unicode__(self): return self.name # # tests.py # from django.test import TestCase from django.db import transaction from .models import Master, Detail class CircularReference(TestCase): def test_adding_with_circular_reference(self): # Postgres will defer validation of foreign key constraints # until the end of the transaction with transaction.atomic(): m = Master(name='Zardoz') # NOT NULL constraints can't be defered in postgres, so # foreign key fields need to be populated beforehand # m.prefetch_id() Detail.objects.create(master=m, name='gun') m.main_thing = Detail.objects.create(master=m, name='Zed') m.save() m = Master.objects.get() self.assertQuerysetEqual( m.detail_set.order_by('name').all(), ['', '']) self.assertEqual(m.main_thing, Detail.objects.get(name='Zed'))