Excluding primary key in Django dumpdata with natural keys

The problem with json is that you can't omit the pk field since it will be required upon loading of the fixture data again. If not existing, json will fail with

$ python manage.py loaddata some_data.json
[...]
File ".../django/core/serializers/python.py", line 85, in Deserializer
data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])}
KeyError: 'pk'

As pointed out in the answer to this question, you can use yaml or xml if you really want to omit the pk attribute OR just replace the primary key value with null.

import re
from django.core import serializers

some_objects = MyClass.objects.all()
s = serializers.serialize('json', some_objects, use_natural_keys=True)
# Replace id values with null - adjust the regex to your needs
s = re.sub('"pk": [0-9]{1,5}', '"pk": null', s)

Updating the answer for anyone coming across this in 2018 and beyond.

There is a way to omit the primary key through the use of natural keys and unique_together method. Taken from the Django documentation on serialization:

You can use this command to test :

python manage.py dumpdata app.model --pks 1,2,3 --indent 4 --natural-primary --natural-foreign > dumpdata.json ;

Serialization of natural keys

So how do you get Django to emit a natural key when serializing an object? Firstly, you need to add another method – this time to the model itself:

class Person(models.Model):
    objects = PersonManager()

    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    birthdate = models.DateField()

    def natural_key(self):
        return (self.first_name, self.last_name)

    class Meta:
        unique_together = (('first_name', 'last_name'),)

That method should always return a natural key tuple – in this example, (first name, last name). Then, when you call serializers.serialize(), you provide use_natural_foreign_keys=True or use_natural_primary_keys=True arguments:

serializers.serialize('json', [book1, book2], indent=2, use_natural_foreign_keys=True, use_natural_primary_keys=True)

When use_natural_foreign_keys=True is specified, Django will use the natural_key() method to serialize any foreign key reference to objects of the type that defines the method.

When use_natural_primary_keys=True is specified, Django will not provide the primary key in the serialized data of this object since it can be calculated during deserialization:

    {
        "model": "store.person",
        "fields": {
            "first_name": "Douglas",
            "last_name": "Adams",
            "birth_date": "1952-03-11",
        }
    }

Override the Serializer class in a separate module:

from django.core.serializers.json import Serializer as JsonSerializer

class Serializer(JsonSerializer):

    def end_object(self, obj):
        self.objects.append({
            "model"  : smart_unicode(obj._meta),
            "fields" : self._current, 
            # Original method adds the pk here
        })
        self._current = None

Register it in Django:

serializers.register_serializer("json_no_pk", "path.to.module.with.custom.serializer")

Add use it:

serializers.serialize('json_no_pk', [obj], indent=4, use_natural_keys=True)