Skip to content

Migration can fail if previous migration has an index with a field that starts with hyphen #405

Open
@ivancvetkovic-z

Description

@ivancvetkovic-z

Software versions

  • Django: 5.0.6
  • mssql-django: 1.5
  • python: 3.10.12
  • SQL Server: 16.0.1000.6
  • OS: Ubuntu 22.04.4 LTS

Table schema and Model

class Post(models.Model):
    title = models.CharField(max_length=200, null=True)
    date_posted = models.DateTimeField()

    class Meta:
        indexes = [models.Index(fields=['-date_posted'])]

Database Connection Settings

DATABASES = {
    "default": {
        "ENGINE": "mssql",
...
        "OPTIONS": {"driver": "ODBC Driver 18 for SQL Server", 'extra_params': "Encrypt=no"},
    },
}

Problem description and steps to reproduce
Migration raises exception when it calls _delete_indexes in schema.py and the previous migration has an index with a field that starts with a hyphen (descending order).

Make a project with the model above and two migrations:

migrations/0001_initial.py

class Migration(migrations.Migration):
    initial = True
    dependencies = []

    operations = [
        migrations.CreateModel(
            name='Post',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('title', models.CharField(max_length=200)),
                ('date_posted', models.DateTimeField()),
            ],
            options={
                'indexes': [models.Index(fields=['-date_posted'], name='blogs_post_date_po_acca62_idx')],
            },
        ),
    ]

migrations/0002_alter_post_title.py

class Migration(migrations.Migration):
    dependencies = [('blogs', '0001_initial'),]

    operations = [
        migrations.AlterField(model_name='post', name='title', field=models.CharField(max_length=200, null=True)),
    ]

Run python manage.py migrate on an empty database.

Expected behavior and actual behavior
The both migrations should succeed.

Instead, the migration 0002_alter_post_title breaks with the exception django.core.exceptions.FieldDoesNotExist: Post has no field named '-date_posted'

Error message/stack trace

Traceback (most recent call last):
  File "/home/user/PycharmProjects/idxtest/manage.py", line 22, in <module>
    main()
  File "/home/user/PycharmProjects/idxtest/manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/core/management/__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/core/management/base.py", line 413, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/core/management/base.py", line 459, in execute
    output = self.handle(*args, **options)
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/core/management/base.py", line 107, in wrapper
    res = handle_func(*args, **kwargs)
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/core/management/commands/migrate.py", line 356, in handle
    post_migrate_state = executor.migrate(
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/db/migrations/executor.py", line 135, in migrate
    state = self._migrate_all_forwards(
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/db/migrations/executor.py", line 167, in _migrate_all_forwards
    state = self.apply_migration(
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/db/migrations/executor.py", line 252, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/db/migrations/migration.py", line 132, in apply
    operation.database_forwards(
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/db/migrations/operations/fields.py", line 235, in database_forwards
    schema_editor.alter_field(from_model, from_field, to_field)
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/db/backends/base/schema.py", line 893, in alter_field
    self._alter_field(
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/mssql/schema.py", line 618, in _alter_field
    indexes_dropped = self._delete_indexes(model, old_field, new_field)
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/mssql/schema.py", line 926, in _delete_indexes
    columns = [model._meta.get_field(field).column for field in index.fields]
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/mssql/schema.py", line 926, in <listcomp>
    columns = [model._meta.get_field(field).column for field in index.fields]
  File "/home/user/.local/share/virtualenvs/idxtest-Z4Fcl3b8/lib/python3.10/site-packages/django/db/models/options.py", line 683, in get_field
    raise FieldDoesNotExist(
django.core.exceptions.FieldDoesNotExist: Post has no field named '-date_posted'

Any other details that can be helpful
The problem is this line in _delete_indexes from schema.py

            columns = [model._meta.get_field(field).column for field in index.fields]

If the index.fields has a field in descending order, that field has a hyphen before the name and the get_field fails. The offending line should use index.fields_orders instead:

            columns = [model._meta.get_field(field).column for field, _ in index.fields_orders]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions