我正在研究一种方法来序列化数据库 A 中的部分数据并在数据库 B 中对其进行反序列化(一种不同安装之间的保存/恢复),并且我查看了 Django自然键以避免由于重复 ID 而导致的问题.
唯一的问题是我应该为我的所有模型添加一个自定义管理器和一个新方法。有没有办法让 Django 通过查看unique=True
或unique_togheter
字段自动生成自然键?
我正在研究一种方法来序列化数据库 A 中的部分数据并在数据库 B 中对其进行反序列化(一种不同安装之间的保存/恢复),并且我查看了 Django自然键以避免由于重复 ID 而导致的问题.
唯一的问题是我应该为我的所有模型添加一个自定义管理器和一个新方法。有没有办法让 Django 通过查看unique=True
或unique_togheter
字段自动生成自然键?
请注意,这个答案与 Django 无关,但希望能给您提供另一种选择。
您没有提到您的数据库,但是,在 SQL Server 中有一个BINARY_CHECKSUM()关键字,您可以使用该关键字为行中保存的数据提供唯一值。将其视为针对行中所有字段的哈希。此校验和方法可用于通过检查本地行校验和 <> 远程行校验和来从另一个数据库更新数据库。
下面的这条 SQL 将从远程数据库更新本地数据库。它不会插入新行,因为您使用insert ... where id > @MaxLocalID
SELECT delivery_item_id, BINARY_CHECKSUM(*) AS bc
INTO #DI
FROM [REMOTE.NETWORK.LOCAL].YourDatabase.dbo.delivery_item di
SELECT delivery_item_id, BINARY_CHECKSUM(*) AS bc
INTO #DI_local
FROM delivery_item di
-- Get rid of items that already match
DELETE FROM #DI_local
WHERE delivery_item_id IN (SELECT l.delivery_item_id
FROM #DI x, #DI_local l
WHERE l.delivery_item_id = x.delivery_item_id
AND l.bc = x.bc)
DROP TABLE #DI
UPDATE DI
SET engineer_id = X.engineer_id,
... -- Set other fields here
FROM delivery_item DI,
[REMOTE.NETWORK.LOCAL].YourDatabase.dbo.delivery_item x,
#DI_local L
WHERE x.delivery_item_id = L.delivery_item_id
AND DI.delivery_item_id = L.delivery_item_id
DROP TABLE #DI_local
要使上述工作正常进行,您需要在本地数据库和远程数据库之间建立一个链接服务器:
-- Create linked server if you don't have one already
IF NOT EXISTS ( SELECT srv.name
FROM sys.servers srv
WHERE srv.server_id != 0
AND srv.name = N'REMOTE.NETWORK.LOCAL' )
BEGIN
EXEC master.dbo.sp_addlinkedserver @server = N'REMOTE.NETWORK.LOCAL',
@srvproduct = N'SQL Server'
EXEC master.dbo.sp_addlinkedsrvlogin
@rmtsrvname = N'REMOTE.NETWORK.LOCAL',
@useself = N'False', @locallogin = NULL,
@rmtuser = N'your user name',
@rmtpassword = 'your password'
END
GO
我的解决方案与自然键无关,而是使用picke/unpickle。这不是最有效的方法,但它很容易适应您的代码。我不知道它是否适用于复杂的数据库结构,但如果这不是你的情况,请尝试一下!
当连接到 db A 时:
import pickle
records_a = your_model.objects.filter(...)
f = open("pickled.records_a.txt", 'wb')
pickle.dump(records_a, f)
f.close()
然后移动文件并在连接到 db B 时运行:
import pickle
records_a = pickle.load(open('pickled.records_a.txt'))
for r in records_a:
r.id = None
r.save()
希望这可以帮助
在这种情况下,您应该使用 GUID 作为您的密钥。数据库可以自动为您生成这些。谷歌唯一标识符。我们有 50 多个仓库都远程插入数据,并使用 SQL Server 复制将它们的数据发送到我们的主数据库。它们都使用 GUID 作为主键,因为它保证是唯一的。它工作得很好。
通过扩展 models.Model 类制作自定义基础模型,并在其中编写通用管理器,然后使用自定义 .save() 方法编辑模型以扩展自定义基础模型。这不会对您的数据库表结构或旧保存的数据产生副作用,除非您更新一些旧行。如果您有旧数据,请尝试对所有记录进行虚假更新。