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

Djongo添加Station对象时触发RecursionError问题求助

Django + Djongo: RecursionError When Adding Station with ForeignKey in Admin Panel

问题背景

在Django管理面板添加Station对象时触发RecursionError,错误提示为"no exception message supplied"。移除Station模型中的ForeignKey关联后错误消失,但业务上必须保留该关联逻辑。

核心报错片段

File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\tokens.py", line 19, in __contains__
    return item is not None and (self is item or item[:len(self)] == self)
RecursionError: maximum recursion depth exceeded in comparison

模型代码

from djongo import models

class City(models.Model):
    name = models.CharField(max_length=100)
    
class Station(models.Model):
    name = models.CharField(max_length=100)
    city = models.ForeignKey(City, on_delete=models.CASCADE)

    def __str__(self):
        return self.name

class Bus(models.Model):
    number = models.CharField(max_length=10)
    stations = models.ManyToManyField(Station)

    def __str__(self):
        return self.number

完整报错回溯

Internal Server Error: /admin/bus/station/add/
Traceback (most recent call last):
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\djongo\sql2mongo\query.py", line 808, in __iter__
    yield from iter(self._query)
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\djongo\sql2mongo\query.py", line 167, in __iter__
    yield self._align_results(doc)
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\djongo\sql2mongo\query.py", line 269, in _align_results
    if selected.table == self.left_table:
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\djongo\sql2mongo\sql_tokens.py", line 133, in table
    return alias2token[name].table
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\djongo\sql2mongo\sql_tokens.py", line 133, in table
    return alias2token[name].table
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\djongo\sql2mongo\sql_tokens.py", line 133, in table
    return alias2token[name].table
  [Previous line repeated 917 more times]
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\djongo\sql2mongo\sql_tokens.py", line 130, in table
    name = self.given_table
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\djongo\sql2mongo\sql_tokens.py", line 141, in given_table
    name = self._token.get_real_name()
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\sql.py", line 361, in get_real_name
    return self._get_first_name(dot_idx)
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\sql.py", line 386, in _get_first_name
    return token.get_name()
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\sql.py", line 355, in get_name
    return self.get_alias() or self.get_real_name()
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\sql.py", line 344, in get_alias
    _, ws = self.token_next_by(t=T.Whitespace)
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\sql.py", line 244, in token_next_by
    return self._token_matching(funcs, idx, end)
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\sql.py", line 223, in _token_matching
    if func(token):
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\sql.py", line 242, in <lambda>
    funcs = lambda tk: imt(tk, i, m, t)
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\utils.py", line 100, in imt
    elif types and any(token.ttype in ttype for ttype in types):
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\utils.py", line 100, in <genexpr>
    elif types and any(token.ttype in ttype for ttype in types):
  File "C:\Users\Admin\Envs\routemaster\lib\site-packages\sqlparse\tokens.py", line 19, in __contains__
    return item is not None and (self is item or item[:len(self)] == self)
RecursionError: maximum recursion depth exceeded in comparison

问题分析

从回溯信息可以看出,递归触发点在Djongo的sql_tokens.py文件中table属性的getter方法(重复调用alias2token[name].table),最终导致sqlparse库的递归比较溢出。这是Djongo处理ForeignKey关联时的已知兼容性bug,并非你的模型存在循环引用——你的模型关联逻辑是单向的(City→Station→Bus),不存在循环依赖。

解决方案

1. 显式指定ForeignKey的related_name

给Station模型的city字段添加明确的related_name,避免Djongo自动生成的名称引发解析冲突:

class Station(models.Model):
    name = models.CharField(max_length=100)
    city = models.ForeignKey(City, on_delete=models.CASCADE, related_name='stations')

    def __str__(self):
        return self.name

2. 调整Djongo版本

该递归问题在Djongo的部分版本中已被修复,尝试切换到经过验证的稳定版本:

pip install djongo==1.3.6

3. 自定义Admin表单简化查询

修改StationAdmin类,限制Admin加载的字段或优化查询逻辑,避免触发Djongo的bug:

from django.contrib import admin
from .models import Station

class StationAdmin(admin.ModelAdmin):
    fields = ('name', 'city')  # 仅显示必要字段,减少自动查询
    def get_queryset(self, request):
        # 提前预加载关联的City对象,简化查询结构
        return super().get_queryset(request).select_related('city')

admin.site.register(Station, StationAdmin)

4. 临时通过Shell创建对象

如果需要紧急创建Station对象,可以绕过Admin面板,直接通过Django Shell操作:

python manage.py shell
from myapp.models import City, Station
# 假设已存在名为"Beijing"的City对象
city = City.objects.get(name='Beijing')
Station.objects.create(name='Central Station', city=city)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 23:52:05