I'm on the cusp of starting work on a new webapp. Part of this will give users pages that they can customise in a one to many relationship. These pages naturally need to have unique URLs.
Left to its own devices, Django would normally assign a standard AUTOINCREMENT
ID to a model. While this works fantastically, it doesn't look great and it also makes pages very predictable (something that isn't desired in this case).
Rather than 1, 2, 3, 4 I would like set-length, randomly generated alphanumeric strings (eg h2esj4). 6 spots of a possible set of 36 characters should give me over two billion combinations which should be more than enough at this stage. Of course if I could expand this at a later time, that would be good too.
But there are two issues:
Random strings occasionally spell out bad words or other offensive phrases. Is there a decent way to sidestep that? To be fair I could probably settle for a numeric string but it does have a hefty hit on the likelihood of clashes.
How do I get Django (or the database) to do the heavy lifting on insert? I'd rather not insert and then work out the key (as that wouldn't be much of a key). I assume there are concurrency issues to be aware of too though if two new pages were generated at the same time and the second (against all odds) magically got the same key as the first before the first was committed.
I don't see this being a million miles different from how URL shorteners generate their IDs. If there's a decent Django implementation of one, I could piggyback off that.
May be you need to look at Python UUID, it can generate random lengthy characters. But you can slice it and use the number of characters you want with little check to make sure it's unique even after slicing.
UUIDField snippet may help you if you don't want to take pain of generating UUID yourself.
Also have a look at this blog post
There is built-in Django way to achieve what you want. Add a field to the model of "custom page" with
primary_key=True
anddefault=
name of key generation function, like this:Now, for every model instance
page
,page.pk
becomes an alias forpage.mykey
, which is being auto-assigned with the string returned by your functionpkgen()
at the moment of creation of that instance.Fast&dirty implementation:
The probability of two pages getting identical primary keys is very low (assuming
random()
is random enough), and there are no concurrency issues. And, of couse, this method is easilly extensible by slicing more chars from encoded string.Looking at the above answers, here is what I am using now.
Django now includes an UUIDField type, so you don't need any custom code or the external package Srikanth Chundi suggested. This implementation uses HEX strings with dashes, so the text is pretty child-safe, other than 1337 expressions like abad1d3a :)
You would use it like this to alias
pk
to theuuid
field as a primary key:Note, however, that when you're routing to this view in urls.py, you need a different regex as mentioned here, e.g.:
This is what I ended up using UUID.
Oli: If you're worried about spelling out rude words, you can always compare/search your UUIDField for them, using the django profanity filter, and skip any UUIDs that might be triggery.