djangopostgresqlmodelmigrationradix

Django error migrating nesting model w/o migrating base model


Purpose to have one BaseModel that can be nested by other models

NOTE: BaseModel should not be written to database

So I have one BaseModel like below

class StaticVariable(models.Model):
    class Meta:
        managed = False
    title = models.CharField(
        max_length=250, blank=False, null=False
    )
    alias = models.CharField(
        max_length=250, blank=False, null=False, unique=True
    )
    created_at = models.DateTimeField(
        auto_now_add=True, blank=False, null=False
    )
    updated_at = models.DateTimeField(
        auto_now=True, blank=False, null=False
    )
    enabled = models.BooleanField(
        default=True, blank=False, null=False
    )
    deleted = models.BooleanField(
        default=False, blank=False, null=False
    )

I made migrations and applied it, since class Meta has managed=False parameter, actual SQL table is not being created (as expected)

After that I create new model which is being nested from StaticVariable model as base

class BodyType(StaticVariable):
    class Meta:
        db_table = 'body_type'
        ordering = ["title", "-id"]

Then I makemigrations, which looks like this

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('utils', '0004_staticvariable'),
        ('app', '0002_alter_category_enabled'),
    ]

    operations = [
        migrations.CreateModel(
            name='BodyType',
            fields=[
                ('staticvariable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='utils.staticvariable')),
            ],
            options={
                'db_table': 'body_type',
                'ordering': ['title', '-id'],
            },
            bases=('utils.staticvariable',),
        ),
    ]

But, unexpectedly I catch below error when I try to migrate

Running migrations:
  Applying app.0003_bodytype...Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/django/db/backends/utils.py", line 87, in _execute
    return self.cursor.execute(sql)
  File "/usr/local/lib/python3.10/site-packages/psycopg/cursor.py", line 737, in execute
    raise ex.with_traceback(None)
psycopg.errors.UndefinedTable: relation "utils_staticvariable" does not exist

I suppose that this is because BaseModel wasn't written to the DB, but I don't want to write empty table to DB


Solution

  • When you inherit from a model Django by default sets up a one-to-one relationship with the base model, which is why it's trying to create a staticvariable_ptr field in your BodyType model that points to a StaticVariable instance.

    As in your code StaticVariable has managed = False, Django doesn't manage the database table for this model, which leads to the error you are facing.

    To solve the issue you should use abstract base classes (Ref. Django Abstract Base Class)

    You define an abstract base class by setting abstract = True in the Meta class of StaticVariable model like this:

    class StaticVariable(models.Model):
        class Meta:
            abstract = True
    

    After making these changes make sure to make new migrations and migrate.