创建相关对象时,Django get_or_create竞争条件

时间:2018-02-02 13:59:39

标签: python mysql django concurrency

我有一个ExtendedUser这样的模型,只指向Django的User模型:

class ExtendedUser(models.Model):
    user = models.OneToOneField(User)

当请求进入时,如果我查找的用户不存在,我想获取或创建User及其相关ExtendedUser。我有这段代码:

def get_or_create_user(username):
    with transaction.atomic():
        user, created = User.objects.get_or_create(
            username=username,
            defaults={
                'first_name': "BLABLA",
            },
        )

        if created:
             extended_user = ExtendedUser()
             extended_user.user = user
             extended_user.save()

    return user

我将其包装在一个交易中,以确保我不创建User但不创建其关联的ExtendedUser

但是,当两个请求同时进入将创建同一个用户时,对于这两个请求,这会不时地以IntegrityError失败。所以我最终没有创建用户..

IntegrityError: (1062, "Duplicate entry 'BLABLABLA' for key 'username'")

请注意,我使用MySQL,但强制READ COMMITTED隔离级别。

我做错了什么?我该怎么处理?模型需要保持原样。

1 个答案:

答案 0 :(得分:1)

也许你应该使用signals来解决这个问题。

保存用户后,将触发信号。它位于信号处理程序中,您应该在其中创建ExtendedUser。

from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        ExtendedUser.objects.create(user=instance)