Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用所需的ForeignKey引用在Django(1.8)应用程序之间移动模型_Python_Database_Django Models_Schema Migration - Fatal编程技术网

Python 使用所需的ForeignKey引用在Django(1.8)应用程序之间移动模型

Python 使用所需的ForeignKey引用在Django(1.8)应用程序之间移动模型,python,database,django-models,schema-migration,Python,Database,Django Models,Schema Migration,这是对这个问题的延伸: 我需要将一组模型从旧应用程序移动到新应用程序。最好的答案似乎是,但由于需要外键引用,事情就有点棘手了@halfnibble在对Ozan答案的评论中提出了一个解决方案,但我仍然无法确定步骤的精确顺序(例如,我何时将模型复制到新应用程序,何时从旧应用程序中删除模型,哪些迁移将位于旧应用程序迁移与新应用程序迁移,等等) 非常感谢您的帮助 在应用程序之间迁移模型。 简而言之,不要这样做 但这个答案在现实生活中的项目和生产数据库中很少起作用。因此,我创建了一个示例来演示这个相当复杂

这是对这个问题的延伸:

我需要将一组模型从
旧应用程序
移动到
新应用程序
。最好的答案似乎是,但由于需要外键引用,事情就有点棘手了@halfnibble在对Ozan答案的评论中提出了一个解决方案,但我仍然无法确定步骤的精确顺序(例如,我何时将模型复制到
新应用程序
,何时从
旧应用程序
中删除模型,哪些迁移将位于
旧应用程序迁移
新应用程序迁移
,等等)


非常感谢您的帮助

在应用程序之间迁移模型。

简而言之,不要这样做

但这个答案在现实生活中的项目和生产数据库中很少起作用。因此,我创建了一个示例来演示这个相当复杂的过程

我正在使用MySQL。(不,那不是我真正的证件)

问题

我正在使用的示例是一个工厂项目,它有一个cars应用程序,最初有一个
Car
模型和一个
轮胎
模型

factory
  |_ cars
    |_ Car
    |_ Tires
汽车
型号与
轮胎
有外键关系。(如中所示,通过汽车模型指定轮胎)

然而,我们很快意识到,
轮胎
将是一个拥有自己视图等的大型模型,因此我们希望它出现在自己的应用程序中。因此,理想的结构是:

factory
  |_ cars
    |_ Car
  |_ tires
    |_ Tires
我们需要保持
汽车
轮胎
之间的外键关系,因为太多依赖于数据的保存

解决方案

第1步。设置设计不好的初始应用程序

浏览

步骤2。创建一个管理界面并添加一组包含外键关系的数据

看法

步骤3。决定将
轮胎
模型移动到自己的应用程序中。精心剪切并将代码粘贴到新的轮胎应用程序中。确保更新
汽车
型号,以指向新的
轮胎。轮胎
型号

然后运行
/manage.py makemigrations
并将数据库备份到某个地方(以防出现严重故障)

最后,运行
/manage.py migrate
并查看doom的错误消息

django.db.utils.IntegrityError:(1217,“无法删除或更新父行:外键约束失败”)

在中查看到目前为止的代码和迁移

第4步。棘手的部分。自动生成的迁移无法看到您只是将模型复制到其他应用程序。因此,我们必须做一些事情来弥补这一点

您可以在“我做了这个测试”中查看最后的迁移,并附上注释,以验证它是否有效

首先,我们将研究
汽车
。您必须进行新的空迁移。实际上,此迁移需要在最近创建的迁移(未能执行的迁移)之前运行。因此,我对我创建的迁移进行了重新编号,并更改了依赖项,以首先运行我的自定义迁移,然后运行
cars
app的最后一次自动生成的迁移

您可以使用以下方法创建空迁移:

./manage.py makemigrations --empty cars
步骤4.a.进行自定义旧应用程序迁移

在第一次自定义迁移中,我只执行“数据库操作”迁移。Django为您提供了拆分“状态”和“数据库”操作的选项。通过查看,您可以看到这是如何完成的

我在这第一步中的目标是将数据库表从
oldapp_model
重命名为
newapp_model
,而不影响Django的状态。您必须根据应用程序名和模型名来确定Django将为您的数据库表命名什么

现在,您可以修改初始的
tires
迁移了

步骤4.b.修改新应用程序初始迁移

操作很好,但我们只想修改“状态”,而不想修改数据库。为什么?因为我们保留了
cars
应用程序中的数据库表。此外,您需要确保以前进行的自定义迁移是此迁移的依赖项。看看轮胎

因此,现在我们在数据库中将
cars.Tires
重命名为
Tires.Tires
,并更改了Django状态以识别
Tires.Tires

步骤4.c.修改旧应用程序上次自动生成的迁移

回到汽车,我们需要修改上次自动生成的迁移。它应该需要我们的第一个定制汽车迁移,以及初始轮胎迁移(我们刚刚修改)

这里我们应该保留
AlterField
操作,因为
Car
模型指向不同的模型(即使它具有相同的数据)。但是,我们需要删除有关
DeleteModel
的迁移行,因为
cars.Tires
模型不再存在。它已完全转换为
轮胎。轮胎
。视图

步骤4.d.清理旧应用程序中的过时模型


