Search code examples
pythondjangoforeign-keysforeign-key-relationshipcyclic-reference

django how to insert into tables reference each other


I'm using django 1.6, and I have 2 models referencing each other like so:

class Person(models.Model):
   address = models.ForeignKey('Address', blank=False)

class Address(models.Model):
   person = models.ForeignKey(Person, blank=False)

The reason I have cyclic foreign key's is for data integrity. Because an address may be assigned to exactly one user, and a user must have at least one address. And yes, I know I can live without this, but I would rather not.

I'm using PostgreSQL with my foreign keys DEFERRABLE INITIALLY DEFERRED, and I want to use transactions to insert the data into those tables. However, when I try to use transaction.atomic():, it does not behave as expected within my view.

Here is what I am doing:

with transaction.atomic():
    addr = Address(street='125 fake street')
    addr.save()

    person = Person()
    person.address_id = addr.id

    addr.person_id = person.id

    addr.save()
    person.save()

However, I keep getting an IntegrityError the first time I call addr.save()

Any suggestions what I'm doing wrong? Is there a better way to to that?


Solution

  • The problem here is, because PostgreSQL does not wait untill the end of transaction to check for NOT NULL.

    sql-set-constraints reference

    "NOT NULL and CHECK constraints are always checked immediately when a row is inserted or modified (not at the end of the statement)."

    And my columns were set to NOT NULL.

    As a workaround, I'm doing this

    with transaction.atomic():
        addr = Address()
        addr.person_id = 0    # setting this temporarily to Zero
        addr.save()
    
        person = Person()
        person.address_id = addr.id
        person.save()
    
        addr.person_id = person.id
        addr.save()
    

    This allows me to insert into the database, and update the foreign keys later, and still fail with if no foreign key matches, because I will never have a value of Zero for id value.