0

I am developing an app in Django.

I wanted to insert in my model an auto-incrementing alphanumerical unique ID field, having, by default, a fixed alphabetical part and an auto-incrementing numerical part. But I also want the availability to change, from admin section, this id to another alphanumerical one, with a different alphanumerical and numerical part.

I tryed to implement this, but it turned out that trying to implement such a field and making it the autofield of the model generates problems in my database.

So I am changing my aim: now I want to implement a time-based alphanumerical unique field with predefined aplphabetic part. Please note: I don't want to overwrite the django default id field, I just want to include in my model a field that gets as default value a unique customized alphanumerical value.

Here is what I did, in my models.py:

def return_timestamped_id():
    prefix = "ITCH"    
    import time
    this_time = time.time()
    this_time  = this_time  *10000000
    this_time  = int(this_time)
    timestamp = str(this_time)
    default_value = prefix + timestamp
    return(default_value)

class object_example(models.Model):
    name = models.CharField(max_length=256, blank=True, null=True)    
    Id_generated = models.CharField(max_length=256, blank=False, null=False, unique=True, default=return_timestamped_id())

The problem is that, as I add objects to this model from the admin section, The Id_generated is always the same.

I expected that the return_timestamped_id() function was called every time I add a new object. It is clear instead that is called just once and then the same return value is passed to the Id_generated of every new object.

How can I change my code in order to get a different timestamp every time a new object is added?

Tms91
  • 3,456
  • 6
  • 40
  • 74

1 Answers1

1

As you probably saw in the Django docs, you can use either a value or a callable as a default. If you use a callable (e.g. a function) then it will be called each time a default is needed.

The problem: you were passing a value because you were calling your function default=return_timestamped_id(). The function was being called once, when your module (models.py) was imported into the application.

The solution: pass the function itself default=return_timestamped_id

You can see in the django.models.Fields class the relevant code (comments mine):

class Field():
    def __init__(self, ..., default=NOT_PROVIDED,...):
        ...
        self.default = default  # save the default as a member variable
        ...

    def get_default(self):
        """Return the default value for this field."""
        return self._get_default()

    @cached_property
    def _get_default(self):
        if self.has_default():
            if callable(self.default):  # if it is callable, return it
                return self.default
            return lambda: self.default # else wrap in a callable
FiddleStix
  • 3,016
  • 20
  • 21
  • thanks, I expected that passing "default=return_timestamped_id()" meant "pass the function, with no input". Then I expect that if later I change my function so that it takes one input (eg. default=return_timestamped_id(input_1), then I will type "default=return_timestamped_id(input_1)". Is it correct? – Tms91 Feb 17 '20 at 13:30