Home > Software engineering >  How to reset auto increment number every year in Django
How to reset auto increment number every year in Django

Time:04-19

I have a model IncomingCorrespondence with auto incrementing field ID. I also have field number, and I want two things for this field:

  1. This field will auto-increment its value, just like ID
  2. Every new year its value will start over from 0 (or 1)
ID Number Date
285 285 2020-03-12
286 286 2020-04-19
287 1 2021-01-01
class IncomingCorrespondence(models.Model):
   ID = models.models.AutoField(primary_key=True)
   date = models.DateField(null=True)
   number = models.IntegerField(null=True)

How can I do that the most efficient and reliable way?

CodePudding user response:

You do not need to store the number, you can simply derive it by the number of items that are stored in the database since it has turned that year with:

class IncomingCorrespondence(models.Model):
    date = models.DateField(null=True)
    created = models.DateTimeField(auto_now_add=True)

    @property
    def number(self):
        return IncomingCorrespondence._base_manager.filter(
            created__year=self.created.year,
            created__lt=self.created
        ).count()   1

We thus have a timestamp created that will store at what datetime the object was created, and we count the number of IncomingCorrespondence for that year before the timestamp plus one. You can in that case work with a package like django-softdelete [GitHub] to keep deleted objects in the database, and just filter these out when viewing the item.

another way might be to assign the maximum plus one to a field:

from django.db.models import Max
from django.utils.timezone import now

def next_number():
    data = IncomingCorrespondence._base_manager.filter(
        date__year=now().year
    ).aggregate(
        max_number=Max('number')
    )['max_number'] or 0
    return data   1

class IncomingCorrespondence(models.Model):
   ID = models.models.AutoField(primary_key=True)
   date = models.DateField(auto_now_add=True)
   number = models.IntegerField(default=next_number, editable=False)

But here Django will dispatch numbers through a query. If there are multiple threads that concurrently create an IncomingCorrespondence, then this can fail. It also depends on the insertion time, not the date of the IncomingCorrespondence object.

CodePudding user response:

You should count number with some method like querying count of created IncomingCorrespondence this year. It should not be done any other way (cronjob for example) as it won't be stable (crontab may fail and you will end up with anomalies (and won't even be able to notice that), or you will create instance right before crontab reset the sequence)

  • Related