You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django使用get_or_create报FOREIGN KEY约束失败错误求助

Django外键约束错误:使用get_or_create创建关联Facoltà的Exam实例失败

错误信息

Internal Server Error: /exams/26
Traceback (most recent call last):
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\models\query.py", line 916, in get_or_create
return self.get(**kwargs), False
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\models\query.py", line 637, in get
raise self.model.DoesNotExist(
exams.models.Exam.DoesNotExist: Exam matching query does not exist.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\backends\base\base.py", line 313, in _commit
return self.connection.commit()
sqlite3.IntegrityError: FOREIGN KEY constraint failed

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\core\handlers\exception.py", line 55, in inner
response = get_response(request)
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\core\handlers\base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\doniy\PycharmProjects\WebScraping\exams\views.py", line 47, in f
createExam(nome=getExam(),anno=getAnno(),semestre=getSemestre(),facoltà=None)
File "C:\Users\doniy\PycharmProjects\WebScraping\exams\views.py", line 19, in createExam
Exam.objects.get_or_create(nome=nome[i],anno=anno[i],semestre=semestre[i], 
Facoltà=Facoltà.objects.get(id=27))
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\models\manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\models\query.py", line 921, in get_or_create
with transaction.atomic(using=self.db):
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\transaction.py", line 263, in __exit__
connection.commit()
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\utils\asyncio.py", line 26, in inner
return func(*args, **kwargs)
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\backends\base\base.py", line 337, in commit
self._commit()
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\backends\base\base.py", line 312, in _commit
with debug_transaction(self, "COMMIT"), self.wrap_database_errors:
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\utils.py", 
line 91, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "C:\Users\doniy\PycharmProjects\WebScraping\venv\lib\site-packages\django\db\backends\base\base.py", line 313, in _commit
return self.connection.commit()
django.db.utils.IntegrityError: FOREIGN KEY constraint failed

问题描述

我开发Django项目2个月,现在遇到上述错误。试图通过get_or_create方法创建多个关联Facoltà外键的Exam模型实例,但一直失败。以下是我的代码:

views.py

def f(request, id):
    facoltà = Facoltà.objects.get(id=id)
    global countF
    if countF == 0:
        connectToEsse3Page(getCod(facoltà))
        countF += 1
    createExam(nome=getExam(),anno=getAnno(),semestre=getSemestre(),facoltà=facoltà)
    exam = Exam.objects.all()
    context = {
        "facoltà":facoltà,
        "exam": exam,
    }
    return render(request, "exams/facoltà.html",context=context)


def createExam(nome,anno,semestre,facoltà):
    for i in range(len(nome)):
        Exam.objects.get_or_create(nome=nome[i],anno=anno[i],semestre=semestre[i], Facoltà=facoltà)

models.py

class Facoltà(models.Model):
    nome = models.CharField(max_length=100)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['nome'], name='unique_migration_nome'
            )
        ]
    def __str__(self):
        return self.nome


class Exam(models.Model):
    nome = models.CharField(max_length=100, primary_key=True)
    anno = models.IntegerField(choices=ANNI)
    semestre = models.IntegerField(choices=SEMESTRI)
    Facoltà = models.ForeignKey(Facoltà, on_delete=models.CASCADE)


    def show_period(self):
        ret = ''

        for nome in ANNI:
            if (nome[0] == self.anno):
                ret += nome[1] + ' '

        for nome in SEMESTRI:
            if (nome[0] == self.semestre):
                ret += nome[1]

        return ret

    def __str__(self):
        return self.nome

问题出在get_or_create这一行,但我看不出写法有问题。有人能指出错误吗?

编辑:我尝试在admin页面创建Exam仍报错,会不会是模型定义有问题?


问题分析与解决

1. 核心问题拆解

  • 硬编码外键实例:createExam函数里硬写了Facoltà.objects.get(id=27),但视图明明传了facoltà参数,这会强制关联ID为27的Facoltà,如果该实例不存在或与当前请求的院系不匹配,直接触发外键约束错误。
  • 主键设计不合理:Exam模型把nome设为主键,意味着同名课程不能属于不同院系、学年或学期,但实际业务中必然存在同名课程,这会导致插入重复主键失败,同时让get_or_create逻辑失效——它会先按nome查询,查不到就创建,但如果同名课程已存在于其他院系下,直接抛出主键冲突。

2. 具体修复步骤

(1)修正createExam的外键参数

删除硬编码的Facoltà查询,改用传入的参数:

def createExam(nome,anno,semestre,facoltà):
    for i in range(len(nome)):
        Exam.objects.get_or_create(nome=nome[i],anno=anno[i],semestre=semestre[i], Facoltà=facoltà)

(2)修改Exam模型的主键与约束

去掉nome的primary_key=True,让Django自动生成自增主键,同时添加联合唯一约束,确保同一院系下的课程+学年+学期不重复:

class Exam(models.Model):
    nome = models.CharField(max_length=100)
    anno = models.IntegerField(choices=ANNI)
    semestre = models.IntegerField(choices=SEMESTRI)
    Facoltà = models.ForeignKey(Facoltà, on_delete=models.CASCADE)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['nome', 'anno', 'semestre', 'Facoltà'], 
                name='unique_exam_per_facolta'
            )
        ]

    # 其余方法保持不变

(3)执行数据库迁移

修改模型后必须更新数据库:

python manage.py makemigrations
python manage.py migrate

(4)解决admin创建失败问题

admin创建报错大概率是之前的模型设计问题导致的,修复上述内容后,再尝试在admin创建Exam,确保选择的Facoltà是已存在的实例。

3. 额外优化建议

  • 避免使用全局变量countF,改用缓存或会话记录状态,全局变量在多线程环境下会出问题。
  • 遍历列表时用zip代替索引,代码更简洁:
def createExam(nome_list, anno_list, semestre_list, facoltà):
    for nome, anno, semestre in zip(nome_list, anno_list, semestre_list):
        Exam.objects.get_or_create(
            nome=nome,
            anno=anno,
            semestre=semestre,
            Facoltà=facoltà
        )

内容的提问来源于stack exchange,提问作者doduz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 09:07:35