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
相关产品推荐
相关产品推荐

