Opened 7 years ago
Last modified 14 months ago
#28438 new Bug
Initial migration creates fields not listed in the migration if mixin class changes — at Initial Version
Reported by: | Michal Dabski | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | 1.11 |
Severity: | Normal | Keywords: | migration, models, mixin, postgresql |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Consider the sample model with a mixin class:
from django.db import models class TestMixin(object): pass class TestModel(TestMixin, models.Model): sample_field = models.CharField(max_length=20)
When running makemigrations, django creates a perfectly good and valid migration:
# -*- coding: utf-8 -*- # Generated by Django 1.11.3 on 2017-07-26 17:03 from __future__ import unicode_literals from django.db import migrations, models import migration_test.models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='TestModel', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('sample_field', models.CharField(max_length=20)), ], bases=(migration_test.models.TestMixin, models.Model), ), ]
SQL:
BEGIN; -- -- Create model TestModel -- CREATE TABLE "migration_test_testmodel" ("id" serial NOT NULL PRIMARY KEY, "sample_field" varchar(20) NOT NULL); COMMIT;
Next, refactor mixin class to add a field to it - need to change mixin's base class to models.Model
, otherwise field will not be correctly inherited by models:
class TestMixin(models.Model): mixin_field = models.CharField(max_length=20, default='test') class Meta: abstract = True
Thie creates a new migration which adds mixin_field
to it - nothing special. However, when applying both migrations after the model changes, second migration fails with the following error django.db.utils.ProgrammingError: column "mixin_field" of relation "migration_test_testmodel" already exists
. as it turns out, the first migration's SQL has now changed to include mixin_field
:
BEGIN; -- -- Create model TestModel -- CREATE TABLE "migration_test_testmodel" ("id" serial NOT NULL PRIMARY KEY, "mixin_field" varchar(20) NOT NULL, "sample_field" varchar(20) NOT NULL); COMMIT;
The python code of the migration obviously has not changed, but the resulting SQL did, and it includes a field not explicitly listed in the migration's fields
.
Note:
- this does not happen if the mixin class extends
models.Model
to begin with. - if model extends a mixin that extends
object
, it ends up in model'sbases
, however if mixin extendsmodel.Model
it does not.
Tested with Django 1.11.3, Python 2.7