Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I load fixtures with circular foreign keys in django?

I have a model for categories, which contains a circular foreign key. I dumped all the data from this model and I created a data migration with django-south for loading them into a different DBMS, but I having a lot of problem doing it, because of this circular dependency.

This is the model I'm referring:

class Category(MPTTModel):
    name = models.CharField(_('name'), max_length=50, unique=True)
    parent = models.ForeignKey('self', null=True, blank=True, related_name='categories')
    description = models.TextField(_('description'), blank=True, null=True)
    created_on = models.DateTimeField(auto_now_add = True, default=date.today())
    updated_on = models.DateTimeField(auto_now = True, default=date.today())

    def __unicode__(self):
        return "%s" %(self.name)

    class Meta:
        verbose_name = _('category')
        verbose_name_plural= _('categories')
like image 875
Yasel Avatar asked Nov 08 '11 03:11

Yasel


2 Answers

Thanks to this post I could find a solution. Temporarily disable foreign key checks while you load in data is the best feasible solution for this issues. Since Django doesn't provide a way to do this, we should execute raw sql code. So, I created a data migration with django-south and the rest is in the code below:

class Migration(DataMigration):

    def forwards(self, orm):
        #~ Disable foreign key checks during fixture loading
        from django.db import connections, DEFAULT_DB_ALIAS
        connection = connections[DEFAULT_DB_ALIAS]
        if 'mysql' in connection.settings_dict['ENGINE']:
            cursor = connection.cursor()
            cursor.execute('SET foreign_key_checks = 0')

        #~ Load fixture
        from django.core.management import call_command
        call_command('loaddata', 'categories_fixture.json', verbosity=0)

        #~ Enable foreign key checks after fixture loading
        if 'mysql' in connection.settings_dict['ENGINE']:
            cursor = connection.cursor()
            cursor.execute('SET foreign_key_checks = 1')
        connection.close()
like image 195
Yasel Avatar answered Oct 17 '22 23:10

Yasel


The quick answer is that you need to disable foreign key constraints while loading.

There's a patch for Django, but it may or may not be in the version you are using:

https://code.djangoproject.com/ticket/3615


Alternatively, don't use fixtures, use SQL: https://docs.djangoproject.com/en/dev/howto/initial-data/#providing-initial-sql-data

The upside is that you can do anything in a model SQL file that you can do in SQL. The downside is that it is no longer database-agnostic, depending on the SQL you are using.

like image 22
Scott A Avatar answered Oct 17 '22 22:10

Scott A