I have a model IncomingCorrespondence
with auto incrementing field ID
. I also have field number
, and I want two things for this field:
- This field will auto-increment its value, just like
ID
- 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)