如何用对该表唯一的不同整数replaceDjango的主键
我有一个Django的Web应用程序,使用默认的自动递增的正整数作为主键。 此密钥在整个应用程序中使用,并经常插入到URL中。 我不想公开这个号码,以便他们可以猜测我的数据库中的用户或其他实体的数量。
这是一个频繁的要求,我已经看到类似的问题与我的答案。 大多数解决schemebuild议散列最初的主键值。 但是,这些答案都不符合我的需要。 这些是我的要求:
- 我想保持主键字段types为整数。
- 我也不希望在每次读取或写入数据库或与数据库进行比较时不必散列/取消散列该值。 这似乎很浪费这样做只是一次:当logging最初插入数据库
- 哈希/encryption函数不需要是可逆的,因为我不需要恢复原始的顺序密钥。 哈希值只需要是唯一的。
- 哈希值需要唯一唯一的表 – 不普遍唯一。
- 散列值应尽可能短。 我想避免超长的(20个以上的字符)url
什么是最好的方法来做到这一点? 以下工作?
def hash_function(int): return fancy-hash-function # What function should I use?? def obfuscate_pk(sender, instance, created, **kwargs): if created: logger.info("MyClass #%s, created with created=%s: %s" % (instance.pk, created, instance)) instance.pk = hash_function(instance.pk) instance.save() logger.info("\tNew Pk=%s" % instance.pk) class MyClass(models.Model): blahblah = models.CharField(max_length=50, null=False, blank=False,) post_save.connect(obfuscate_pk, sender=MyClass)
理念
我会向你推荐与Instragam使用的相同的方法。 他们的要求似乎紧随你的。
生成的ID应该可以按时间sorting(例如,可以对照片ID列表进行sorting,而无需获取关于照片的更多信息)ID理想情况下应该是64位(对于较小的索引以及像Redis这样的系统中更好的存储)系统应尽可能less地引入新的“移动部件” – 我们如何通过less数工程师来扩展Instagram的很大一部分是select我们信任的简单易懂的解决scheme。
他们提出了一个基于时间戳的数据库,一个数据库碎片和一个自动增量部分的系统。 Sincce你似乎没有使用碎片。 基于时间的组合可以有41位,随机select23位。 如果在同一时间插入logging,那么确实会产生830万的冲突几率。 但在实践中,你永远不可能打到这个。 对,那么代码如何呢?
生成ID
START_TIME = a constant that represents a unix timestamp def make_id(): ''' inspired by http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram ''' t = int(time.time()*1000) - START_TIME u = random.SystemRandom().getrandbits(23) id = (t << 23 ) | u return id def reverse_id(id): t = id >> 23 return t + START_TIME
请注意,上面的代码中的START_TIME
是一些任意的开始时间。 您可以使用time.time()* 1000,获取该值并将其设置为START_TIME
请注意,我发布的reverse_id
方法允许您查看创buildlogging的时间。 如果你需要跟踪这些信息,你可以这样做,而无需添加其他领域! 所以你的主键实际上是保存你的存储,而不是增加它!
该模型
现在这就是你的模型的样子。
class MyClass(models.Model): id = models.BigIntegerField(default = fields.make_id, primary_key=True)
如果你在django之外更改你的数据库,你需要创buildmake_id
作为一个sql函数
作为一个脚注。 这有点像Mongodb为每个对象生成_ID所使用的方法。
你需要分开两个问题:
-
主键(当前是一个自动递增整数)是可以在数据库级别实施的简单,相对可预测的唯一标识符的最佳select。
-
这并不意味着您必须在url中向用户公开它。
我build议添加一个新的UUID字段到你的模型,并重新映射你的视图来使用它,而不是PK,进行对象查找。
一个非常简单的解决scheme就是在将ID发送到外部源之前对其进行简单的encryption。 你可以在回来的时候解密它。
保持AUTO_INCREMENT
,但以半秘密的方式传递它:在cookie中。 它需要一些编码来build立cookie,设置它,并阅读它。 但是,除了严重的黑客之外,cookies都是隐藏的。