Opened 8 years ago

Last modified 17 months ago

#28438 new Bug

Initial migration creates fields not listed in the migration if mixin class changes — at Version 1

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
Pull Requests:How to create a pull request

Description (last modified by Michal Dabski)

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

This 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's bases, however if mixin extends model.Model it does not.

Tested with Django 1.11.3, Python 2.7

According to the ticket's flags, the next step(s) to move this issue forward are:

  • To provide a patch by sending a pull request. Claim the ticket when you start working so that someone else doesn't duplicate effort. Before sending a pull request, review your work against the patch review checklist. Check the "Has patch" flag on the ticket after sending a pull request and include a link to the pull request in the ticket comment when making that update. The usual format is: [https://github.com/django/django/pull/#### PR].

Change History (1)

comment:1 by Michal Dabski, 8 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top