#34027: When ForeignKey target field type is changed from CharField to
IntegerField, varchar_pattern_ops index is not dropped on PostgreSQL and
migration fails
--------------------------------------+----------------------------
Reporter: Chris | Owner: nobody
Type: Bug | Status: new
Component: Migrations | Version: 3.2
Severity: Normal | Keywords: PostgreSQL
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
--------------------------------------+----------------------------
When a `ForeignKey` points to `CharField`, and the `CharField` is then
changed to e.g. an `AutoField`, the migration fails with:
{{{psycopg2.errors.DatatypeMismatch: operator class "varchar_pattern_ops"
does not accept data type bigint}}}
The reason seems to be that the original `ForeignKey` column in the
database was a `varchar`, and Django created a `varchar_pattern_ops` index
for it (e.g. one of those `..._like` indexes). Changing the column type to
`bigint` is not accepted by this index.
Manually dropping the index before attempting to run the migrations
results in the migration being performed successfully.
Performing the same set of migrations on SQLite and on MySQL does not
result in an error, it only fails on PostgreSQL.
----
Test case:
- Use models.py:
{{{
class ModelA(models.Model):
# Custom CharField primary key
id = models.CharField(max_length=10, primary_key=True)
class ModelB(models.Model):
modela = models.ForeignKey(ModelA, on_delete=models.CASCADE)
}}}
- Run `makemigrations` and `migrate` commands
- Alter `ModelA`:
{{{
class ModelA(models.Model):
# No more custom primary key
pass
}}}
- Run `makemigrations` and `migrate` commands again
- Observe error on PostgreSQL, success on SQLite and MySQL
- Manually `DROP` the `<applabel>_modelb_modela_id_<...>_like` index in
PostgreSQL
- Again run the `migrate` command
- Now the migration succeeds
----
The problem is apparently that the
`BaseDatabaseSchemaEditor._alter_field()` method simply calls
`_alter_column_type_sql()` or `_alter_column_collation_sql()` to directly
change the column type of relations pointing to the field. These methods
do not generate any additional SQL related to indexes etc as the normal
(PostgreSQL version of) `_alter_field` method would under similar
circumstances. Note that the `..._like` index for the primary key itself
_is_ dropped.
Similarly also, if the primary key field is changed in the other
direction, e.g. from `AutoField` to `CharField`, the `..._like` index is
not added to the existing `ForeignKey`, it is only added for the primary
key field, as it normally is when an integer field is changed to a text
field.
Possibly related issues: #27338 #27860
Reported for version 3.2 but also observed on 4.1.
--
Ticket URL: <https://code.djangoproject.com/ticket/34027>
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 view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/0107018360873a1d-0ed2a052-2d37-44a6-97d2-5dec97cc4ac4-000000%40eu-central-1.amazonses.com.