简体   繁体   中英

Django keeps recreating foreign key field for legacy database with migrations command

I'm quite new to Django development. I'm working with a legacy database created with MySQL. Now I'm facing a problems with Django migrations. I have few tables that are using foreign keys for the reference to another table. Now if I allow Django to manage those tables with foreign keys, then Django tries to recreate the foreign key fields during make-migrations and migrate command. Even when the fields are already there. Besides this Django is working perfectly with the database if I don't allow Django to manage those table.

My Code is for table facing error

Models.py

from django.db import models
from django.utils.translation import gettext_lazy as _
from django.db.models.signals import pre_save
from chooseright.utils import unique_slug_generator

class StoreTable(models.Model):
    store_id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=45, blank=True, null=True)
    slug = models.SlugField(max_length=45, blank=True, null=True)
    category = models.ForeignKey(CategoryTable, on_delete=models.CASCADE, blank=True, null=True)
    brand = models.ForeignKey(BrandTable, models.DO_NOTHING, blank=True, null=True)
    
    class Meta:
        managed = True
        db_table = 'store_table'
        verbose_name = _("Store")
        verbose_name_plural = _("Stores")

    def __str__(self):
        return self.name

Migration Code

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

    dependencies = [
        ('core', '0009_auto_20200820_1258'),
    ]

    operations = [
        migrations.RenameField(
            model_name='storetable',
            old_name='store_name',
            new_name='name',
        ),
        migrations.AddField(
            model_name='storetable',
            name='brand',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='core.BrandTable'),
        ),
        migrations.AddField(
            model_name='storetable',
            name='category',
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='core.CategoryTable'),
        ),
    ]

Traceback when trying to migrate

  File "C:\Users\Usama\dev\Django Projects\lib\site-packages\MySQLdb\connections.py", line 259, in query
    _mysql.connection.query(self, query)
django.db.utils.OperationalError: (1060, "Duplicate column name 'brand_id'")

Now I know that Django is trying to recreate the foreign key field. But since it is a legacy database, I can't understand why it is happening.

I encountered this issue today when I had to make a small change on a really legacy project using Django 1.11. I believe you are running into this bug . The workaround mentioned in comment 7 worked for me. The bug has not been resolved yet so may be it still happening in newer versions of Django.

Basically you would be performing these steps to get around the issue:

  1. When you initially run inspectdb and to create the model, Django will create the model with managed = False .
  2. In models.py , you should temporarily set managed = True before making migrations.
  3. Then create the migrations using manage.py makemigrations . Do NOT run the migration yet.
  4. Inspect the generated migration file and manually update all managed: True to manage: False .
  5. Lastly go back to your models.py and revert any managed = True to managed = False .
  6. Now run migrations using manage.py migrate .

Once the above steps are complete, you should then convert unmanaged models to managed models by doing this:

  1. In models.py , you will now permanently set managed = True or just delete the managed line altogether as it defaults to True .
  2. Create the migrations using manage.py makemigrations .
  3. Run migrations using manage.py migrate .

At this point you are free to make further updates to the model and you will notice that Django no longer attempts to recreated the ForeignKey that already exists.

According to the docs here , you need to tell django to not manage your model. Set managed=False of your model, if you not want that django creates or modifies anything with its migrations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM