59

I want to generate different/unique id per request in django from models field. I did this but I keep getting the same id.

class Paid(models.Model):
     user=models.ForeignKey(User)
     eyw_transactionref=models.CharField(max_length=100, null=True, blank=True, unique=True, default=uuid.uuid4()) #want to generate new unique id from this field

     def __unicode__(self):
        return self.user
picomon
  • 1,479
  • 4
  • 21
  • 38

5 Answers5

139

Since version 1.8 Django has UUIDField

import uuid
from django.db import models

class MyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    # other fields
madzohan
  • 11,488
  • 9
  • 40
  • 67
64

If you are using Django 1.8 or superior, madzohan's answer is the right answer.


Do it like this:

#note the uuid without parenthesis
eyw_transactionref=models.CharField(max_length=100, blank=True, unique=True, default=uuid.uuid4)

The reason why is because with the parenthesis you evaluate the function when the model is imported and this will yield an uuid which will be used for every instance created.

Without parenthesis you passed just the function needed to be called to give the default value to the field and it will be called each time the model is imported.

You can also take this approach:

class Paid(models.Model):
     user=models.ForeignKey(User)
     eyw_transactionref=models.CharField(max_length=100, null=True, blank=True, unique=True)

     def __init__(self):
         super(Paid, self).__init__()
         self.eyw_transactionref = str(uuid.uuid4())

     def __unicode__(self):
        return self.user
Paulo Bu
  • 29,294
  • 6
  • 74
  • 73
  • 1
    I did that..I'm now getting NULL in my db, it means it's not saving! Should I post my views? – picomon Jun 04 '13 at 18:59
  • 2
    If you have a default value then you won't need `null=True` in the field definition. I'll remove from the answer. Try without that. – Paulo Bu Jun 04 '13 at 19:00
  • 1
    Now getting this error IntegrityError at /pay/ (1048, "Column 'eyw_transactionref' cannot be null") I removed blank=True also. – picomon Jun 04 '13 at 19:06
  • 1
    That's kind of weird. It should work, I'll put an override to the `__init__` method as an alternative. – Paulo Bu Jun 04 '13 at 19:14
  • 1
    Also try this with the default value, maybe it works: `default=lambda:str(uuid.uuid4())`. – Paulo Bu Jun 04 '13 at 19:25
  • Thanks so much now working! I made a mistake in my view! You rock :) – picomon Jun 04 '13 at 22:19
  • Lol! You're welcome :) Finally just for curiosity... what way worked? The first one? – Paulo Bu Jun 05 '13 at 00:33
  • Ah man, I dislike when the accepted answer makes use of something `uuid` that needs to be imported but it isn't in the answer. It just makes the answer that much better, ya know? – teewuane Dec 02 '14 at 23:00
  • @teewuane I understand, but the answer addresses the OP questions, which was already using `uuid` without putting the import statement, that's why I didn't find it relevant to include :) – Paulo Bu Dec 03 '14 at 12:22
  • Hello, I tried your solution and it works, except that my generating function gets called 6 times... I would love to understand why, if you could please explain, that would be great. For info, I use django 1.7. Thanks. – AdelaN Mar 31 '15 at 09:44
  • @AdelaN Must likely because you are creating 6 models. This will call the function every time you instantiate an object from that model. That was the OP's original question – Paulo Bu Aug 04 '15 at 07:34
  • I ran into a serious technical problem. If I specify the uuid function for default, the resulting south migration has an actual hard-coded UUID in it. That absolutely wrong if I understand that correctly, every entity would get that same exact UUID which is hard-coded there? – Csaba Toth Aug 06 '15 at 05:36
  • I mean it would be the *same* for all the entities? That's really bad! – Csaba Toth Aug 06 '15 at 05:43
29

If you need or want to use a custom ID-generating function rather than Django's UUID field, you can use a while loop in the save() method. For sufficiently large unique IDs, this will almost never result in more than a single db call to verify uniqueness:

urlhash = models.CharField(max_length=6, null=True, blank=True, unique=True)

# Sample of an ID generator - could be any string/number generator
# For a 6-char field, this one yields 2.1 billion unique IDs
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
    return ''.join(random.choice(chars) for _ in range(size))

def save(self):
    if not self.urlhash:
        # Generate ID once, then check the db. If exists, keep trying.
        self.urlhash = id_generator()
        while MyModel.objects.filter(urlhash=self.urlhash).exists():
            self.urlhash = id_generator()
    super(MyModel, self).save()
shacker
  • 14,712
  • 8
  • 89
  • 89
2

This answer from Google Code worked for me:

https://groups.google.com/d/msg/south-users/dTyajWop-ZM/-AeuLaGKtyEJ

add:

from uuid import UUID

to your generated migration file.

woodardj
  • 313
  • 1
  • 2
  • 12
1

you can use uuid for this task. UUIDField is a special field to store universally unique identifiers. Universally unique identifiers are a good alternative to AutoField for primary_key. The database will not generate the UUID for you, so it is recommended to use default.

import uuid
from django.db import models
class MyUUIDModel(models.Model):
   id = models.UUIDField(
     primary_key = True,
     default = uuid.uuid4,
     editable = False)

for more detail visit this link

Alphonse Prakash
  • 804
  • 7
  • 17