Django 2.0:sqlite IntegrityError:外键约束失败

Posted

技术标签:

【中文标题】Django 2.0:sqlite IntegrityError:外键约束失败【英文标题】:Django 2.0: sqlite IntegrityError: FOREIGN KEY constraint failed 【发布时间】:2018-05-17 03:48:12 【问题描述】:

我正在努力将 Django 2.0 支持添加到 django-pagetree 库。在自动化测试期间,使用 sqlite 内存数据库,我遇到了一堆这样的错误:

  File "/home/nnyby/src/django-pagetree/pagetree/tests/test_models.py", line 638, in setUp
    'children': [],
  File "/home/nnyby/src/django-pagetree/pagetree/models.py", line 586, in add_child_section_from_dict

...

  File "/home/nnyby/src/django-pagetree/venv/lib/python3.5/site-packages/django/db/backends/base/base.py", line 239, in _commit
    return self.connection.commit()
django.db.utils.IntegrityError: FOREIGN KEY constraint failed

这在 Django 2.0 发行说明中有所说明:https://docs.djangoproject.com/en/2.0/releases/2.0/#foreign-key-constraints-are-now-enabled-on-sqlite

根据我不完全理解的描述,这不应该适用于非持久性的测试数据库,对吧?使用 Django 2.0 时,我的 sqlite 测试数据库不会使用适当的选项创建吗?

我用于测试的应用设置在这里:https://github.com/ccnmtl/django-pagetree/blob/master/runtests.py

【问题讨论】:

【参考方案1】:

文档说明了两件事:

    如果您有 ForeignKey 约束,它们现在在数据库级别强制执行。因此,请确保您没有违反外键约束。这是您问题的最可能原因,尽管这意味着您会在其他数据库中看到这些问题。在你的代码中寻找这样的模式:

    # in pagetree/models.py, line 810
    @classmethod
    def create_from_dict(cls, d):
        return cls.objects.create()  # what happens to d by the way?
    

    这肯定会因为 ForeignKey 约束错误而失败,因为 PageBlock 必须有 section,所以你不能在没有先分配它的情况下调用 create

    如果您通过执行原子事务(例如)延迟提交外键来规避外键约束,则您的外键需要初始延迟。事实上,你的测试数据库应该已经有了,因为它每次都重建。

【讨论】:

感谢您的深入研究,我认为您在这里发现了一个错误 - d 应该传递给 cls.objects.create()【参考方案2】:

A 遇到了一些不同的情况,但出现了相同的错误。问题是我使用相同的模型名称和字段名称

不正确的代码

class Column(models.Model):
    ...

class ColumnToDepartment(models.Model):
    column = models.ForeignKey(Column, on_delete=models.CASCADE)

解决方案

class Column(models.Model):
    ...

class ColumnToDepartment(models.Model):
    referring_column = models.ForeignKey(Column, on_delete=models.CASCADE)

【讨论】:

这对我很有帮助!在看到这个答案之前,我完全不知所措...... Django 处理多表继承的方式意味着在你的类层次结构中引入了几个属性,这些属性对应于你的子类的降级名称。如果您没有意识到这一点,它可能会让您认为您的代码有一个奇怪的行为。【参考方案3】:

您是否已将 on_delete 添加到您的 FOREIGN KEY 中?在 Django 2.0 上,此参数是必需的。 您还可以看到: https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey.on_delete https://docs.djangoproject.com/en/2.0/howto/upgrade-version/ https://docs.djangoproject.com/en/2.0/topics/db/examples/many_to_one/ https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey

【讨论】:

是的,我的模型文件和迁移都有,所以我认为这不是问题所在。如果你有兴趣,我目前的 django 2.0 diff 在这里:github.com/ccnmtl/django-pagetree/pull/187/files 这个确实帮助了我。我将on_delete 属性设置为DO_NOTHING,这最终违反了外键约束。将其设置为 SET_NULL 为我修复了它。【参考方案4】:

在我的例子中,我发现我的模型引用的 ForeignKey 对象不存在。 所以我只是将引用的 FK 对象更改为存在对象。

【讨论】:

【参考方案5】:

我的 Django 项目中出现了这个错误:sqlite3.IntegrityError: FOREIGN KEY constraint failed。结果我删除了沿线某处的迁移文件夹,因此当我运行python manage.py makemigrations 时它没有接收到我的模型更改。只要确保您仍然有一个包含迁移的迁移文件夹。

【讨论】:

【参考方案6】:

还有一件事要检查,在我的情况下,它与我的装置文件有关。 迁移到 Django3 后重新生成它们解决了我在测试我的应用程序时遇到的问题。

./manage.py dumpdata app.Model1 app.Model2 --indent=4 > ./app/fixtures/file.json

【讨论】:

【参考方案7】:

当我在迁移或表格方面遇到问题时,我会这样做,这通常会有所帮助:

    评论您的问题字符串; 做python3 manage.py makemigrationspython3 manage.py migrate; 那你一定要python3 manage.py migrate --fake; 取消注释您的字符串,然后再次执行 python3 manage.py makemigrationspython3 manage.py migrate

希望对你有用

【讨论】:

【参考方案8】:

迁移后我的问题解决了,因为我更改了外键,然后没有应用迁移。

具体来说,起初我在模型中有以下代码:

class TeacherRequest(models.Model):
    requester = models.ForeignKey(
        Profile,
        on_delete=models.CASCADE,
        related_name="teacher_request",
    )

    class RequestStatus(models.TextChoices):
        PENDING = '1', _('pending')
        APPROVED = '2', _('approved')
        REJECTED = '3', _('rejected')

    status = models.CharField(
        choices=RequestStatus.choices,
        max_length=1,
        default=RequestStatus.PENDING,
    )

然后我把外键从Profile改成了User


class TeacherRequest(models.Model):
    requester = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="teacher_request",
    )

    class RequestStatus(models.TextChoices):
        PENDING = '1', _('pending')
        APPROVED = '2', _('approved')
        REJECTED = '3', _('rejected')

    status = models.CharField(
        choices=RequestStatus.choices,
        max_length=1,
        default=RequestStatus.PENDING,
    )

解决方案

python manage.py makemigrations
python manage.py migrate

【讨论】:

以上是关于Django 2.0:sqlite IntegrityError:外键约束失败的主要内容,如果未能解决你的问题,请参考以下文章

django_ORM

sqlite法典-2.0

在 CakePHP 2.0 中使用 SQLite3

sqlite方法-2.0

使用 SQLite 和 WinForms 2.0 C# 的编码问题

NHibernate 与 C#-Sqlite 在 > .NET 2.0 中没有 DbConnection