Django多对多字段赋值触发TypeError,请求技术排查解决
Django ManyToManyField 赋值错误解决方法
错误原因
你遇到的TypeError核心原因:Django的ManyToMany字段不允许在create()方法中直接赋值。多对多关系依赖中间表存储关联记录,而create()仅创建主表对象,此时中间表还没有对应的主表条目,因此必须先创建主对象,再通过set()或add()方法关联多对多数据。原代码中在shipping.objects.create()里直接给coolbox_id传列表,触发了这个禁止性限制。
代码修改方案
修正后的视图代码
def add_ship(request): if request.method=='POST': m_namedriver = request.POST.get('m_namedriver') driver_id = Driver.objects.get(driver_id=m_namedriver) m_licensepl = request.POST.get('m_licensepl') car_id = Car.objects.get(car_id=m_licensepl) m_weightcoolbox = request.POST.getlist('m_weightcoolbox') ship_date = request.POST.get('ship_date') ship_time = request.POST.get('ship_time') original = request.POST.get('original') destination = request.POST.get('destination') # 修正判断逻辑:用exists()更高效,同时修复笔误 if shipping.objects.exists(): ship_id_max = shipping.objects.aggregate(Max('shipping_id'))['shipping_id__max'] next_ship_id = ship_id_max[:2] + str(int(ship_id_max[2:6]) + 1) else: next_ship_id = "SP1000" # 创建shipping对象时,移除ManyToMany字段coolbox_id的赋值 new_shipping = shipping.objects.create( shipping_id=next_ship_id, driver_id=driver_id, car_id=car_id, ship_date=ship_date, ship_time=ship_time, original=original, destination=destination, ) # 通过set()方法关联选中的Coolbox对象 selected_coolboxes = Coolbox.objects.filter(coolbox_id__in=m_weightcoolbox) new_shipping.coolbox_id.set(selected_coolboxes) return render(request,'add_ship.html',{'message1':"Add shipping successful."}) driver_ship = Driver.objects.all() car_ship = Car.objects.all() coolbox_ship = Coolbox.objects.all() return render(request,'add_ship.html',{'driver_ship':driver_ship,'car_ship':car_ship,'coolbox_ship':coolbox_ship})
关键修改点
- 移除create()中的ManyToMany赋值:删除
create()方法里的coolbox_id = [i for i in Coolbox.objects.filter(...)]这一行。 - 用set()关联多对多数据:创建
shipping对象后,通过set()方法传入筛选出的Coolbox对象列表,完成多对多关系的绑定。 - 修复冗余代码:删除无效的
new_shipping.save()(create()方法已经自动保存对象),修正判断条件里的笔误!= !=为exists()(更高效的存在性判断)。
可选优化:模型字段命名规范
虽然不是错误,但模型里的字段名coolbox_id容易和Coolbox模型的主键混淆,建议改成复数形式更符合Django命名习惯:
class shipping(models.Model): shipping_id = models.CharField(max_length=15,primary_key=True) driver_id = models.ForeignKey(Driver, on_delete=models.CASCADE, related_name="driverfk") car_id = models.ForeignKey(Car, on_delete=models.CASCADE, related_name="carfk") # 修改字段名为复数形式 coolboxes = models.ManyToManyField(Coolbox, related_name="coolboxfk") ship_date = models.DateField(blank=True,null=True) ship_time = models.TimeField(blank=True,null=True) original = models.CharField(max_length=200) destination = models.CharField(max_length=200) def __str__(self): return f"{self.shipping_id}: {self.driver_id}"
修改后视图中对应的关联代码也要改为new_shipping.coolboxes.set(selected_coolboxes)。
内容的提问来源于stack exchange,提问作者Poramet Rodtanee
相关产品推荐
相关产品推荐

