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

Django中通过POST传递外键ID报错,如何正确设置外键?

问题:无法通过POST将课程ID关联到Exam外键字段

运行代码时出现错误:

Cannot assign "'1'": "Exam.course" must be a "Courses" instance.

相关代码:

models.py

class Courses(models.Model):
     course_name=models.CharField(max_length=50)
     course_price=models.IntegerField()

class Exam(models.Model):
     exam_name=models.CharField(max_length=101)
     course=models.ForeignKey(Courses,on_delete=models.CASCADE,default='python')
     exam_time=models.DateTimeField()

views.py

def Examadd(request):
    mycourses = Courses.objects.all()
    context = {'mycourses': mycourses}
    if request.method == 'POST':
        newexam = request.POST.get('examname')
        course = request.POST.get('courses')
        examtime = request.POST.get('time')
        new = Exam.objects.create(exam_name=newexam,course=course,exam_time=examtime)
        new.save()
        messages.success(request, "Course created successfully")
        return redirect('Courselist')
    return render(request,'addexam.html',context)

addexam.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Add New Exam</h1>
    <form method="post">
        {% csrf_token %}
        <label>Examname:</label>
        <input type="text" name="examname">
        <label>Course:</label>
        <select name="courses">
            {% for i in mycourses %}
            <option value={{i.id}}>{{i.course_name}}</option>
            {% endfor %}
        </select>
        <label>Exam time and date:</label>
        <input type="text" name="examtime">
        <button type="submit">Add</button>
    </form>
</body>
</html>

解决方案

核心问题

外键字段course要求接收Courses模型的实例对象,但你直接传递了字符串类型的课程ID(比如'1'),导致类型不匹配。另外,Exam模型中course的default='python'配置错误,外键默认值不能是字符串,必须是课程ID或实例。

方法1:直接使用course_id赋值ID

Django会为每个外键字段自动生成xxx_id的数据库列,你可以直接将POST获取的ID赋值给这个字段:

修改views.py中的创建逻辑:

new = Exam.objects.create(
    exam_name=newexam,
    course_id=course,  # 替换原有的course=course
    exam_time=examtime
)

这是最简单直接的方式,不需要额外查询数据库。

方法2:查询课程实例后赋值

如果需要验证课程是否存在(避免无效ID),可以先通过ID获取Courses实例:

from django.shortcuts import get_object_or_404

def Examadd(request):
    mycourses = Courses.objects.all()
    context = {'mycourses': mycourses}
    if request.method == 'POST':
        newexam = request.POST.get('examname')
        course_id = request.POST.get('courses')
        # 注意:HTML中考试时间的name是examtime,这里要对应
        examtime = request.POST.get('examtime')
        
        # 获取课程实例,不存在则返回404页面
        course_instance = get_object_or_404(Courses, id=course_id)
        
        new = Exam.objects.create(
            exam_name=newexam,
            course=course_instance,
            exam_time=examtime
        )
        # 修正提示文案:应该是Exam而非Course
        messages.success(request, "Exam created successfully")
        return redirect('Courselist')
    return render(request,'addexam.html',context)

额外修复项

  1. 修正Exam模型的default错误
    原代码中default='python'无效,可改为:

    # 方式1:设置默认课程ID(需确保该ID存在)
    course=models.ForeignKey(Courses,on_delete=models.CASCADE, default=1)
    # 方式2:允许外键为空(如果业务允许)
    course=models.ForeignKey(Courses,on_delete=models.CASCADE, null=True, blank=True)
    
  2. 统一表单字段名
    HTML中考试时间输入框的name是examtime,但原views中用request.POST.get('time')获取,会导致值为空,需改为request.POST.get('examtime')。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 22:55:16