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'])