为什么Django的get_or_create会导致这个IntegrityError?

6 投票
2 回答
5821 浏览
提问于 2025-04-16 19:40

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

在保存数据的时候,我用这个方法把这个字段设置为一个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 http://stackoverflow.com/questions/2257441/python-random-string-generation-with-upper-case-letters-and-digits"""
    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的错误,并且在接下来的几分钟里还会继续出现这个错误。然后它才会正常返回。这是为什么呢?

2 个回答

1

当然会有这个问题。它的一个规定是,它一定会返回一个确实存在的模型,而为了做到这一点,它必须先保存。

补充:

你遇到这个错误是因为这个值在数据库里已经存在了。

4

是的。

https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create

根据文档:

新对象的创建大致遵循这个算法:

defaults = kwargs.pop('defaults', {})
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
params.update(defaults)
obj = self.model(**params)
obj.save()

撰写回答