user6082142
user6082142

Reputation:

Django generate custom ID

I saw this answer but there is no specific answer yet. I want to create custom id that starts with letter. When a new record comes into database I want to change the id to A00001, .... A00002, .... A00010, ...A10000 etc. The id will be always in range 99999- 00001 so how can I do that?

my model is simple:

class Custom(models.Model):
    id = models.AutoField(primary_key=True, editable=False)

Upvotes: 7

Views: 14828

Answers (5)

Prithwish Halder
Prithwish Halder

Reputation: 11

It's better to create a new field for the custom id in the models and the process in the backend. You can set that as primary_key with unique=True and editable=False:

class Custom(models.Model):
  id = models.Autofield(primary_key=True, editable=False, max_length=10)
  uid= models.CharField(max_length=100, unique=True)

  def save(self, *args, **kwargs):
    super().save(*args, **kwargs)
    self.set_uid()                                 # calling the set_uid function

  def set_uid(self):
    if not self.uid:                               # if uid of the instance is blank
      uid = "CUS" + str(self.id + (10 ** 5))       # generating the uid
      customer= Custom.objects.get(id=self.id)     # getting the instance
      customer.uid = uid                           # allocating the value
      customer.save()                              # saving the instance

  def __str__(self):
    return self.uid

Can also merge the set_uid() inside the save() where the function is called:

class Custom(models.Model):
  id = models.Autofield(primary_key=True, editable=False, max_length=10)
  uid= models.CharField(max_length=100, unique=True)

  def save(self, *args, **kwargs):
    super().save(*args, **kwargs)
    if not self.uid:                                # if uid of the instance is blank
      self.uid = "CUS" + str(self.id + (10 ** 5))   # generating the uid and allocating the value
      self.save()                                   # saving the instance
  
  def __str__(self):
    return self.uid

Upvotes: 1

Yua Xan
Yua Xan

Reputation: 1

I tried to use answer of @JPG, but it has a bug. The bug is becasue it can't auto increment. I fixed the bug, and this my resultant code:

def save(self, **kwargs):
    if not self.id:
        max = YourModel.objects.aggregate(
            id_max=models.Max('id'))['id_max']
        if max is not None:
            max += 1
        else:
            max = 100
        self.id = "{:08d}".format(
            max)  # id from 100 to start
    super().save(*kwargs)

Upvotes: 0

JPG
JPG

Reputation: 88499

The AutoField field is a kind of IntegerField field, so you can't use PKs as A00001 .

So, the possible way to achieve the requirement is to change the AutoField to CharField.

Technically you can use "String PK Field" But, you should be aware of the problems/performance issues if you are going to use that.

Here I found one nice SO post that explains the same - Strings as Primary Keys in SQL Database

========================================================================

If you still really wish to migrate to String PKs, read the following

First you need to use the CharField instead of AutoField and override the save() method of model

from django.db.models import Max


class Custom(models.Model):
    id = models.CharField(primary_key=True, editable=False, max_length=10)
    name = models.CharField(max_length=100)

    def save(self, **kwargs):
        if not self.id:
            max = Custom.objects.aggregate(id_max=Max('id'))['id_max']
            self.id = "{}{:05d}".format('A', max if max is not None else 1)
        super().save(*kwargs)

Upvotes: 9

Kyaw Zaw Tun
Kyaw Zaw Tun

Reputation: 43

I also have another way, That i use in my django project. Here are some code

def ids():
no = Employee.objects.count()
if no == None:
    return 1
else:
    return no + 1
emp_id = models.IntegerField(('Code'), default=ids, unique=True, editable=False)


id = models.CharField(primary_key=True, editable=False, max_length=30)
def save(self, **kwargs):
    if not self.id:
        self.id = "{}{:08d}".format('ABC', self.emp_id)
    super().save(*kwargs)

Upvotes: 4

user8060120
user8060120

Reputation:

string as Primary Key not good idea if you plan to do references to the table, so i recommend you to add a property, for example:

class Custom(models.Model):
    id = models.AutoField(primary_key=True, editable=False)

    @property
    def sid(self):
        return "A%05d" % self.id

and to do queries you can do processing the input values, for example:

s_input = "A%05d" % 231 # 'A00231'
number = s_input[1:] # '00231'
input_id = int(number) # 231

Upvotes: 5

Related Questions