1

I am developing an app in Django.

I want to insert in my model an auto-incrementing alphanumerical 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.
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 an auto-incrementing alphanumerical value.

Example of what I want:

  • Desired alphabetical constant part: ITM

  • Desired numerical auto-incrementing part: 00000

    So that every object of my model, when generated, get default progressive values like: ITM00001, ITM00002, ITM00003, ...

  • Also, I would like to be able to change the field value from my admin section into values like ABC0000001, DFG0051, RST034, ...

  • Max field length: 10 (It can be also higher)

I realize that I have to use AutoField and to somehow join the constant string with the auto-incrementing numerical variable, but I don't know how to do it.

class my_model(models.Model):

    Field_1 = models.CharField(max_length=10, blank=True, null=True)
    static_ID = models.AutoField(???)

What code should I write to get a field with the features I described upwards?

Tms91
  • 3,456
  • 6
  • 40
  • 74

3 Answers3

2

Instead of storing it, why not using a property method to generate that id? For example:

class MyModel(models.Model):

    field_one = models.CharField(max_length=10, blank=True, null=True)
    
    @property
    def static_id(self):
        'ITM{0:07d}'.format(self.pk)

If you are concerned with filtering, then you can use custom manager method:

class CustomManager(models.Manager):
    def get_id(self, static_id):
        return int(static_id[2:])
    def filter_static_id(self, static_id):
        _id = self.get_id(static_id)
        return self.filter(pk=_id)
    
  def filter_static_id(self, static_id):
        _id = self.get_id(static_id)
        return self.get(pk=_id)

 class MyModel(models.Model):
      objects = CustomManager()
   
Tms91
  • 3,456
  • 6
  • 40
  • 74
ruddra
  • 50,746
  • 7
  • 78
  • 101
  • This class MyModel(models.Model): field_one = models.CharField(max_length=10, blank=True, null=True) @property def static_id(self): 'ITM{0:07d}'.format(self.pk) Makes me run into error: django.core.exceptions.FieldError: Unknown field(s) (static_id) specified for my_model – Tms91 Feb 07 '20 at 13:56
  • Where do you get the error? Can you add the full error stactrace? – ruddra Feb 07 '20 at 14:16
1

Maybe you can split your field into three separate fields:

class MyModel(models.Model):
    PREF = "ITM"
    NUMS = 5

    field1 = models.CharField(max_length=10, blank=True, null=True)
    ...
    pref = models.CharField(max_length=3, default=PREF)  # prefix that has defaul value and can be modified
    nums = models.PositiveIntegerField(default=NUMS)  # the number of digits
    static_id = models.AutoField(primary_key=False)  # auto increment field

    class Meta:
        unique_together = ('pref', 'nums', 'static_id')

    @property
    def static_key(self):
        return self.pref + str(self.static_id).zfill(self.nums)
Fomalhaut
  • 8,590
  • 8
  • 51
  • 95
  • I run into error assert not cls._meta.auto_field, "Model %s can't have more than one AutoField." % cls._meta.label AssertionError: Model my_app.my_model can't have more than one AutoField. Apparently, each django model must have no more than one AutoField so I am forced to set static_id = models.AutoField(primary_key=True) – Tms91 Feb 07 '20 at 13:48
  • I prefer not to follow this path because by overwriting the django default id often generates problems with managing that id by the admin. – Tms91 Feb 07 '20 at 15:55
0

SOLVED:

Since I don't need a specific length for my id, nor a constant increment between two consecutive ids, I can use time.time() to get a unique time number every time the object in the model is created. Then I can turn that time number into a string and concatenate it with a constant prefix.

In models.py:

import time

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


class my_model(models.Model):        
    Field_1 = models.CharField(max_length=256)
    static_ID = models.CharField(max_length=256, blank=False, null=False, default=return_timestamped_id)
Tms91
  • 3,456
  • 6
  • 40
  • 74