PostgresSQL functions as default value?

Hi there,

I’m trying to use UUID on my Django application, as I prefer to share a UUID instead of a simple ID, this way I have external/internal identificators.

I want Django to tell postgres to set a default value to ‘uuid_generate_v4()’

But it’s not obeying my.

I tried to create a callable with this:

def uuid_generate_v4():
Generates a random UUID based on postgresql native function.

:return: Returns a native UUID.
:rtype: UUID
with connection.cursor() as cursor:
    cursor.execute("SELECT uuid_generate_v4()")
    row = cursor.fetchone()
return row

I also tried this:

class uuid_generate_v4(models.Func):
  template = 'uuid_generate_v4()'
  output_field = models.UUIDField()

But none of it seems to work, is there any way to have a default UUID4 using the uuid-ossp instead of pgcrypto?

As this is more of a PostgreSQL issue than a Django issue, you’ll probably get better answers elsewhere.

But, from what I can quickly find in the PostgreSQL 12 documentation, they have this note:


If you only need randomly-generated (version 4) UUIDs, consider using the gen_random_uuid() function from the pgcrypto module instead.

It looks like the module providing this function, uuid-ossp, isn’t built-in by default - you might need to compile from source.

EDIT: Ok, the above is wrong. As of PostgreSQL 12, the extension is still being provided, it just needs to be installed as an extension in your database:

This allows the following (from the Django shell_plus):

In [21]: c = connection.cursor()                                                                    
In [22]: c.execute("select uuid_generate_v4()")                                                     
In [23]: print(c.fetchone())                                                                        

Edit #2: While looking for something else, I ran across this:


I’m not exactly sure what your use case is so this may not apply, but when I want to include default UUIDs for my models, I apply it to the model field itself.

import uuid

from django.db import models

class MyModel(models.Model):
     uuid = models.UUIDField(default=uuid.uuid4, db_index=True)

I’ve been on projects where an abstract model with a UUIDField is used as the superclass for models where we want UUIDs. UUIDs are handled at the Python level, but it has worked for me in practice.

1 Like

Thanks to both of you.

We were trying to use the select uuid_generate_v4 directly in the ‘default’ field, awaiting that this get’s reflected as a default value in the database, but instead of it, it looks like it just provide this value to the object instead. We wanted to be in database level instead of python level, to make sure the UUID value is not repeated and also save time when the dba is touching the database in raw…

But thinking now, I thing thats a bit fetichist and we can go just with uuid.uuid4 or the option of RandomUUID that comes in django.contrib.

This approach has a “problem” that is unknown to most django developers I have met:

In the save method, will never be None.

This is due to how a model Field starts to behave when the default argument is filled with a value or a callable.

A large number of django users (and a lot of non-official django tutorials) believe that checking in the save method is a safe way to detect and decide whether an instance of a model is new or not.

No, is not reliable for this purpose.
The safe way to detect and decide whether an instance of a model is new or not is to use self._state object

I think the documentation doesn’t emphasize enough on this little point to make sure the developer really understands the implications of that.

(I know I could improve documents, however, English is not my primary language and I feel that I would probably write something more complicated than a native speaker would write)