用随机主键创建Django对象
我正在使用一个API,它要求我为交易生成不透明的“参考ID”,也就是说,这些ID是独一无二的,用户无法猜测或推测出它们的内容。(“infer”这个词用得对吗?)
这是我目前拼凑出来的代码:
randomRef = randint(0, 99999999999999)
while Transaction.objects.filter(transactionRef = randomRef).count():
randomRef = randint(0, 99999999999999)
Transaction.objects.create(user=user, transactionRef=randomRef, price=999)
不幸的是,我的数据库现在似乎缺少一些交易记录。我意识到我的方法并不是特别安全(比如我在多个mod_wsgi apache线程上运行相同的django代码,它们可能会生成相同的randomRef!)
有没有人能给我一些更好的方法来生成随机的主键呢?
6 个回答
6
jbrendel 创建了一个类,你只需要继承这个类就能获得一个自定义的ID。
15
我根据这个问题创建了一个代码片段:https://gist.github.com/735861
根据Amber的建议,私钥是用DES加密和解密的。加密后的密钥用36进制表示,但只要这种表示方式是独特的,其他字符表示法也可以。
任何需要这种加密私钥表示的模型,只需要从代码中展示的模型和管理器继承就可以了。
下面是代码的核心部分:
import struct
from Crypto.Cipher import DES
from django.db import models
class EncryptedPKModelManager(models.Manager):
"""Allows models to be identified based on their encrypted_pk value."""
def get(self, *args, **kwargs):
encrypted_pk = kwargs.pop('encrypted_pk', None)
if encrypted_pk:
kwargs['pk'] = struct.unpack('<Q', self.model.encryption.decrypt(
struct.pack('<Q', encrypted_pk)
))[0]
return super(EncryptedPKModelManager, self).get(*args, **kwargs)
class EncryptedPKModel(models.Model):
"""Adds encrypted_pk property to children."""
encryption = DES.new('8charkey') # Change this 8 character secret key
def _encrypted_pk(self):
return struct.unpack('<Q', self.encryption_obj.encrypt(
str(struct.pack('<Q', self.pk))
))[0]
encrypted_pk = property(_encrypted_pk)
class Meta:
abstract = True
对于一个叫做transaction
的Transaction
对象,transaction.encrypted_pk
会返回私钥的加密表示。Transaction.objects.get(encrypted_pk=some_value)
会根据加密的私钥表示来查找对象。
需要注意的是,这段代码假设只对可以正确表示为长整型的私钥有效。
16
为什么不直接加密普通的顺序ID呢?对那些不知道加密钥匙的人来说,这些ID看起来就像是随机的。你可以写一个工具,在数据发送到数据库的时候自动解密ID,而在从数据库取出数据的时候再加密它。