kijana
kijana

Reputation: 332

A field with values generated by concatenating an auto field with defined Characters Django

I want to have a Django CharField in my models whose values will be generated as by concatenating fixed value and the value of an autogenerated value e.g value1: KAM001, Value2:KAM002 ...

Am stuck on how I can achieve that.

Upvotes: 4

Views: 2153

Answers (1)

furins
furins

Reputation: 5048

There are many ways to answer to your question. It really depends on what the purpose of this field is and when do you want the code to be autogenerated (before or after the record is saved).

In the following code I'm defining a Charfield that stores codes with a fixed part ('KAM') and an incremental one ('001', '002', ...), none of these parts already defined elsewhere. When the object is saved, the field code, if empty, is populated incrementally.

class MyModel(models.Model):
    code = models.CharField(blank=True, default='')

    def save(self, force_insert=False, force_update=False):
        if self.code == "":
            existing_codes = MyModel.objects.all().order_by('-code')
            if existing_codes.count() > 0:
                new_code = int(existing_codes[0].code[1:]) + 1
            else:
                new_code = 0
            self.code = 'KAM%03d' % new_code
        super(MyModel, self).save(force_insert, force_update)

If you want to concatenate a string to an autoincrement field, the code is slightly less complex:

class MyModel(models.Model):
    id = models.AutoField(primary_key=True)
    code = models.CharField(blank=True, default='')

    def save(self, force_insert=False, force_update=False):
        self.code = 'KAM%08d' % self.id
        super(MyModel, self).save(force_insert, force_update)

If you want the code to be defined before saving the record you can use this approach:

class MyModel(models.Model):
    code = models.CharField(blank=True, default=new_code)

    @property
    def new_code(self):
        existing_codes = MyModel.objects.all().order_by('-code')
        if existing_codes.count() > 0:
            new_code = int(existing_codes[0].code[1:]) + 1
        else:
            new_code = 0
        return 'KAM%03d' % new_code

but please note that this approach may generate duplicate values if two objects are instantiated before the first one is saved, so I discourage you to use this approach.

other approaches may use signals, triggers, etc. These are just some of many.

e.g., if you do not need to execute queries basing on the "Charfield field" I suggest you an alternative approach:

class MyModel(models.Model):
    # ... your fields here

    def my_code(self):
        return 'KAM%08d'%self.pk  # please note that I've added more padding zeroes

this can be called from your templates in this way:

{{obj.my_code}}

where obj is an instance of MyModel

if you need also to change the initial part for some records (the 'KAM' part) the "define on save" approach is the way to go.

Upvotes: 3

Related Questions