1👍
✅
By the "unique counter per User" you mean the code series per User. So I would create a new model ReceiptCodeSeries
from django.db import transaction, models
class ReceiptCodeSeries(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
series_count = models.IntegerField(default=0)
# Optional fields
prefix = models.CharField(default="2021")
suffix_length = models.IntegerField(default=4)
@classmethod
def get_next_code(cls, user):
with transaction.atomic():
series = cls.objects.select_for_update().get(user=user)
series.series_count += 1
series.save()
return series.prefix + str(series.ticket_series_count).zfill(series.suffix_length)
This approach locks the code series for each get_next_code
call so parallel requests will be fine.
Example usage:
>>> code_series = ReceiptCodeSeries.objects.get(user=some_user)
>>> print(code_series.series_count)
0
>>> ReceiptCodeSeries.get_next_code(some_user)
"2021-0001"
>>> code_series.refresh_from_db()
>>> print(code_series.series_count)
1
If you want to learn more about this approach, please read a great article from Haki Benita – How to Manage Concurrency in Django Models
Source:stackexchange.com