Opened 6 years ago

Closed 6 years ago

#25904 closed Bug (duplicate)

--fake-initial does not work for ManyToMany with through Model

Reported by: Maciej Pawlisz Owned by: Tim Graham
Component: Migrations Version: 1.9
Severity: Release blocker Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I came across this issue when migrating from django 1.6.11 and south. When model has ManyToMany field then automatic initial migration contains AddField operation for this field, which of course is not present in database, so django thinks that it cannot fake this migration.

How to reproduce:
fake_through.models.py:

from django.db import models
class A(models.Model):
    b = models.ManyToManyField('B', through="C")

class B(models.Model):
    pass

class C(models.Model):
    a = models.ForeignKey('A')
    b = models.ForeignKey('B')

commands:

python manage.py makemigrations fake_through
python manage.py migrate fake_through
python manage.py migrate fake_through zero --fake
python manage.py migrate fake_through --fake-initial
django.db.utils.OperationalError: table "fake_through_a" already exists

Change History (5)

comment:1 Changed 6 years ago by Tim Graham

Did you set the version on the ticket correctly? I might expect that behavior in Django 1.8 but if you generated the migrations with Django 1.9, then they should have the initial attribute set such that this shouldn't happen.

comment:2 Changed 6 years ago by Maciej Pawlisz

It was Django 1.9. From what I see when initial is True, django proceeds to checking db schema and this check fails. Actually it fails with every ManyToManyField, because it is added in AddField operation, but is not present in database schema:
djang.db.migrations.executor.py:291

                db_field = model._meta.get_field(operation.name).column
                fields = self.connection.introspection.get_table_description(self.connection.cursor(), table)
                if db_field not in (f.name for f in fields):
                    return False, project_state

Easy fix would be adding this line before that check:

     if isinstance(operation.field,models.ManyToMany):
        continue

But maybe the bug is somewhere else ie. why model._meta.get_field(operation.name).column is not None for ManyToManyField ?

comment:3 Changed 6 years ago by Tim Graham

Severity: NormalRelease blocker
Triage Stage: UnreviewedAccepted

Thanks, I understand now. I'll have to look at the code a bit more to advise on the proper fix. For reference, db97a8849519a3933bf4abd2184efd68ebc21965 added the Migration.initial option.

comment:4 Changed 6 years ago by Tim Graham

Owner: changed from nobody to Tim Graham
Status: newassigned

comment:5 Changed 6 years ago by Tim Graham

Resolution: duplicate
Status: assignedclosed

The fix for #25904 should address this as whether or not the ManyToManyField uses an explicit through model doesn't matter.

Note: See TracTickets for help on using tickets.
Back to Top