为django模型生成独特的哈希值

Lak*_*sad 17 python random django hash

我想为每个模型使用唯一的哈希而不是ID.

我实现了以下功能,可以轻松地全面使用它.

import random,hashlib
from base64 import urlsafe_b64encode

def set_unique_random_value(model_object,field_name='hash_uuid',length=5,use_sha=True,urlencode=False):
    while 1:
        uuid_number = str(random.random())[2:]
        uuid = hashlib.sha256(uuid_number).hexdigest() if use_sha else uuid_number
        uuid = uuid[:length]
        if urlencode:
            uuid = urlsafe_b64encode(uuid)[:-1]
        hash_id_dict = {field_name:uuid}
        try:
            model_object.__class__.objects.get(**hash_id_dict)
        except model_object.__class__.DoesNotExist:
            setattr(model_object,field_name,uuid)
            return
Run Code Online (Sandbox Code Playgroud)

我正在寻求反馈,我怎么能这样做?我怎样才能改进它?有什么好坏和丑陋的?

Pio*_*pla 33

我不喜欢这一点:

uuid = uuid[:5]
Run Code Online (Sandbox Code Playgroud)

在最好的情况下(uuid是均匀分布的),你会在1k元素之后发生碰撞,概率大于0.5!

这是因为生日问题.简而言之,当元素数量大于可能标签数量的平方根时,证明碰撞概率超过0.5.

您有0xFFFFF = 10 ^ 6个标签(不同的数字),因此在生成1000个值后,您将开始发生碰撞.

即使你将长度增加到-1,你仍然有问题:

str(random.random())[2:]
Run Code Online (Sandbox Code Playgroud)

您将在3*10 ^ 6之后开始发生碰撞(随后进行相同的计算).

我认为你最好的选择是使用更有可能是唯一的uuid,这是一个例子

>>> import uuid
>>> uuid.uuid1().hex
'7e0e52d0386411df81ce001b631bdd31'
Run Code Online (Sandbox Code Playgroud)

更新 如果你不相信数学,只需运行以下示例来查看碰撞:

 >>> len(set(hashlib.sha256(str(i)).hexdigest()[:5] for i in range(0,2000)))
 1999 # it should obviously print 2000 if there wasn't any collision
Run Code Online (Sandbox Code Playgroud)

  • 生日问题实际上适用于随机数生成.但是,Python的uuid包不涉及特定的随机数生成.实际上,你的例子中的uuid1()与密码安全无关.只是指出这一点,万一有人可能会想到将Python的uuid包与随机数生成等同起来. (4认同)

nik*_*ola 15

丑陋的:

随机导入

从文档:

该模块为各种分布实现伪随机数生成器.

如果有的话,请使用os.urandom

返回一串适合加密使用的n个随机字节.

这是我在模型中使用它的方式:

import os
from binascii import hexlify

def _createId():
    return hexlify(os.urandom(16))

class Book(models.Model):
    id_book = models.CharField(max_length=32, primary_key=True, default=_createId)
Run Code Online (Sandbox Code Playgroud)

  • 不,主键必须是唯一的,所以如果发生碰撞,你会得到一个``IntegrityError``.对那一个没什么沉默. (2认同)

Ign*_*ams 8

使用数据库引擎的UUID支持而不是编写自己的哈希.除了SQLite之外,几乎所有东西都支持它们,因此没有理由不使用它们.

  • 很高兴看到一些关于如何使用Django的ORM做到这一点的例子. (9认同)

Ryn*_*ett 7

Django 1.8+有一个内置的UUIDField.这里的建议执行,使用标准库的uuid模块,从该文档:

import uuid
from django.db import models

class MyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # other fields
Run Code Online (Sandbox Code Playgroud)

对于较旧的django版本,您可以使用django-uuidfield包.