繁体   English   中英

自动合并任意Django模型

[英]Automatically merging arbitrary Django models

我有两个要合并的Django-ORM托管数据库。 两者都具有非常相似的架构,并且都具有标准的auth_users表,以及其他一些互相引用的共享表以及auth_users,我想将它们自动合并到单个数据库中。

可以理解,这取决于外键关系以及在每个表中构成“唯一”记录的内容,这可能是非常重要的。

有谁知道是否存在执行此合并操作的工具?

如果当前没有类似的东西存在,我正在考虑根据标准的loaddata命令编写自己的管理命令。 本质上,您将使用标准的dumpdata命令从源数据库中导出表,然后使用修改后的版本的loaddata将它们“合并”到目标数据库中。

例如,如果我有数据库A和B,并且想将数据库B合并到数据库A中,那么我想按照伪代码执行以下过程:

merge_database_dst = A
merge_database_src = B
for table in sorted(merge_database_dst.get_redundant_tables(merge_database_src), key=acyclic_dependency):
    key = table.get_unique_column_key()
    src_id_to_dst_id = {}
    for record_src in merge_database_src.table.objects.all():
        src_key_value = record_src.get_key_value(key)
        try:
            record_dst = merge_database_dst.table.objects.get(key)
            dst_key_value = record_dst.get_key_value(key)
        except merge_database_dst.table.DoesNotExist:
            record_dst = merge_database_dst.table(**[(k,convert_fk(v)) for k,v in record_src._meta.fields])
            record_dst.save()
            dst_key_value = record_dst.get_key_value(key)
        src_id_to_dst_id[(table,record_src.id)] = record_dst.id

convert_fk()函数将使用src_id_to_dst_id索引将源表中的外键引用转换为目标表中的等效ID。

总而言之,该算法将按照依赖关系的顺序对要合并的表进行迭代,而父级则首先进行迭代。 因此,如果我们要合并依赖于auth_users的表auth_users和mycustomprofile,我们将迭代['auth_users','mycustomprofile']。

每个合并的表都需要某种指示符,用于记录表示通用唯一记录(即“键”)的列组合。 对于auth_users,可能是“用户名”和/或“电子邮件”列。

如果数据库B中的键值已存在于A中,则不会从B导入记录,而是会记录A中现有记录的ID。

如果数据库B中的键的值在A中不存在,则从B导入记录,并记录新记录的ID。

使用先前记录的ID创建映射,解释如何将B中特定记录的外键引用映射到A中新的合并/预先存在的记录。当将来的记录合并到A中时,将使用此映射转换外键。

我仍然可以设想在某些情况下,导入的记录引用了转储数据中未包含的表,这可能会导致整个导入失败,因此将需要某种“ dryrun”选项来模拟导入,以确保可以将所有FK引用翻译。

这似乎是一种实用的方法吗? 有没有更好的办法?

编辑:这不是我要找的东西,但我认为其他人可能会发现它很有趣。 Turbion项目具有一种机制,可以在同一数据库中的不同Django模型中的等效记录之间复制更改。 它通过定义两个Django模型之间的转换层(即merging.ModelLayer)来工作,因此,例如,如果您更新用​​户bob@bob.com的个人资料中的“ www”字段,它将自动更新用户中的“ url”字段bob@bob.com的其他个人资料。

我要寻找的功能有些不同,因为我想不频繁地合并整个(或部分)数据库快照,这类似于loaddata management命令的方式。

哇。 无论如何,这将是一项复杂的工作。 说:

如果我正确理解了项目的需求,那么可以使用South中的数据迁移来完成。 即使这样,如果我说这将是一个玩笑,我还是会撒谎。

我的建议是-这主要是对您的问题的一个假设的鹦鹉,但是我想澄清一下-您有一个作为基础的“主”表,并且该表还添加了另一表的记录它。 因此,表A保留了它所有的现有记录,并且仅从B中获取添加项。B将添加项添加到A中,一旦完成,B将被删除。

我不愿意为您编写示例代码,因为您的实际工作会比这复杂得多,但是无论如何,我都会尝试为您指明正确的方向。 考虑类似...

import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models

class Migration(DataMigration):
    def forwards(self, orm):
        for b in orm.B.objects.all():
            # sanity check: does this item get copied into A at all?
            if orm.A.objects.filter(username=b.username):
                continue

            # make an A record with the properties of my B record
            a = orm.A(
                first_name=b.first_name,
                last_name=b.last_name,
                email_address=b.email_address,
                [...]
            )

            # save the new A record, and delete the B record
            a.save()
            b.delete()

    def backwards(self, orm):
        # backwards method, if you write one

这将最终将不在A中的所有B迁移到A,并为您提供一个B表,这些B应该是重复的,然后您可以通过其他某种方式对其进行检查,然后再删除。

就像我说的那样,此样本并不意味着是完整的。 如果您决定采用这种方式,请花时间在South文档中 ,尤其要确保您了解数据迁移

那是我的2美分。 希望能帮助到你。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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