2010-03-25 41 views
17

Tôi muốn sử dụng các băm duy nhất cho mỗi mô hình thay vì các id.Tạo các băm duy nhất cho các kiểu django

Tôi đã thực hiện chức năng sau để sử dụng nó trên bảng dễ dàng.

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 

Tôi đang tìm kiếm phản hồi, tôi có thể làm gì khác? Làm thế nào tôi có thể cải thiện nó? Điều gì là tốt xấu và xấu xí về nó?

+0

Bạn có thể vui lòng làm rõ: Bạn có cần băm ngẫu nhiên hoặc băm duy nhất không gian và thời gian không? Tôi hỏi bởi vì người dùng thường chỉ muốn trước đây nhưng sử dụng các thuật ngữ "duy nhất" và "ngẫu nhiên" thay thế cho nhau. – nikola

+0

Bạn có thể đăng cập nhật về cách bạn đã sửa không? Tôi đang tìm kiếm một giải pháp. – Thomas

+0

Thật điên rồ khi tạo một id duy nhất. Nếu làm uuid chỉ tạo ra một uuid và không thay đổi chiều dài hoặc bất cứ điều gì. Đặt mô hình của bạn để sử dụng trường đó làm khóa chính. Chỉ cần tạo một uuid khi lưu, đừng lo lắng về va chạm. – dalore

Trả lời

7

Sử dụng hỗ trợ UUID của công cụ cơ sở dữ liệu thay vì tạo mã băm của riêng bạn. Hầu hết mọi thứ ngoài SQLite đều hỗ trợ chúng, vì vậy có rất ít lý do để không sử dụng chúng.

+9

Nó sẽ là tốt đẹp để xem một số ví dụ về cách làm điều đó với ORM của Django. –

+0

tốt, nó không phải là "django" điều. Trong postgresql bạn có http://www.postgresql.org/docs/8.3/static/datatype-uuid.html này. Tôi nghĩ rằng trong cơ sở dữ liệu khác, họ có một cái gì đó tương tự –

30

tôi không thích điều này chút:

uuid = uuid[:5] 

Trong kịch bản tốt nhất (uuid được phân bố đều), bạn sẽ nhận được một vụ va chạm với xác suất lớn hơn 0,5 sau 1k của các yếu tố!

Đó là vì số birthday problem. Tóm lại, chứng minh rằng xác suất va chạm vượt quá 0,5 khi số phần tử lớn hơn số căn bậc hai so với số nhãn có thể.

Bạn có 0xFFFFF = 10^6 nhãn (số khác nhau) vì vậy sau 1000 giá trị được tạo, bạn sẽ bắt đầu có xung đột.

Thậm chí nếu bạn phóng to dài đến -1 bạn vẫn còn có vấn đề ở đây:

str(random.random())[2:] 

Bạn sẽ bắt đầu có va chạm sau 3 * 10^6 (các tính toán tương tự sau).

Tôi nghĩ rằng đặt cược tốt nhất của bạn là sử dụng uuid rằng có nhiều khả năng là duy nhất, đây là một ví dụ

>>> import uuid 
>>> uuid.uuid1().hex 
'7e0e52d0386411df81ce001b631bdd31' 

Cập nhật Nếu bạn không tin tưởng toán học chỉ cần chạy các mẫu sau đây để xem va chạm:

>>> 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 
+4

Vấn đề sinh nhật thực sự áp dụng cho việc tạo số ngẫu nhiên. Tuy nhiên, gói uuid của Python không liên quan đến việc tạo số ngẫu nhiên cụ thể. Trên thực tế, uuid1() từ ví dụ của bạn không ở đâu gần như ngẫu nhiên như trong bảo mật mã hóa. Chỉ cần chỉ ra điều này trong trường hợp ai đó có thể có được ý tưởng để đánh đồng gói uuid của Python với việc tạo số ngẫu nhiên. – nikola

14

Các xấu xí:

nhập khẩu ngẫu nhiên

From the documentation:

Module này thực hiện giả ngẫu nhiên máy phát số cho các bản phân phối khác nhau.

Nếu bất cứ điều gì, xin vui lòng sử dụng os.urandom

Return một chuỗi các byte n ngẫu nhiên thích hợp cho việc sử dụng mật mã.

Đây là cách tôi sử dụng nó trong các mô hình của tôi:

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) 
+0

Một điều cần lưu ý là urandom chậm hơn nhiều so với giả ngẫu nhiên vì vậy nếu bạn không cần nó vì lý do mật mã, nó có thể không đáng để sử dụng. Trên osx mac của tôi nó là ** 21 lần ** chậm hơn. Hãy xem xét: >>> timeit.Timer ('nhập ngẫu nhiên; random.random()'). Timeit (100000) 0.1538231372833252 >>> timeit.Timer ('os nhập khẩu; os.urandom (2)') .timeit (100000) 3.1858959197998047 –

+0

Tôi vừa kiểm tra xem uuid có còn chậm hơn không :) –

+0

Điều này rất nguy hiểm! Nếu bạn có một va chạm chính thì bản ghi mới của bạn sẽ âm thầm ghi đè lên bản ghi hiện có của bạn. – sherbang

5

Django 1.8+ đã tích hợp sẵn UUIDField. Dưới đây là việc thực hiện đề nghị, sử dụng mô-đun thư viện chuẩn của uuid, từ the docs:

import uuid 
from django.db import models 

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

Đối với phiên bản django cũ hơn, bạn có thể sử dụng gói django-uuidfield.

Các vấn đề liên quan