【问题标题】:Automate the generation of natural keys自动生成自然键
【发布时间】:2011-05-28 17:07:18
【问题描述】:

我正在研究一种方法来序列化数据库 A 中的部分数据并在数据库 B 中反序列化它(一种不同安装之间的保存/恢复),我查看了 Django natural keys 以避免出现问题由于重复的 ID。

唯一的问题是我应该为我的所有模型添加一个自定义管理器和一个新方法。有没有办法让 Django 通过查看unique=Trueunique_togheter 字段来自动生成自然键?

【问题讨论】:

标签: django django-models natural-key


【解决方案1】:

请注意这个答案与 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

【讨论】:

  • 这不正是我想要实现的:不是数据库之间的同步,而是同一数据库的单独安装之间的用户驱动的数据交换。即:用户 A 将他的数据插入到他的安装中,然后将数据导出到一个文件中,并将其提供给用户 B,用户 B 将数据加载到他自己的安装中(已经有它的数据)。我想避免任何 ID 冲突(并管理所有其他问题!)
  • 嗨,唐。在这种情况下,您应该使用 GUID 作为您的密钥。数据库可以自动为您生成这些。请参阅唯一标识符。我们有 50 多个仓库都远程插入数据,并使用 SQL Server 复制将它们的数据发送到我们的主数据库。它们都使用 GUID 作为主键,因为它保证是唯一的。效果很好。
【解决方案2】:

在这种情况下,您应该使用 GUID 作为您的密钥。数据库可以自动为您生成这些。 Google 唯一标识符。我们有 50 多个仓库都远程插入数据,并使用 SQL Server 复制将它们的数据发送到我们的主数据库。它们都使用 GUID 作为主键,因为它保证是唯一的。效果很好。

【讨论】:

    【解决方案3】:

    通过扩展 models.Model 类来制作自定义基础模型,并在其中编写您的通用管理器,然后使用自定义 .save() 方法编辑您的模型以扩展自定义基础模型。这不会对您的数据库表结构或旧保存的数据产生副作用,除非您更新一些旧行。如果您有旧数据,请尝试对所有记录进行虚假更新。

    【讨论】:

    • 这是正确的答案,但需要充实...我目前正在处理这个问题,但诀窍是弄清楚如何将字段传递给 NK 查找。另一种可能性是创建返回正确类型的 Manager 类的工厂函数。
    【解决方案4】:

    我的解决方案与自然键无关,而是使用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()
    

    希望对你有帮助

    【讨论】:

    • 谢谢,这个答案的方向是正确的,但它仍然不能满足我的需求:我需要重建在 Django 中依赖于记录 ID 的关系;所以我不能将它设置为 None 并让 Django 分配它。
    猜你喜欢
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-01
    相关资源
    最近更新 更多