TL DR . There is currently no sensible way to do this without creating a custom Serializer / Deserializer .
The problem with models that have common relationships is that Django does not see target as a field at all, only target_content_type and target_object_id , and it tries to serialize and deserialize them separately.
The classes responsible for serializing and deserializing Django models are in the django.core.serializers.base and django.core.serializers.python . All the rest ( xml , json and yaml ) apply to any of them (and python continues to base ). Field serialization is performed as follows (irrelevant lines):
for obj in queryset: for field in concrete_model._meta.local_fields: if field.rel is None: self.handle_field(obj, field) else: self.handle_fk_field(obj, field)
Here's the first complication: the ContentType foreign key ContentType processed normally, with natural keys, as we expected. But PositiveIntegerField handled by handle_field , which is executed as follows:
def handle_field(self, obj, field): value = field._get_val_from_obj(obj)
i.e. the only setting option here (subclassing PositiveIntegerField and defining custom value_to_string ) will have no effect since the serializer will not call This. Changing the target_object_id data target_object_id to something larger than an integer is likely to break many other things, so this is not an option.
We could define our custom handle_field to emit natural keys in this case, but then a second complication arises: deserialization is done as follows:
for (field_name, field_value) in six.iteritems(d["fields"]): field = Model._meta.get_field(field_name) ... data[field.name] = field.to_python(field_value)
Even if we set up the to_python method, it only field_value , outside the context of the object. This is not a problem when using integers, since it will be interpreted as the primary key of the model , regardless of which model . But for deserializing a natural key, we first need to know which model this key belongs to and that the information is not available if we did not receive a reference to the object (and the target_content_type field target_content_type already been deserialized).
As you can see, this is not an impossible task - supporting natural keys in a generic relationship, but to achieve this, a lot needs to be changed in the serialization and deserialization code. Necessary steps, then (if someone copes with the task):
- Create a custom
Field extending PositiveIntegerField using methods for encoding / decoding an object - calling the reference models natural_key and get_by_natural_key ; - Cancel the
handle_field serializer to invoke the encoder, if any; - Introduce your own deserializer, which: 1) imposes some order in the fields, ensuring that the content type is deserialized in front of the natural key; 2) calls the decoder, passing not only
field_value , but also a link to the decoded ContentType .