从迁移数据“许多一对多”到“多到很多通过”在Django(Migrating data from “

2019-06-26 06:48发布

我有一个模型

class Category(models.Model):
    title           = models.CharField(...)
    entry           = models.ManyToManyField(Entry,null=True,blank=True,
                                             related_name='category_entries',
                                             )

那我想重构为具有与每个关系的其他数据:

class Category(models.Model):
    title           = models.CharField(...)
    entry           = models.ManyToManyField(Entry,null=True,blank=True,
                                             related_name='category_entries',
                                             through='CategoryEntry',
                                             )

但南删除现有的表。 我怎样才能保持现有的MTM的关系?

Answer 1:

  1. 没有任何多余的字段创建中间模型,现在。 给它一个唯一约束,以配合现有的并指定表名,以配合现有的:

     class CategoryEntry(models.Model): category = models.ForeignKey(Category) entry = models.ForeignKey(Entry) class Meta: db_table='main_category_entries' #change main_ to your application unique_together = (('category', 'entry')) 
  2. 运行南方架构迁移。

  3. 编辑生成的模式迁移脚本,并注释掉所有的向前和向后的条目,因为你现有的交集表使用重。 添加pass完成的方法。

  4. 运行迁移。

  5. 更新现有的代码。 由于它在说https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-many-relationships ,“不同于一般的多到很多领域,你不能使用添加,创建或分配到创建关系”,所以你需要修改任何现有的应用程序代码,例如

     c.entry.add(e) 

    有可能成为:

     try: categoryentry = c.categoryentry_set.get(entry = e) except CategoryEntry.DoesNotExist: categoryentry = CategoryEntry(category=c, entry=e) categoryentry.save() 

    和:

     e.category_entries.add(c) 

    有可能成为:

     categoryentry = CategoryEntry(category=c, entry=e) #set extra fields here categoryentry.save() 

    和:

     c.entry.remove(e) 

    有可能成为:

     categoryentry = c.categoryentry_set.get(entry = e) categoryentry.delete() 
  6. 一旦这个初始伪迁移已经完成,接下来就可以添加额外的字段到CategoryEntry ,创造进一步的迁移是正常的。



Answer 2:

在Django 1.7+内置迁移中,“状态代码”(即模型的代码定义)的计算方法是不同的,并且需要不同的解决方案。

在南(Django的预1.7),整个“代码状态”被保存在每个迁移 - 但在Django 1.7+内置的迁移,它是从着眼于整个迁移组得来,所以你需要指定“代码状态”的变化在迁移不改变数据库。

和上面一样,这将需要几个步骤来完成。

  1. 创建像上面的答案一个中间模型:

     class CategoryEntry(models.Model): category = models.ForeignKey(Category) entry = models.ForeignKey(Entry) class Meta: db_table = 'main_category_entries' #change main_ to your application unique_together = ('category', 'entry') 
  2. 创建一个自动的迁移与django-admin.py makemigrations和修改代码; 移动业务清单到state_operations一个的论点migrations.SeparateDatabaseAndState操作,并留下database_operations列表为空。 它应该是这样的:

     class Migration(migrations.Migration): operations = [ migrations.SeparateDatabaseAndState( state_operations=[ migrations.CreateModel(CategoryEntry..) ... ], database_operations=[] ), ] 
  3. 编辑CategoryEntry包含你想要什么,并创建一个新的自动迁移与django-admin.py makemigrations



Answer 3:

我会做下列方式:

  1. 添加CategoryEntry类模型,做一个自动模式迁移。 这将添加包含的属性的空表CategoryEntry 。 要注意的是,旧的M2M表保持不变,因为through='CategoryEntry'还没有被添加。

  2. 做数据迁移的所有数据从现有的M2M表在步骤1中创建的表复制到这样做,运行datamigration命令,编辑方法forward()backward()中自动生成相应的迁移脚本。

  3. 现在添加through='CategoryEntry'部分(只是你想要的方式),并做了schemamigration。 这将删除旧表M2M。



文章来源: Migrating data from “Many-To-Many” to “Many-To-Many Through” in django