rrb_bbr
rrb_bbr

Reputation: 3056

Properly Generating Unique Identifier for Django Model

I did the following in my model.py to generate a unique identifier for it:

 12 def rand_key(size):
 13     return ''.join([random.choice(string.letters + string.digits) for i in range(size)])
 14 
 15 
 16 class Share(models.Model):
 17 
 20     resource_content_type = models.ForeignKey(ContentType)
 21     resource_object_id = models.PositiveIntegerField()
 22     resource_content_object = generic.GenericForeignKey('resource_content_type', 'resource_object_id')
 23 
 24     identifier = models.CharField(max_length=16,unique=True,default=rand_key(16))

The thing is that when a try to save consecutively two records, the error message duplicate key value violates unique constraint "share_share_identifier_key" pop up. I'm sure that this is a common feature.

What I'm doing wrong?

Thanks

Edit: Let me just add the the first record is created without any problem and the identifier field has a propoerly "random" value. Is in the cration of the second record that happens the clash. It seems that the rand_key function is somehow beeing cached.

Upvotes: 1

Views: 2423

Answers (2)

Muhammed K K
Muhammed K K

Reputation: 1172

The problem is that you are assigning the output of the random function to the default argument. Then the value will be same for all the entries. Try this code

def rand_key(size):
    return ''.join([random.choice(string.letters + string.digits) for i in range(size)])


class Share(models.Model):
    resource_content_type = models.ForeignKey(ContentType)
    resource_object_id = models.PositiveIntegerField()
    resource_content_object = generic.GenericForeignKey('resource_content_type', 'resource_object_id')
    identifier = models.CharField(max_length=16, unique=True)

    def save(self, force_insert=False, force_update=False, using=None,
         update_fields=None):
        if self.identifier is None:
            self.identifier = rand_key(16)
        models.Model.save(self, force_insert, force_update, using, update_fields)

This will genereate random chars each time a entry is saved.

Upvotes: 5

Mike S
Mike S

Reputation: 1577

A couple corrections to Muhammed K K's answer (would have commented but not allowed). This is overriding the models save method and will add the unique ID when the model is saved the first time.

def save(self, force_insert=False, force_update=False, using=None,
         update_fields=None):
        if self.identifier is None or len(self.identifier) == 0:
            self.identifier = rand_key(16)
        models.Model.save(self, force_insert, force_update, using, update_fields)

I needed to pass self as the first argument to save and check that the identifier was either an empty string OR null. I don't know what causes these differences or if his answer was not intended to be used vertatim... I'm using Django 1.6 and python 2.6.

Upvotes: 2

Related Questions