Django:覆盖save方法以处理unique = True IntegrityError

时间:2016-01-21 22:01:02

标签: python django django-models

我的模型有一个CharField,默认为随机生成的字符串,该字符串应该是唯一的。我不想使用UUIDField。如果生成的代码是重复的,有没有办法覆盖save方法来处理引发的IntegrityError?或者我应该在我的生成函数中检查它?

MODEL

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

功能

def get_generated_code():
    code = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(11))
    return code

2 个答案:

答案 0 :(得分:3)

这就是我最终要做的事情。

我覆盖了save方法,以便在那里设置代码并检查完整性错误,这只会在3次尝试失败后才会引发错误。由于碰撞的可能性很小,特别是在连续3次尝试之后,我觉得这是一个充分的解决方案,而不是在替代解决方案中进行多个数据库查询。

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

答案 1 :(得分:0)

请考虑用原子事务包装super方法,以避免出现任何TransactionManagementError

from django.db IntegrityError, transaction
def save(self, *args, **kwargs):
    try:
        with transaction.atomic():
            super(Keyword, self).save(*args, **kwargs)
    except IntegrityError:
        # [...] do something else
        raise IntegrityError