У меня есть две управляемые базы данных 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 для преобразования ссылок на внешние ключи в исходной таблице в эквивалентные идентификаторы в целевой таблице.
Подводя итог, можно сказать, что алгоритм будет перебирать таблицу для объединения в порядке зависимости, причем сначала перебираются родители. Поэтому, если мы хотим объединить таблицы auth_users и mycustomprofile, которые зависят от auth_users, мы будем выполнять итерации ['auth_users', 'mycustomprofile'].
Каждая объединенная таблица должна иметь своего рода индикатор, документирующий комбинацию столбцов, которая обозначает универсально уникальную запись (то есть «ключ»). Для auth_users это может быть столбец «username» и / или «email».
Если значение ключа в базе данных B уже существует в A, то запись не импортируется из B, но записывается идентификатор существующей записи в A.
Если значение ключа в базе данных B не существует в A, то запись импортируется из B, и записывается идентификатор новой записи.
Используя ранее записанный идентификатор, создается сопоставление, объясняющее, как сопоставить ссылки внешнего ключа на эту конкретную запись в B с новой объединенной / ранее существующей записью в A. Когда будущие записи объединяются в A, это сопоставление будет использоваться для преобразования внешних ключей.
Я все еще мог бы представить некоторые случаи, когда импортированная запись ссылается на таблицу, не включенную в dumpdata, что может привести к сбою всего импорта, поэтому для моделирования импорта потребуется какая-то опция "dryrun", чтобы гарантировать весь FK ссылки могут быть переведены.
Это похоже на практический подход? Есть ли лучший способ?
РЕДАКТИРОВАТЬ: Это не совсем то, что я ищу, но я думал, что другие могут найти это интересным. Проект Turbion имеет механизм копирования изменений между эквивалентными записями в разных моделях Django в одной базе данных. Он работает, определяя слой перевода (т.е. merging.ModelLayer) между двумя моделями Django, поэтому, скажем, если вы обновите поле «www» в профиле пользователя bob@bob.com, оно автоматически обновит поле «url» в пользователе Другой профиль bob@bob.com.
Функциональность, которую я ищу, немного отличается, в том смысле, что я хочу объединять весь (или частичный) снимок базы данных через нечастые интервалы, в некотором роде, как это делает команда управления загрузкой данных.