Here's my model:
class MyModel(BaseModel):
no = models.PositiveIntegerField() # Human-friendly no -> counter that starts from 1 for every type
type = models.ForeignKey(MyModelType)
I set the value for the no
field in model's pre_save
signal:
@receiver(pre_save, sender=MyModel)
def mymodel_pre_save(sender, instance, *args, **kwargs):
if not instance._state.adding:
return
obj_count = MyModel.objects.filter(type=instance.type).count()
instance.no = obj_count + 1
The bug with this code is that it produces different objects having same no
number. Probably it happens when multiple users create objects at the same time.
What's the best way to fix it? Would moving assignment to .save()
method of the model suffice in high-load environment?
Solution
Eventually, I've implemented @moooeeeep's solution but moved the logic from post_save
to model's save
method:
class MyModel(BaseModel):
...
def save(self, *args, **kwargs):
adding = self.pk is None
with transaction.atomic():
super().save(*args, **kwargs)
if adding:
# Compute and set `.no`
obj_count = MyModel.objects.filter(type=self.type, id__lte=self.id).count()
self.no = obj_count
self.save(update_fields=['no'])