You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>.

错误原因

  1. 核心错误:active_session.log.remove(active_session.log)这行代码中,active_session.log是ManyRelatedManager对象,而remove()方法需要传入具体的Log实例、实例ID,或者QuerySet,不能直接传入管理器本身。
  2. 冗余逻辑:重新查询ActiveSession.objects.get(id=ActiveSession.objects.last().id,log__in=log)完全没必要,已经持有active_session实例,直接操作即可。
  3. 循环逻辑问题:循环遍历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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 15:30:56