最后但并非最不重要的一点是,您需要在cars应用程序中进行最终自定义迁移。在这里,我们将执行“状态”操作,仅删除
cars.Tires
模型。仅因为
cars.Tires
的数据库表已被重命名,所以它才处于状态。这将清除剩余的Django状态。

刚刚将两个模型从
旧应用程序
移动到
新应用程序
,但是FK引用在
应用程序x
应用程序y
的一些模型中,而不是
旧应用程序
的模型中

在这种情况下,请按照Nostalg.io提供的步骤进行操作,如下所示:

#cars/migrations/0002...py :

class AlterModelTableF( migrations.AlterModelTable):
    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        print( 'nothing back on', app_label, self.name, self.table)

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

    database_operations= [
        AlterModelTableF( 'tires', 'tires_tires' ),
        ]
    operations = [
        migrations.SeparateDatabaseAndState( database_operations= database_operations)         
    ]           


#cars/migrations/0004...py :

class AlterModelTableR( migrations.AlterModelTable):
    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        print( 'nothing forw on', app_label, self.name, self.table)
    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        super().database_forwards( app_label, schema_editor, from_state, to_state)

class Migration(migrations.Migration):
    dependencies = [
        ('cars', '0003_auto_20150603_0630'),
    ]

    # This needs to be a state-only operation because the database model was renamed, and no longer exists according to Django.
    state_operations = [
        migrations.DeleteModel(
            name='Tires',
        ),
    ]

    database_operations= [
        AlterModelTableR( 'tires', 'tires_tires' ),
        ]
    operations = [
        # After this state operation, the Django DB state should match the actual database structure.
       migrations.SeparateDatabaseAndState( state_operations=state_operations,
         database_operations=database_operations)
    ]   
  • 将模型从
    旧应用程序
    移动到
    新应用程序
    ,然后更新整个公司的
    导入
    语句
    def migrate_model(apps, schema_editor):
        old_model = apps.get_model('old_app', 'MovingModel')
        new_model = apps.get_model('new_app', 'MovingModel')
        for mod in old_model.objects.all():
            mod.__class__ = new_model
            mod.save()
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('new_app', '0006_auto_20171027_0213'),
        ]
    
        operations = [
            migrations.RunPython(migrate_model),
            migrations.DeleteModel(
                name='MovingModel',
            ),
        ]     
    
    class MigrateOrCreateTable(migrations.CreateModel):
        def __init__(self, source_table, dst_table, *args, **kwargs):
            super(MigrateOrCreateTable, self).__init__(*args, **kwargs)
            self.source_table = source_table
            self.dst_table = dst_table
    
        def database_forwards(self, app_label, schema_editor, from_state, to_state):
            table_exists = self.source_table in schema_editor.connection.introspection.table_names()
            if table_exists:
                with schema_editor.connection.cursor() as cursor:
                    cursor.execute("RENAME TABLE {} TO {};".format(self.source_table, self.dst_table))
            else:
                return super(MigrateOrCreateTable, self).database_forwards(app_label, schema_editor, from_state, to_state)
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('myapp', '0002_some_migration'),
        ]
    
        operations = [
            MigrateOrCreateTable(
                source_table='old_app_mymodel',
                dst_table='myapp_mymodel',
                name='MyModel',
                fields=[
                    ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('name', models.CharField(max_length=18))
                ],
            ),
        ]
    
        migrations.AlterModelTable('historicalmodelname', 'newapp_historicalmodelname'),
    
        migrations.DeleteModel(name='HistoricalModleName'),
    
    #cars/migrations/0002...py :
    
    class AlterModelTableF( migrations.AlterModelTable):
        def database_backwards(self, app_label, schema_editor, from_state, to_state):
            print( 'nothing back on', app_label, self.name, self.table)
    
    class Migration(migrations.Migration):                                                         
        dependencies = [
            ('cars', '0001_initial'),
        ]
    
        database_operations= [
            AlterModelTableF( 'tires', 'tires_tires' ),
            ]
        operations = [
            migrations.SeparateDatabaseAndState( database_operations= database_operations)         
        ]           
    
    
    #cars/migrations/0004...py :
    
    class AlterModelTableR( migrations.AlterModelTable):
        def database_forwards(self, app_label, schema_editor, from_state, to_state):
            print( 'nothing forw on', app_label, self.name, self.table)
        def database_backwards(self, app_label, schema_editor, from_state, to_state):
            super().database_forwards( app_label, schema_editor, from_state, to_state)
    
    class Migration(migrations.Migration):
        dependencies = [
            ('cars', '0003_auto_20150603_0630'),
        ]
    
        # This needs to be a state-only operation because the database model was renamed, and no longer exists according to Django.
        state_operations = [
            migrations.DeleteModel(
                name='Tires',
            ),
        ]
    
        database_operations= [
            AlterModelTableR( 'tires', 'tires_tires' ),
            ]
        operations = [
            # After this state operation, the Django DB state should match the actual database structure.
           migrations.SeparateDatabaseAndState( state_operations=state_operations,
             database_operations=database_operations)
        ]   
    
    rm cars/migrations/*
    ./manage.py makemigrations
    ./manage.py migrate --fake-initial
    
    class M(models.Model):
        a = models.ForeignKey(B, on_delete=models.CASCADE)
        b = models.IntegerField()
    
        class Meta:
            db_table = "new_M"
    
    operations = [
        SeparateDatabaseAndState([], [
            migrations.CreateModel(...), ...
        ]),
    ]