Why do i get the error " duplicate key value violates unique constraint "" DETAIL: Key (id_application)=(PR-1005576039) already exists

Question:

my models.py

def document_id():
    random_numbers = random.randint(1000000000, 1009999999)
    doc_id = "PR-" + str(random_numbers)
    return doc_id

class Document(models.Model):
    id_application = models.CharField(default=document_id(), unique=True, editable=False)
    applicant_name = models.CharField(max_length=100)
    to_whom = models.CharField(max_length=255, blank=False)
    comment = models.TextField(blank=False)
    email = models.EmailField(blank=False)
    through_whom = models.CharField(max_length=255, blank=False)
    creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    status = models.CharField(max_length=255, choices=STATUS_CHOICES, default='Pending')
    is_private = models.BooleanField(default=False)
    stage = models.CharField(max_length=255, choices=STAGES, default='Departmental Review')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

the problem happens every two times i create a document application, for some reasons it is using the last document application id.
I am using a postgresql database.

Asked By: daevid_thegreat

||

Answers:

Your problem is in this line:

id_application = models.CharField(default=document_id(), unique=True, editable=False)

Although it might seem intuitive that document_id() is called every time you create a new instance of Document, this is not true. This is evaluated only once and later the randomly generated value will be the same. So, in case you didn’t provide the value for id_application when instantiating your model, you will get a duplicated value error when creating a second instance.

To avoid this, you need to provide the default in the __init__ of the model instead and remove the default kwarg from the field definition for clarity.

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    if self.id_application is None:
        self.id_application = document_id()

Or, you can also pass the function to the default and it will get called when creating each object. See the docs.

# Note that there are no parenthesis
id_application = models.CharField(default=document_id, unique=True, editable=False)
Answered By: vinkomlacic