Django多对多字段赋值报错:禁止直接赋值正向侧,需用set()方法
解决Django多对多关系直接赋值的报错问题
这个报错的原因很明确:你的Restaurant模型里的category是多对多字段(ManyToManyField),Django禁止直接给这种字段的正向关联集合赋值,必须用add()或者set()方法来管理关联关系。
问题出在哪?
你原来的代码试图把ProductCategory对象直接赋值给restaurant['category'],然后用Restaurant(**restaurant)创建对象——但多对多字段不是单个对象,而是一个集合,这种直接赋值的方式Django不允许,所以抛出了Direct assignment to the forward side of a many-to-many set is prohibited的错误。
修改后的脚本代码
根据你的JSON数据结构(每个餐厅对应单个分类名称),可以这样修改handle方法里的餐厅处理部分:
restaurants = load_from_json('restaurants') Restaurant.objects.all().delete() for restaurant in restaurants: # 先从字典里取出分类名称,移除category键(避免创建对象时传入多对多字段) category_name = restaurant.pop('category') # 获取对应的分类对象 _category = ProductCategory.objects.get(name=category_name) # 创建并保存餐厅对象(此时还没关联分类) new_restaurant = Restaurant(**restaurant) new_restaurant.save() # 用add()方法关联分类 new_restaurant.category.add(_category)
如果你的JSON里一个餐厅对应多个分类
如果你的JSON数据中,餐厅的category是一个名称列表(比如["中餐", "快餐"]),可以用set()方法批量关联:
restaurants = load_from_json('restaurants') Restaurant.objects.all().delete() for restaurant in restaurants: category_names = restaurant.pop('category') # 批量获取所有对应的分类对象 categories = ProductCategory.objects.filter(name__in=category_names) new_restaurant = Restaurant(**restaurant) new_restaurant.save() # 用set()批量设置关联 new_restaurant.category.set(categories)
关键注意事项
- 必须先调用
new_restaurant.save(),再操作多对多关联:因为多对多的中间表需要依赖餐厅对象的主键(只有保存后对象才有主键)。 pop('category')是为了避免在创建Restaurant对象时,把多对多字段作为普通字段传入,这会触发Django的校验错误。
内容的提问来源于stack exchange,提问作者Razeel
相关产品推荐
相关产品推荐

