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

Django中PostgreSQL递归Raw Query报错:MenuEntry.parent赋值异常求助

解决Django中PostgreSQL递归原生查询的ValueError问题

问题根因

你的递归CTE字段定义和数据库表的实际字段顺序不匹配,导致Django解析数据时出错。menu_menuentry表的字段顺序是id, menu_id, parent_id, text,但你定义的CTE是my_2ndmenu_items (id, parent, text),用SELECT *返回数据时,第二个字段是menu_id,会被Django错误地赋值给MenuEntry.parent外键字段——外键需要的是MenuEntry实例,而不是menu_id的数值或文本,所以触发了ValueError。

另外,递归部分的SELECT m.*会返回多余字段,和CTE定义的字段数不匹配,进一步加重了这个问题。

修复后的代码

调整CTE的字段定义,明确指定需要的字段,保证和数据库表、Django模型的字段对应:

queryset = MenuEntry.objects.raw("""
WITH RECURSIVE my_2ndmenu_items (id, menu_id, parent_id, text) AS (
    -- 初始查询:获取menu_B的一级菜单条目
    SELECT id, menu_id, parent_id, text 
    FROM menu_menuentry 
    WHERE menu_id = (SELECT id FROM menu_menu WHERE name = %s)
    UNION ALL
    -- 递归查询:获取子菜单条目
    SELECT m.id, m.menu_id, m.parent_id, m.text 
    FROM menu_menuentry m
    INNER JOIN my_2ndmenu_items r ON m.parent_id = r.id
)
SELECT id, menu_id, parent_id, text FROM my_2ndmenu_items
""", ["menu_B"])

核心调整说明

  • 明确CTE的字段列表,和menu_menuentry表的实际字段一一对应,避免SELECT *带来的字段顺序混乱
  • 用UNION ALL替代UNION:递归查询不需要去重,UNION ALL性能更优
  • 删除递归部分的WHERE m.parent_id IS NOT NULL:因为INNER JOIN已经确保m.parent_id存在(关联到父条目id),这个条件多余

修复后,Django会正确把parent_id映射到MenuEntry.parent外键,自动转换为MenuEntry实例,不会再触发错误。

内容的提问来源于stack exchange,提问作者Alexander Mirnyy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 01:13:31