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

父键已存在但FOREIGN KEY约束仍失败的原因排查

FOREIGN KEY约束失败问题排查

问题背景

将Excel数据同步到数据库时,所有课程记录均触发外键约束错误。代码中已通过get_object_or_404成功获取到Staff和Course实例,但仍报错。已尝试重置数据库、重新执行makemigrations和migrate,问题未解决。

执行代码

for record in lesson_records:
    try:
        date = parser.parse(record['Date']).date()
        start_time = parser.parse(record['Start Time']).time()
        end_time = parser.parse(record['End Time']).time()

        primary_tutor = get_object_or_404(Staff, gmail=record['Primary Tutor Email'])
        logger.info(primary_tutor)
        course = get_object_or_404(Course, course_code=record['Course Code'])
        logger.info(course)

        lesson, created = Lesson.objects.update_or_create(
            lesson_code=record['Lesson Code'],
            defaults={
                'course_code': course,
                'date': date,
                'start_time': start_time,
                'end_time': end_time,
                'lesson_no': record['Lesson Number'],
                'school': record['School / Customer'],
                'teacher': record['Teacher'],
                'teacher_contact': record['Teacher Contact'],
                'venue': record['Venue'],
                'remarks': record['Remark'],
                'delivery_format': record['Delivery Format'],
                'primary_tutor': primary_tutor
            }
        )

        logger.info(record['Lesson Code'])
    except Exception as e:
        lesson_errors.append(f"Error in Lesson {record['Lesson Code']}: {str(e)}")
        logger.error(f"Error in {record['Lesson Code']}: {str(e)}")

报错信息

Error in [course code]: FOREIGN KEY constraint failed

Lesson模型定义

class Lesson(models.Model):
    course_code = models.ForeignKey(Course, on_delete=models.CASCADE)
    date = models.DateField()
    start_time = models.TimeField()
    end_time = models.TimeField()
    lesson_no = models.IntegerField()
    lesson_code = models.CharField(max_length=20, primary_key=True)
    school = models.CharField(max_length=100)
    teacher = models.CharField(max_length=10)
    teacher_contact = models.CharField(max_length=100)
    teacher_email = models.EmailField(blank=True, null=True)
    venue = models.CharField(max_length=100)
    remarks = models.TextField(blank=True, null=True)
    delivery_format = models.CharField(max_length=10)
    primary_tutor = models.ForeignKey(Staff, on_delete=models.CASCADE, related_name='primary_tutor')
    other_tutors = models.ManyToManyField(Staff)
    calender_id = models.CharField(max_length=100, blank=True, null=True)
    change = models.BooleanField(default=False)

排查方向与解决方案

  1. 字段名冲突修复
    Lesson中外键字段命名为course_code,与关联模型Course的course_code字段重名,可能导致Django生成SQL时逻辑混淆。建议修改Lesson模型的外键字段名:

    # 修改Lesson模型的外键字段
    course = models.ForeignKey(Course, on_delete=models.CASCADE)
    

    同步更新代码中的update_or_create参数:

    defaults={
        'course': course,  # 对应修改后的字段名
        # 其他字段保持不变
    }
    

    修改后重新执行makemigrations和migrate。

  2. 事务状态检查
    检查代码是否运行在未提交的事务环境中,嵌套事务或未提交的操作可能导致获取到的实例未被数据库持久化,触发外键约束。可在获取实例后添加事务提交逻辑,或确认当前事务状态。

  3. 关联模型主键验证
    确认Course和Staff模型的主键类型与Lesson中外键的关联类型一致。例如,如果Course使用默认自增id作为主键而非course_code,需确保查询到的Course实例主键在数据库中存在且状态正常。

  4. 数据库引擎特性适配
    若使用SQLite,部分场景下外键约束检查会延迟到事务提交阶段。可尝试切换至PostgreSQL等数据库测试,或开启SQLite的即时外键约束检查:

    # 在settings.py的数据库配置中添加
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': BASE_DIR / 'db.sqlite3',
            'OPTIONS': {
                'sqlite3': {
                    'foreign_keys': True,
                },
            },
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:40:56