Étienne Loks
Étienne Loks

Reputation: 165

Django serialization using natural keys: foreign key to the same model

I have a RelationType model with a foreign key to itself:

class TypeManager(models.Manager):
    def get_by_natural_key(self, slug):
        return self.get(slug=slug)

class RelationType(models.Model):
    name = models.CharField(_(u"Name"), max_length=100)
    slug = models.SlugField(_(u"Slug"), max_length=100, unique=True)
    inverse_relation = models.ForeignKey(
        'RelationType', verbose_name=_(u"Inverse relation"),        
        blank=True, null=True)
    objects = TypeManager()

    def natural_key(self):
        return (self.slug, )

Once serialized it produces this kind of JSON:

[{
    "fields": {
        "name": "Has got",
        "inverse_relation": [
            "is_in"
        ],
        "slug": "has_got"
    },  
    "model": "myapp.relationtype"
},  
{
    "fields": {
        "name": "Is in",
        "inverse_relation": [
            "has_got"
        ],
        "slug": "is_in"
    "model": "myapp.relationtype"
}]

This is logically not loadable by Django:

DeserializationError: Problem installing fixture 'myfixture.json': RelationType matching query does not exist.

Is there a mean to manage this wisely?

Upvotes: 2

Views: 971

Answers (1)

Étienne Loks
Étienne Loks

Reputation: 165

I came up with a pretty ugly solution (I would be glad if someone comes with a better one).

I generate the fixture first:

./manage.py dumpdata --indent 4 --natural-primary --natural-foreign \ 
    myapp.relationtype > fixtures/initial_relationtypes.json

Then I use some UNIX magic to remove "self" relations:

cat fixtures/initial_relation_types.json | tr '\n' '\r' |  \
  sed -e 's/"inverse_relation": *\[\r *\"[-_a-z0-9]*\" *\r *\]/"inverse_relation": null/g' | \
  tr '\r' '\n' > fixtures/initial_relation_type-norel.json

For the curious about UNIX magic, I translate new line character with another arbitrary character because sed cannot do multi lines regular expressions.

Then I can load the two fixtures with the norel fixture first:

./manage.py loaddata fixtures/initial_relation_type-norel.json
./manage.py loaddata fixtures/initial_relation_type.json

Upvotes: 1

Related Questions