Tuesday, September 22, 2020

Django Migrations: Converting a PK field to ID + PK for Multi-table Inheritance

Dear Django community,

in a project, I'm struggling to fix a problem with my database schema and data migrations.

Here's what I want to do:

My application used to have a "Person" model. As time went by, it turned out that we would also need an model for "Organization". Both should inherit the (non-abstract) model "Actor", that holds attributes that are common between Organizaztions and Persons.

That's what it should look like in the end:

class Actor(models.Model):
    # Actor is new!
    name = models.CharField(...)

class Organization(Actor):
     # organization is new, too!
     # organization attributes ...

class Person(Actor):
    biography = models.TextField(...)

To keep existing data, I created an Actor-instance for each person (using the person's PK value) and used a data migration to copy the attribute values that are common for both Organiation and Person to Actor.

Next, I turned the Person model's PK field into a PK + FK field, thereby linking it with the Actor table:

class Migration(migrations.Migration):
    dependencies = [
        ('resources', 'xxx'),
    ]

    operations = [
        migrations.RenameField(
             model_name='person',
            
old_name
='id',
            
new_name
='actor_ptr_id',
       
)
        migrations.AlterField(
            model_name='person',
            name='actor_ptr_id',
            field=models.OneToOneField(auto_created=True, default=0, on_delete=django.db.models.deletion.CASCADE,
                                       parent_link=True, primary_key=True, serialize=False, to='resources.Actor',
                                       db_column='actor_ptr_id'),
            preserve_default=False

        ),
    ]


My Django app does everything it should – data from both tables (persons and actor) are join when loading person instances from the database.

Here's the hard part:

Whenever I run ./manage.py makemigrations now, a new migration is created. The migration first drops my actor_ptr_id field and then re-creates it (see migration code below). This is quite annoying, because it would break the links between actor and person table. The point seems to be that Django doesn't accept creating xxx_ptr_id links manually. Any ideas how to prevent Django from re-creating this migration over and over again?

class Migration(migrations.Migration):

    dependencies = [
        ('resources', 'xxx'),
    ]

    operations = [
        migrations.RemoveField(
            model_name='person',
            name='actor_ptr_id',
        ),
        migrations.AddField(
            model_name='person',
            name='actor_ptr',
            field=models.OneToOneField(auto_created=True, default=0, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='resources.actor'),
            preserve_default=False,
        ),
    ]

Thanks for any ideas and help!

Best regards
Julian

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/7577e3de-a20e-455a-8931-a04728209900n%40googlegroups.com.

No comments:

Post a Comment