Opened 10 years ago

Closed 10 years ago

Last modified 10 years ago

#23101 closed Bug (fixed)

Changing name of M2MField while db_table keeps table name unchanged leads to spurious migration that changes table name

Reported by: maney@… Owned by: abraham.martin
Component: Migrations Version: 1.7-rc-2
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

This is the terse version, I'm going to revisit this later as I think this and #22975 share similar root cause: using the apparent/default name and overlooking the db_table that actually sets the table's name.

In Model "Some", have a field like

x = ManyToManyField("Other") # table name app_some_x

Change that to

x_set = ManyToManyField("Other", db_table="app_some_x")

which doesn't actually change anything in the schema, but the migration sees it as a rename of the intermediate table, generates a migration, and changes the name. At this point you can observe in the shell that eg., Some.x_set.field.m2m_db_table() -> app_some_x, but the table in the database has been migrated to app_some_x_set.

(caveat: the above hasn't been tested per se, I'm summarizing to get this on record before I have to go. Marked as 1.7, but while chatting with Andrew I did check it against master - no change.)

Attachments (4)

models-0001.py (846 bytes ) - added by maney@… 10 years ago.
models-0001
models-0002.py (941 bytes ) - added by maney@… 10 years ago.
models-0002
bug.txt (4.4 KB ) - added by maney@… 10 years ago.
description of test results, speculation about root cause
23101.diff (1.5 KB ) - added by abraham.martin 10 years ago.
fix

Download all attachments as: .zip

Change History (15)

by maney@…, 10 years ago

Attachment: models-0001.py added

models-0001

by maney@…, 10 years ago

Attachment: models-0002.py added

models-0002

by maney@…, 10 years ago

Attachment: bug.txt added

description of test results, speculation about root cause

comment:1 by Baptiste Mispelon, 10 years ago

Triage Stage: UnreviewedAccepted
Type: UncategorizedBug

Hi,

I cna reproduce the issue with a very simple scenario and it seems quite serious.

Using these models:

class Foo(models.Model):
    pass


class Bar(models.Model):
    foos = models.ManyToManyField("Foo", db_table='custom_table')

Running manage.py makemigrations and manage.py migrate creates a table called <app_name>__bar_foos instead of custom_table.

This works fine in 1.6 so it's definitely a release blocker.

Thanks.

comment:2 by abraham.martin, 10 years ago

Owner: changed from nobody to abraham.martin
Status: newassigned

by abraham.martin, 10 years ago

Attachment: 23101.diff added

fix

comment:3 by Abraham Martin <abraham@…>, 10 years ago

Resolution: fixed
Status: assignedclosed

In 999758fc7a2d6fcb01eb40de937d4420f884788d:

Fixed #23101 db_table wasn't copied in deconstruct

comment:4 by Andrew Godwin <andrew@…>, 10 years ago

In 37f8a83ad050a1040712876002edcbfc0b057603:

Merge pull request #2977 from abrahammartin/stable/1.7.x

Fixed #23101 db_table wasn't copied in deconstruct

comment:5 by Andrew Godwin <andrew@…>, 10 years ago

In e1347e9253821a31f9896de9eb993e2376e7398f:

Fixed #23101 db_table wasn't copied in deconstruct

Forward port of 999758fc7a2d6fcb01eb40de937d4420f884788d from
stable/1.7.x

comment:6 by maney@…, 10 years ago

Resolution: fixed
Status: closednew
Version: 1.7-rc-11.7-rc-2

The changes in RC2 fix the initial creation, but do little or nothing for the second migration - that still such a mess that I'm not even sure how many ways it fails, though I believe the error reported is the same as ever:

OperationalError: table "x_three_ring" already exists

This is the migration from model-0001 (the initial state) to model-0002

comment:7 by Andrew Godwin, 10 years ago

I cannot replicate - running the models.py files as supplied works perfectly. Can you verify that this still fails for you on the latest master?

comment:8 by Mattias Linnap <mattias@…>, 10 years ago

On both 1.7 RC2 and master, makemigrations and migrate run without errors.
For models One and Two it asks you if you renamed the models. But for models Three and Four, the old fields are removed and new fields are added instead of being detected as renames:

Did you rename the foo.One model to Onesie? [y/N] y
Did you rename the foo.Two model to Twosies? [y/N] y
Migrations for 'foo':
  0002_auto_20140728_1821.py:
    - Rename model One to Onesie
    - Rename model Two to Twosies
    - Add field ring to four
    - Add field ringsies to three
    - Remove field ringsie from four
    - Remove field ring from three

This may or may not be correct, depending on how clever the rename detector is supposed to be?

comment:9 by Andrew Godwin <andrew@…>, 10 years ago

Resolution: fixed
Status: newclosed

In a338e0773592ce4030407428c77815a713b6c9c7:

Fixed #23101: Prefer doing deletes before creates in autodetector.

Makes declined or missed renames still work (but drop data).

comment:10 by Andrew Godwin <andrew@…>, 10 years ago

In 0a4fbf4e13b194383f9eecc0af337a50fb6dfe98:

[1.7.x] Fixed #23101: Prefer doing deletes before creates in autodetector.

Makes declined or missed renames still work (but drop data).

comment:11 by Andrew Godwin, 10 years ago

The rename detector prefers false negatives rather than false positives, so this is expected behaviour.

However, declining or missing the rename was making django emit a CREATE then a DELETE for the fields in that order, rather than (correctly) DELETE then CREATE. I've fixed this, so at least it'll run without errors.

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