Opened 8 years ago
Last modified 2 years 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.Modelto begin with. - if model extends a mixin that extends
object, it ends up in model'sbases, however if mixin extendsmodel.Modelit does not.
Tested with Django 1.11.3, Python 2.7