#
# models.py
#

from django.db import connection, models
 
 
class PrefetchIDMixin(object):
    def prefetch_id(self):
        # <https://djangosnippets.org/snippets/2731/>
        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
            # <http://postgresql.nabble.com/DEFERRABLE-NOT-NULL-constraint-tp5743655p5743779.html>
            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(),
            ['<Detail: gun>', '<Detail: Zed>'])
        self.assertEqual(m.main_thing, Detail.objects.get(name='Zed'))