#27860: Changing a CharField to a ForeignKey explodes when migrating in
PostgreSQL
-------------------------------+--------------------------------------
Reporter: Daniel Quinn | Owner: nobody
Type: Uncategorized | Status: new
Component: Migrations | Version: 1.10
Severity: Normal | Resolution:
Keywords: PostgreSQL | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Old description:
> 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 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
New description:
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
--
Comment (by Daniel Quinn):
`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?
--
Ticket URL: <https://code.djangoproject.com/ticket/27860#comment:2>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/069.18b9e982b8a05c8f4e7f808c245de013%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.