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)
额外修复项
修正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)统一表单字段名
HTML中考试时间输入框的name是examtime,但原views中用request.POST.get('time')获取,会导致值为空,需改为request.POST.get('examtime')。
内容的提问来源于stack exchange,提问作者Muhammad Asif
相关产品推荐
相关产品推荐

