我正在测试一个小应用,我扩展了用户模型以添加一些额外的信息。用户可以通过django-allauth(google OAuth2)注册,并将条目添加到他们的数据库中。
class LabUser(models.Model):
user = models.OneToOneField(User)
verified = models.BooleanField(default=False, blank=False)
phone_number = models.CharField(max_length=30, verbose_name="Phone Number", null=True, blank=True)
home_phone = models.CharField(max_length=30,verbose_name="Home Phone", null=True, blank=True)
def __unicode__(self):
return self.user.username
但是,当我尝试使用django-admin面板添加另一个用户时,我收到以下数据库错误:
IntegrityError: duplicate key value violates unique constraint "lab_manager_labuser_user_id_key"
DETAIL: Key (user_id)=(24) already exists.
检查psql中的表后,我看到以下内容:
l=# select id, username from auth_user;
id | username
----+----------------
13 | xxxx
23 | xxxx
18 | xxxx
12 | xxxx
21 | xxxx
14 | xxxx
22 | xxxx
1 | xxxx
(8 rows)
l=# select id, user_id from lab_manager_labuser;
id | user_id
----+---------
9 | 13
1 | 1
16 | 18
8 | 12
10 | 14
21 | 21
22 | 22
23 | 23
(8 rows)
查看我的序列表我可以看到这些值高于各自的模型表:
l=# SELECT sequence_name, last_value FROM auth_user_id_seq;
sequence_name | last_value
------------------+------------
auth_user_id_seq | 24
(1 row)
l=# SELECT sequence_name, last_value FROM lab_manager_labuser_id_seq;
sequence_name | last_value
----------------------------+------------
lab_manager_labuser_id_seq | 25
(1 row)
我看过this类似的问题,但找不到在我的情况下发生这种碰撞的原因。这两个序列似乎都超出了我表中的值。
即。我尝试了以下操作,虽然它增加了我的密钥,但它仍然会导致假定的完整性错误,而数据库中显然不存在这些密钥。
SELECT setval('lab_manager_labuser_id_seq', (SELECT MAX(user_id) from lab_manager_labuser)+1)")
任何帮助都将不胜感激。
更新
我设置了一个接收器来创建一个labuser模型如下,也许我这样做不正确导致数据库不匹配:
@receiver(post_save, sender=User)
def add_labuser(sender, created, instance, **kwargs):
if created:
LabUser.objects.create(user=instance)
我认为这必须是问题的一部分,因为我可以使用shell中的以下代码成功创建用户对象:
a = User()
##(add fields)##
a.save()
LabUser.objects.create(user=a)
发生重复键错误的原因是因为我通过管理面板添加用户内联如下:
class LabUserInline(admin.StackedInline):
model = LabUser
can_delete = False
显然,当通过Admin创建用户时,在调用save之前,将通过内联自动创建LabUser记录。然后,当收到post_save信号时,django会尝试为同一个User对象创建另一个LabUser记录,此时会发生密钥冲突。
有人知道如何规避这种冗余吗?
答案 0 :(得分:0)
我想出了这个问题。虽然当用户通过注册表单注册时,django-allauth默认没有创建LabUser对象,但是django管理面板是,因为我实现了以下内联。
class LabUserInline(admin.StackedInline):
model = LabUser
can_delete = False
verbose_name = 'Lab User'
verbose_name_plural = 'Lab Users'
此外,它是在调用user.save()之前创建此对象,因此当我发送post_save信号并调用接收器时,LabUser对象已经存在,导致密钥冲突。
我通过删除保存后信号来修复此问题,并简单地在django-allauth的SignUp表单的save()方法中创建对象。
def save(self, user):
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.save()
labuser = LabUser.objects.create(user=user)
...populate fields...
labuser.save()