[英]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.