Generate a random alphanumeric string as a primary key for a model

django, postgresql, python

Solution

Here's how I would do it without making the field a primary key:

from django.db import IntegrityError

class MyTemporaryObject(models.Model):
    auto_pseudoid = models.CharField(max_length=16, blank=True, editable=False, unique=True)
    # add index=True if you plan to look objects up by it
    # blank=True is so you can validate objects before saving - the save method will ensure that it gets a value

    # other fields as desired

    def save(self, *args, **kwargs):
        if not self.auto_pseudoid:
            self.auto_pseudoid = generate_random_alphanumeric(16)
            # using your function as above or anything else
        success = False
        failures = 0
        while not success:
            try:
                super(MyTemporaryObject, self).save(*args, **kwargs)
            except IntegrityError:
                 failures += 1
                 if failures > 5: # or some other arbitrary cutoff point at which things are clearly wrong
                     raise
                 else:
                     # looks like a collision, try another random value
                     self.auto_pseudoid = generate_random_alphanumeric(16)
            else:
                 success = True

Two problems that this avoids, compared to using the field as the primary key are that:

1) Django's built in relationship fields require integer keys

2) Django uses the presence of the primary key in the database as a sign that `save` should update an existing record rather than insert a new one. This means if you do get a collision in your primary key field, it'll silently overwrite whatever else used to be in the row.

Problem

I would like a model to generate automatically a random alphanumeric string as its primary key when I create a new instance of it. example: ``` from django.db import models class MyTemporaryObject(models.Model): id = AutoGenStringField(lenght=16, primary_key=True) some_filed = ... some_other_field = ... ``` in my mind the key should look something like this "Ay3kJaBdGfcadZdao03293". It's for very temporary use. In case of collision I would like it Django to try a new key. I was wondering if there was already something out there, or a very simple solution I am not seeing (I am fairly new to python and Django). Otherwise I was thinking to do my own version of `models.AutoField`, would that be the right approach? I have already found how to generate the key here, so it's not about the string generation. I would just like to have it work seamlessly with a simple Django service without adding too much complexity to the code. EDIT: Possible solution? What do you think? ``` id = models.CharField(unique=True, primary_key=True, default=StringKeyGenerator(), editable=False) ``` with ``` class StringKeyGenerator(object): def __init__(self, len=16): self.lenght = len def __call__(self): return ''.join(random.choice(string.letters + string.digits) for x in range(self.lenght)) ``` I came up with it after going through the Django documentation one more time.

Original source

Related problems