使用随机主键创建django对象

rdr*_*rey 9 python random django primary-key

我正在使用一个API,它希望我为使用API​​的事务生成不透明的"引用ID",换句话说,用户无法以任何方式猜测或推断的唯一引用.(是'推断'适当的英语?)

这就是我目前一起入侵的内容:

randomRef = randint(0, 99999999999999)
while Transaction.objects.filter(transactionRef = randomRef).count():
    randomRef = randint(0, 99999999999999)

Transaction.objects.create(user=user, transactionRef=randomRef, price=999)
Run Code Online (Sandbox Code Playgroud)

不幸的是,我的数据库目前似乎缺少交易.我已经意识到我的方法并不特别是线程安全(假设我在多个mod_wsgi apache线程上运行相同的django代码,它们都可以生成相同的randomRef!)

有没有人有更好的技巧为我生成随机主键?

Amb*_*ber 16

为什么不加密正常的顺序ID呢?对于不知道加密密钥的人来说,ID似乎是随机的.您可以编写一个包装器,在到DB的路上自动解密ID,并在从DB上的路上对其进行加密.


Tre*_*ner 11

我根据这个问题创建了一个要点: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
Run Code Online (Sandbox Code Playgroud)

对于Transaction调用的对象transaction,transaction.encrypted_pk将返回私钥的加密表示. Transaction.objects.get(encrypted_pk=some_value)将基于加密的私钥表示来搜索对象.

应该注意的是,此代码假定仅适用于可以正确表示为长值的私钥.


xst*_*ter 6

jbrendel创建了一个类,您可以简单地继承它以获取自定义ID.

https://github.com/jbrendel/django-randomprimary