为什么Django的get_or_create会导致IntegrityError?

6

我有一个模型,其中包含以下字段:
token = models.CharField(max_length=32, default="", unique=True, null=False, db_index=True)

在save()方法中,我使用以下方法将该字段设置为32个字符的随机字符串:

def save(self, *args, **kwargs):
    if (self.token is None or len(self.token) == 0):
        self.token = random_identifier()
    super(SessionPassthrough, self).save(*args, **kwargs)

def random_identifier(n=32):
    """ Generate a random identifier of length n. 

    From https://dev59.com/mnE95IYBdhLWcg3wkeof"""
    return ''.join(random.choice(string.ascii_lowercase + string.digits) for x in range(n))

每当我尝试创建一个新模型实例时,就会出现以下错误:
IntegrityError: duplicate key value violates unique constraint "wakelytics_sessionpassthrough_token_key"

我使用以下方法创建实例:

@staticmethod
def for_session(session):
    sp, c = SessionPassthrough.objects.get_or_create(session=session)
    return sp

get_or_create()在写入数据库之前是否调用了该方法的save()函数?答案:是的

每当我第一次使用session调用该方法时,它会产生IntegrityError,并且在几分钟内持续出现错误。然后它会正确返回。这是什么原因造成的?


知道即使是随机程序也可能选择一个已经存在的值...对吧? - Ignacio Vazquez-Abrams
我知道。但是每次都这样吗?然后它就不会再抛出错误了? - Mantas Vidutis
这是随机的。你不知道它会在什么时候选择一个还没有在你的数据库中的值。 - Ignacio Vazquez-Abrams
但在这种情况下,它有时会返回而没有错误,而现在它可靠地在最初的几次/分钟内失败,然后成功。 - Mantas Vidutis
2个回答

4

1
当然了。它的合同的一部分是,它将返回一个确实存在的模型,并且为了做到这一点,它必须保存。
编辑:
你之所以会得到那个错误,是因为该值已经存在于数据库中。

5
如果已经存在,get_or_create不会返回它吗?为什么要抛出错误? 如果对象已经存在于数据库中,get_or_create将返回该对象。但是,如果使用get_or_create时发生了多个对象匹配给定的参数,则会引发错误,以避免创建重复的对象。 - Mantas Vidutis
1
因为“session”不同,所以它是一个单独的行。 - Ignacio Vazquez-Abrams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接