djangodjango-fixtures

When using natural_keys in Django, how can I distinguish between creates & updates?


In Django, I often copy model fixtures from one database to another. My models use natural_keys (though I'm not sure that's relevant) during serialization. How can I ensure the instances that have been updated in one database are not inserted into the other database?

Consider the following code:

models.py:

class AuthorManager(models.Manager):
  def get_by_natural_key(self, name):
    return self.get(name=name)

class Author(models.Model):
  objects = AuthorManager()
  name = models.CharField(max_length=100)
  def natural_key(self):
    return (self.name,)

Now if I create an author called "William Shakespeare" and dump it to a fixture via python manage.py dumpdata --natural_keys I will wind up w/ the following sort of file:

[
  {
    "model": "myapp.author",
    "fields": {
      "name": "Wiliam Shakespeare"
    }
  }
]

I can load that into another db and it will create a new Author named "William Shakespeare".

But, if I rename that author to "Bill Shakespeare" in the original database and recreate the fixture and load it into the other database then it will create another new Author named "Bill Shakespeare" instead of update the existing Author's name.

Any ideas on how to approach this?


Solution

  • You're using fixtures for what it's not made for: synchronizing databases. It's made for populating empty databases. In particular, "deletion" cannot be expressed in fixtures. An update based on natural keys could be expressed as an insertion + a deletion.

    Now you can work around this by simply not using natural keys, but then the primary keys must be identical between databases. If the target database receives inserts from another source, then this is a problem as updates will be occur at the wrong object.

    In short: use synchronization/replication tools to synchronize databases, use fixtures for migrations and tests. Trying to use fixtures for synchronization is error prone.