Django多对多关系表单报错:TypeError: Field 'id'期望数字却得到<Profile: user1>
问题分析与解决:推荐应用提交报错
Field 'id' expected a number but got <Profile: user1> 问题描述
开发一款推荐应用,用户可向多位用户推荐影视、书籍。表单显示所有用户列表,勾选目标用户提交推荐时,出现错误:Field 'id' expected a number but got <Profile: user1>。尝试修改表单ModelMultipleChoiceField的queryset为values_list,仅返回类似(1,1)的元组,无法显示用户名也无法保存数据。
models.py
from django.db import models from django.contrib.auth.models import User from django.db.models.signals import post_save from django.dispatch import receiver class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) follows = models.ManyToManyField( 'self', related_name='followed_by', symmetrical=False, blank=True, ) def __str__(self): return self.user.username class Recommendation(models.Model): user = models.ForeignKey( User, related_name="recs", on_delete=models.DO_NOTHING ) recipients = models.ManyToManyField( User, related_name="received_recs", symmetrical=False, blank=True ) title = models.CharField(max_length=300) description = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return ( f"{self.user} " f"({self.created_at:%y-%m-%d %H:%M}): " f"{self.title}" )
views.py
from django.shortcuts import render, redirect from .models import Profile, Recommendation from .forms import RecForm def dashboard(request): all_recs = Recommendation.objects.all() if request.method == "POST": form = RecForm(request.POST or None) if form.is_valid(): rec = form.save(commit=False) rec.user = request.user rec.save() form.save_m2m() return redirect("watchthisshit:dashboard") form = RecForm() return render(request, "watchthisshit/dashboard.html", { "all_recs": all_recs, "form": form })
forms.py
from django import forms from django.db.models.base import Model from .models import Profile, Recommendation class RecForm(forms.ModelForm): title = forms.CharField(required=True) description = forms.CharField(widget=forms.widgets.Textarea( attrs={ "placeholder": "You don't have to write a description, but it would be pretty cool if you did...", "class": "textarea is-success is-medium" } ), label="",) recipients = forms.ModelMultipleChoiceField( queryset=Profile.objects.all(), widget=forms.CheckboxSelectMultiple ) class Meta: model = Recommendation fields = ["title", "description", "recipients"] exclude = ("user", )
错误原因
表单的recipients字段关联了Profile模型,但Recommendation模型的recipients字段实际关联的是User模型。提交表单时,表单传递的是Profile对象,而数据库期望接收User的ID,导致类型不匹配,触发报错。
之前尝试用values_list的方式无效,因为ModelMultipleChoiceField需要接收模型实例的queryset,而非元组数据,无法正确识别和保存对象。
解决步骤
方案一:调整表单关联User模型(推荐)
修改forms.py中的recipients字段,将queryset改为User.objects.all(),同时可自定义显示文本:
class RecForm(forms.ModelForm): title = forms.CharField(required=True) description = forms.CharField(widget=forms.widgets.Textarea( attrs={ "placeholder": "You don't have to write a description, but it would be pretty cool if you did...", "class": "textarea is-success is-medium" } ), label="",) recipients = forms.ModelMultipleChoiceField( queryset=User.objects.all(), widget=forms.CheckboxSelectMultiple, # 自定义显示用户名,若需显示Profile中字段可调整逻辑 label_from_instance=lambda obj: obj.username ) class Meta: model = Recommendation fields = ["title", "description", "recipients"] exclude = ("user", )
方案二:修改模型关联Profile(若业务需要)
如果业务逻辑更适合关联Profile而非User,修改models.py的Recommendation模型:
class Recommendation(models.Model): user = models.ForeignKey( User, related_name="recs", on_delete=models.DO_NOTHING ) # 将关联对象改为Profile recipients = models.ManyToManyField( Profile, related_name="received_recs", symmetrical=False, blank=True ) title = models.CharField(max_length=300) description = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return ( f"{self.user} " f"({self.created_at:%y-%m-%d %H:%M}): " f"{self.title}" )
此方案下,原表单的Profile queryset与模型匹配,无需修改表单,且Profile的__str__方法已返回用户名,显示正常。
额外提示
- 若使用方案一,如需显示
Profile中的自定义字段(如昵称),可调整label_from_instance逻辑:lambda obj: obj.profile.nickname if hasattr(obj, 'profile') else obj.username - 执行模型修改后,需运行
python manage.py makemigrations和python manage.py migrate更新数据库。
内容的提问来源于stack exchange,提问作者Sarah
相关产品推荐
相关产品推荐

