Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: Override save method to handle unique=True IntegrityError

My model has a CharField that defaults to a randomly generated string which should be unique. I don't want to use a UUIDField. Is there a way to override the save method to handle IntegrityError raised if the code generated is a duplicate? Or should I check for that in my generation function?

MODEL

class Item(models.Model):
    ...
    item_code = models.CharField(max_length=11, default=get_generated_code, unique=True)

FUNCTION

def get_generated_code():
    code = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(11))
    return code
like image 547
blue_zinc Avatar asked Jan 21 '16 22:01

blue_zinc


1 Answers

This is what I ended up doing.

I overrode the save method such that the code is set within there and checks for integrity errors, which only raises it after 3 unsuccessful tries. As the chances of a collision are small enough, especially after 3 consecutive tries, I feel like this is a sufficient solution rather than making multiple database queries in alternative solutions.

class Item(models.Model):
    ...
    # blank = True as this is handled by save method
    code = models.CharField(max_length=11, blank=True, unique=True)

    def save(self, *args, **kwargs):
        if not self.code:
            self.code = get_generated_code()
        success = False
        errors = 0
        while not success:
            try:
                super(Item, self).save(*args, **kwargs)
            except IntegrityError:
                errors += 1
                if errors > 3:
                    # tried 3 times, no dice. raise the integrity error and handle elsewhere
                    raise
                else:
                    self.code = get_generated_code()
            else:
                success = True
like image 134
blue_zinc Avatar answered Sep 28 '22 08:09

blue_zinc