如何在Django迁移中手动删除和重新创建外键约束

2024-10-02 20:43:15 发布

您现在位置:Python中文网/ 问答频道 /正文

我想我有一个不太清楚的案子,Django没有涉及。 我使用的是django1.11.20,当使用mySQL时,这个问题就显现出来了,使用sqlite没有问题(因为它不使用foreignkey约束)

这是设置。

  • 我有一个名为'Function'的模型,它有一个自动主键字段'id'(由Django制作)
  • 我有一个名为“Training”的模型,在这个模型上有一个叫做“subscribe\u functions”的多个关系,它指向函数。你知道吗

    class Training(RegistrationBlock):

    subscribe_functions = models.ManyToManyField('Function', blank=False, limit_choices_to={'avail_option': True},
                                             related_name="trainings",
                                             verbose_name=_('Functiongroups that may register'),
                                             help_text=_('People in the selected functions may register their '
                                                         'availability'))
    

所以Django为这个表做了一个很好的中间表,在那个表上有一个外键约束,列'function\ id'指向这个约束函数id是的

问题来了。

现在我想在不丢失数据的情况下为函数添加一个父模型,并实际将一些数据移动到父模型中。 因此,我创建父模型('CoreFunction')并将其迁移(它在一个单独的应用程序中),然后在我的migration for Function中执行以下操作:

  • 将函数上的字段“id”重命名为“corefunction\u ptr”

    migrations.RenameField(
        model_name='function',
        old_name='id',
        new_name='corefunction_ptr'
    ),
    
  • 通过RunPython操作将一些数据从子模型传输到父模型

  • 然后这样做:

    migrations.AlterField(
        model_name='function',
        name='corefunction_ptr',
        field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='rlgcore.CoreFunction'),
    ),
    

本质上是将corefunction_ptr字段转换为primary_key字段并将其指向父模型。你知道吗

在mySQL数据库上运行这个迁移时,我得到一个错误,即存在foreignkey约束,并且corefunction\u ptr字段不能修改。你知道吗

_mysql_exceptions.OperationalError: (1846, 'ALGORITHM=COPY is not supported. Reason: Columns participating in a foreign key are renamed. Try ALGORITHM=INPLACE.')

通过我的数据库,我发现这是对中间表training\u subscribefunctions的约束。你知道吗

我将它定位到这个查询中(在phpmyadmin中抛出它时会出现相同的错误)。 ALTER TABLE 'pe_function' CHANGE 'corefunction_ptr' 'corefunction_ptr_id' integer NOT NULL;

然而,有另一个模型通过ForeignKey链接到函数,对于该表,约束被删除,稍后将重新创建。(我跑python manage.py sqlmigrate [appname] [migrationname]去看看发生了什么)

Ifound the code in Django决定是否应放弃外键约束,但由于它被确定为反向多个2,因此决定结果为假。你知道吗

所以问题是

如何在迁移文件中编写代码来检查我试图重命名id字段的模型是否有更多限制,然后删除限制,然后再次添加?你知道吗

我通过原始SQL查询找到了a way to find the restraints pointing to a table。但是,我必须将所有找到的信息存储在某个地方(全局变量?)以后再加上同样的约束。我更愿意使用Django代码本身(例如来自BaseDatabaseSchemaEditor._alter_field),但我不知道如何使用。你知道吗

我知道可以提供给RunPython操作的函数会得到一个模式编辑器,但我不知道如何/在哪里获得以及如何传递_delete_constraint_sql_create_fk_sql期望的参数。你知道吗

我想用尽可能少的字段/表名/模型名等硬编码来解决这个问题。你知道吗

有什么想法吗?你知道吗


Tags: todjango函数namein模型idtrue