ESSolutions / django-mssql-backend

Django backend for Microsoft SQL Server
https://pypi.org/project/django-mssql-backend/
BSD 3-Clause "New" or "Revised" License
147 stars 51 forks source link

Alter field migration fails if field part of unique_together constraint #84

Open CCattermoul opened 4 years ago

CCattermoul commented 4 years ago

A simple max_length change on a char field will trigger the failure:-

operations = [
    migrations.CreateModel(
        name='TestAlter',
        fields=[
            ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
            ('key', models.CharField(max_length=10)),
            ('value', models.TextField(blank=True, default='')),
            ('uniqueness', models.CharField(max_length=10)),
        ],
        options={
            'unique_together': {('key', 'uniqueness')},
        },
    ),
    migrations.AlterField(
        model_name='TestAlter',
        name='key',
        field=models.CharField(max_length=20),
    ),
]

File "/opt/test/rest/venv_django_2/lib64/python3.6/site-packages/sql_server/pyodbc/base.py", line 553, in execute return self.cursor.execute(sql, params) django.db.utils.ProgrammingError: ('42S11', "[42S11] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]The operation failed because an index or statistics with name 'test_testalter_key_uniqueness_f43d78f4_uniq' already exists on table 'test_testalter'. (1913) (SQLExecDirectW)")

Django 2.2.13 django-mssql-backend 2.8.1

CCattermoul commented 4 years ago

I think my example above over simplifies the problem, apologies. I think it occurs if the original constraint was created in django-pyodbc-azure

rjschave commented 3 years ago

@CCattermoul,

Thank you for posting this comment about django-pyodbc-azure. We've been struggling to figure out why some (Wagtail) migrations apply successfully in some projects, but not others. After seeing your comment, we realized the problem only occurred in older projects that originally used django-pyodbc-azure and were later updated to use django-mssql-backend.

Here's our workaround, in case others have the same issue and find this comment....

  1. Create a new database and apply migrations (using django-mssql-backend). Make sure you apply migrations in the newly created database to the same point as the production database.
  2. Use Redgate's SQL Compare tool to compare the differences between the two databases.
  3. Using SQL Compare, sync the schema differences from the newly created database to the production database.
  4. Apply unapplied migrations in production database (that had previously failed). These migrations should succeed now.

We were able to confirm this works with the trial version of Redgate's SQL Compare.

Another solution would be to dump the data to json (using dumpdata), recreate the database (using django-mssql-backend), and load the data from json (using loaddata). This options doesn't require the use of 3rd party tools.