Django:IntegrityError:列 user_id 不是唯一的

13 投票
3 回答
17093 浏览
提问于 2025-04-16 19:47

我想测试一些使用用户对象的东西。

但是不知为什么,我得到了:

IntegrityError: column user_id is not unique

我已经想了很久,但似乎找不到问题出在哪里。一开始我以为可能是数据库在测试之间没有被刷新,但我追踪了一下 User.objects.all(),结果是一个空列表。

这是我的测试:

from django.contrib.auth.models import User
from django.test import TestCase

class TestSomething(TestCase):
    def test_create_user(self):
        User.objects.create_user('foo', 'foo@bar', 'bar')

我的测试设置:

from settings import *

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', 
        'NAME': ':memory:',
    }
}

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

更新:

我应该更仔细地阅读我的错误信息。实际上是以下这个信号导致了问题。

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile(user=instance).save()

3 个回答

1

我想你在Profile模型中有一个叫user_id的字段,并且这个字段是唯一的,对吧?

看起来你在代码的其他地方试图保存与同一个用户对象相关的Profile。get_or_create这个快捷方式工作得很好,因为它只有在数据库中没有这个对象时才会创建一个新的对象。否则,它会返回已经存在的对象。另一方面,Profile().save()只是尝试保存这个对象,如果无法保存就会抛出一个异常。

这样说你能理解吗?

5

我遇到了同样的问题,解决起来很简单。这个问题发生在你运行 'manage.py dumpdata' 的时候,而你的数据库里已经有一个 UserProfile。这个 UserProfile 会被包含在生成的 json 文件里,所以当你加载测试数据并尝试创建一个相同用户名的新 UserProfile 时,就会出现冲突,因为这个用户名的 UserProfile 已经存在了。解决办法就是直接从 json 文件中删除这个 UserProfile。

举个例子:

  • 你有一个现有的数据库,里面有一个用户名为 'mathew' 的用户,还有一个与这个用户关联的 UserProfile
  • 你运行了 manage.py dumpdata
  • 现在生成的 json 文件里包含了这个 UserProfile,因为它是你应用模型的一部分(但不包括用户本身)
  • 然后你在测试中尝试创建一个用户,代码是: 'User.objects.create_user('mathew', 'mathew@example.com', 'password')'
  • 你的保存后信号会被触发,试图为用户 'mathew' 创建一个关联的 UserProfile
  • 但是这个 UserProfile 已经存在了,所以你就会收到一个错误

希望这能帮到你。

6

我通过调整我的信号来解决了这个问题,代码如下:

from django.dispatch import receiver

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.get_or_create(user=instance)

这样做解决了表面上的问题,但并没有真正解决根本原因。我觉得把普通测试和Django测试混在一起可能在某个地方引发了错误。当我单独运行我提问中的测试时,它是可以正常工作的。

如果没有其他答案,我就把这个答案标记为正确。

撰写回答