Opened 9 years ago
Closed 8 years ago
#27860 closed Bug (fixed)
Changing a CharField to a ForeignKey crashes when migrating in PostgreSQL
| Reported by: | Daniel Quinn | Owned by: | Mariusz Felisiak |
|---|---|---|---|
| Component: | Migrations | Version: | 1.10 |
| Severity: | Normal | Keywords: | PostgreSQL |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
If I have a model that looks like this:
class MyModel(models.Model):
my_field = models.CharField(max_length=128, db_index=True)
makemigrations will create a migration that looks like this:
migrations.CreateModel(
name='MyModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('my_field', models.CharField(db_index=True, max_length=128)),
],
),
However, if I later change the field to a ForeignKey:
class MyOtherModel(models.Model):
stuff = models.CharField(max_length=128)
class MyModel(models.Model):
my_field = models.ForeignKey("alpha.MyOtherModel", blank=True)
makemigrations will create this:
migrations.AlterField(
model_name='mymodel',
name='my_field',
field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, to='alpha.MyOtherModel'),
),
...which explodes in PostgreSQL (but not SQLite or MySQL) with this:
psycopg2.ProgrammingError: operator class "varchar_pattern_ops" does not accept data type integer
The fix (at least for my case) was to manually break up the AlterField into separate RemoveField and AddField steps like this:
migrations.RemoveField(
model_name='mymodel',
name='my_field',
),
migrations.AddField(
model_name='mymodel',
name='my_field',
field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.CASCADE, to='alpha.MyOtherModel'),
),
I ran into this on my own GPL project, and the issue history wherein we found and fixed the problem is here: https://github.com/danielquinn/paperless/issues/183
Change History (7)
comment:1 by , 9 years ago
comment:2 by , 9 years ago
| Description: | modified (diff) |
|---|
alpha.MyOtherModel is using a default numeric key. Sorry, I should have included that in the ticket and so I've modified it to include the MyOtherModel class.
The problem is that migrations is doing an alter for a field that changed not just from a CharField to a ForeignKeyField but rather to a foreign key of a different type. SQLite and MySQL somehow didn't have a problem with this, but PostgreSQL exploded.
Perhaps a solution would be a warning stage not unlike the prompt you get when trying to add a field with no default= value? Something like:
It looks like you've changed a CharField to a ForeignKey of a different type. This will generate an AddField and RemoveField. Is that cool with you?
comment:3 by , 9 years ago
| Summary: | Changing a CharField to a ForeignKey explodes when migrating in PostgreSQL → Changing a CharField to a ForeignKey crashes when migrating in PostgreSQL |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
| Type: | Uncategorized → Bug |
It looks like the varchar_pattern_ops index needs to be dropped before altering the field.
comment:4 by , 9 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
I couldn't reproduce a problem with these final models:
class CharPK(models.Model): id = models.CharField(primary_key=True, max_length=128) class MyModel(models.Model): my_field = models.ForeignKey(CharPK, max_length=128, on_delete=models.CASCADE)Does "alpha.MyOtherModel" have a
CharFieldprimary key?I'm not sure what the proper resolution would be here, considering that automatically generating
RemoveField/AddFieldwould be data loss operations.