Does UUIDField's 'default' attribute takes care of the uniqueness?

Question:

I just jumped into Django for a quick project and I figured there is a UUIDField in the models.

I am using this for an external id field that every model will have to expose the object. Will the default parameter handle the uniqueness or do I have to write it in the save? I mean I know there is practically no chance of values colliding, but just to know how it is done internally

Asked By: Deepankar Bajpeyi

||

Answers:

No, it does not. Here is the relevant part of the code from Django:

def get_db_prep_value(self, value, connection, prepared=False):
    if isinstance(value, six.string_types):
        value = uuid.UUID(value.replace('-', ''))
    if isinstance(value, uuid.UUID):
        if connection.features.has_native_uuid_field:
            return value
        return value.hex
    return value

As you can see, when preparing the value for the database, it simple calls uuid with a replace on hyphens; there’s no check for existing uniqueness. That said, the UUIDField inherits from class Field, which will obey Django’s models unique definition.

Answered By: FlipperPA

How does UUID module guarantees unique values each time?

RFC 4122(UUID module specification) specifies three algorithms to generate UUIDs:

  1. Using IEEE 802 MAC addresses as a source of uniqueness
  2. Using pseudo-random numbers
  3. Using well-known strings combined with cryptographic hashing

In all cases the seed value is combined with the system clock and a clock sequence value (to maintain uniqueness in case the clock was set backwards). As a result, the UUIDs generated according to the mechanisms above will be unique from all other UUIDs that have been or will be assigned.

Taken from RFC 4122 Abstract:

A UUID is 128 bits long, and can guarantee uniqueness across space and
time.

Note: Due to this uniqueness property of UUIDS, there is no check done by Django internally (as mentioned by @FlipperPA) to check if there already exists another object with the same uuid.

Answered By: Rahul Gupta

Django doesn’t enforce the uniqueness of UUIDs. That’s because the main use case for UUIDs is to provide an identifier that can be expected to be unique without having to check with a centralized authority (like a database, which is what unique=True does).

(Note that UUIDs are not guaranteed to be unique, there is just an astronomically small chance of a collision.)

You certainly can use the database to enforce uniqueness on top of the UUIDs if you want (by setting unique=True on your field), but I would say that’s an unusual, and hard to justify, configuration.

I am fond of using UUIDs as primary keys and I am fond of not delivering 500 errors to end users for a simple operation such as create a login. So I have the following classmethod in my model. I siphon off some pre-assigned reserved guids for synthetic transactions on the production database and don’t want those colliding either. Cosmic lightning has struck before, a variant (instrumented to report collision) of the code below has actually fired the second attempt of guid assignment. The code shown below still risks a concurrent write collision from a different app server, so my views go back to this method if write/create operations in the view fail.

I do ack that this code is slower by the time cost of the db lookup, but as guid is my pk it is not ridiculously expensive when the underlying db uses a b-tree index on the field.

@classmethod
def attempt_to_set_guid(cls,attemptedGuid=None):
    while(True):
        try:
            if attemptedGuid is None:
                attemptedGuid = uuid4() 
            elif (attemptedGuid in cls.reserved_guids):
                attemptedGuid = uuid4() 
                continue
            alreadyExists = Guid.objects.get(guid=attemptedGuid)
            break
        except Exception as e:
            break
    return attemptedGuid
Answered By: Stephan Doliov
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.