Description
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]