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.