Django多对多关系操作报错:Field 'id'期望数字却获ManyRelatedManager
解决Django多对多关系删除时报错:Field 'id' expected a number but got
问题说明
删除多对多关系中的记录时触发如下错误:
Field 'id' expected a number but got
需求逻辑:
- 接收POST请求中合法的
data.log_order - 检查
ActiveSession关联的Log记录:- 存在匹配
log_order的旧记录时,删除旧记录并添加新数据 - 无匹配记录或无历史记录时,直接添加新数据
- 存在匹配
相关代码
模型与表单
class Log(models.Model): ................................... log_order = models.IntegerField(validators=[MinValueValidator(1)],blank=True, null=True) class LogForm(forms.Form): ............................. log_order = forms.IntegerField() class ActiveSession(models.Model): log = models.ManyToManyField(Log, related_name='savedlogs') ..................................
原视图代码
if active_session.log.values(): print(active_session.log.values()) for i in active_session.log.values(): if i['log_order']==int(data.log_order): log_order = data.log_order log=Log.objects.filter(log_order=log_order) print(log) active_session = ActiveSession.objects.get(id=ActiveSession.objects.last().id,log__in=log) print(active_session) active_session.log.remove(active_session.log) active_session.log.add(data) print(active_session.log.values()) else: active_session.log.add(data) print(active_session.log.values()) print('Existing Log with different order_no') else: active_session.log.add(data) print('Log added to Session') print(active_session.log.values()) return HttpResponseRedirect(url)
完整报错追踪
Traceback (most recent call last): File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\fields\__init__.py", line 1774, in get_prep_value return int(value) TypeError: int() argument must be a string, a bytes-like object or a number, not 'ManyRelatedManager' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner response = get_response(request) File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "C:\Users\User\Desktop\Gym_App\my_gym\views.py", line 115, in addlog active_session.log.remove(active_session.log) File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 967, in remove self._remove_items(self.source_field_name, self.target_field_name, *objs) File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\fields\related_descriptors.py", line 1197, in _remove_items self.through._default_manager.using(db).filter(filters).delete() File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\query.py", line 942, in filter return self._filter_or_exclude(False, *args, **kwargs) File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\query.py", line 962, in _filter_or_exclude clone._filter_or_exclude_inplace(negate, *args, **kwargs) File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\query.py", line 969, in _filter_or_exclude_inplace self._query.add_q(Q(*args, **kwargs)) File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\sql\query.py", line 1360, in add_q clause, _ = self._add_q(q_object, self.used_aliases) File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\sql\query.py", line 1379, in _add_q child_clause, needed_inner = self.build_filter( File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\sql\query.py", line 1239, in build_filter return self._add_q( File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\sql\query.py", line 1379, in _add_q child_clause, needed_inner = self.build_filter( File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\sql\query.py", line 1321, in build_filter condition = self.build_lookup(lookups, col, value) File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\sql\query.py", line 1167, in build_lookup lookup = lookup_class(lhs, rhs) File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\lookups.py", line 24, in __init__ self.rhs = self.get_prep_lookup() File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\fields\related_lookups.py", line 59, in get_prep_lookup self.rhs = [target_field.get_prep_value(v) for v in self.rhs] File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\fields\related_lookups.py", line 59, in <listcomp> self.rhs = [target_field.get_prep_value(v) for v in self.rhs] File "C:\Users\User\Desktop\Portfolio\venv\lib\site-packages\django\db\models\fields\__init__.py", line 1776, in get_prep_value raise e.__class__( TypeError: Field 'id' expected a number but got <django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x04E93418>.
错误原因
- 核心错误:
active_session.log.remove(active_session.log)这行代码中,active_session.log是ManyRelatedManager对象,而remove()方法需要传入具体的Log实例、实例ID,或者QuerySet,不能直接传入管理器本身。 - 冗余逻辑:重新查询
ActiveSession.objects.get(id=ActiveSession.objects.last().id,log__in=log)完全没必要,已经持有active_session实例,直接操作即可。 - 循环逻辑问题:循环遍历
active_session.log.values()时,只要有一条记录不匹配就会执行add(data),导致重复添加新数据。
修复后的视图代码
# 先获取当前session下匹配log_order的Log记录 target_logs = active_session.log.filter(log_order=int(data.log_order)) if target_logs.exists(): # 删除匹配的旧记录 active_session.log.remove(*target_logs) print(f"Removed old log with order: {data.log_order}") # 添加新数据 active_session.log.add(data) print('Log added to Session') print(active_session.log.values()) return HttpResponseRedirect(url)
优化点说明
- 直接通过当前
active_session关联的log管理器过滤匹配记录,避免全局查询Log.objects.filter(...)导致的无关数据匹配 - 使用
exists()判断是否存在匹配记录,比遍历values()更高效 - 用
*target_logs将QuerySet解包后传入remove(),符合方法要求的参数格式 - 简化逻辑:无论是否有旧记录,最后统一添加新数据,避免循环中的重复添加问题
内容的提问来源于stack exchange,提问作者A_K
相关产品推荐
相关产品推荐

