我有一个可重复使用的django应用程序,它应该支持python2.7
,python 3.x
和pypy
。我在开始时在python 2.7
开发了它,我的所有测试都运行得很好。我也让他们在python3.3
工作。但我对python3.4
,pypy
,pypy3
有疑问;
django.db.utils.OperationalError: parser stack overflow
我的测试在sqlite3
上运行。我检查了跟踪,我猜它是关于查询大小的。我找不到任何解决方案来解决这个问题。
我在我的sqlite3
环境中覆盖了内置python3.4
代码来pring哪个sql,它是否会引发错误。这真是个大sql。 这没关系,你不需要检查sql,我只是在这里发布它以显示它是多么大。这也可能比这更大。因为queryset
正在for循环中运行时构建。
顺便说一下,正如我之前所说,python2.7
和python3.3
没有问题。问题引起了他人的注意。
是否有任何配置可以解决这个问题?
这是sql:
SELECT "river_approvement".
"id", "river_approvement".
"content_type_id", "river_approvement".
"object_id", "river_approvement".
"field", "river_approvement".
"meta_id", "river_approvement".
"transactioner_id", "river_approvement".
"transaction_date", "river_approvement".
"status", "river_approvement".
"skip", "river_approvement".
"order", "river_approvement".
"enabled"
FROM "river_approvement"
INNER JOIN "river_approvementmeta"
ON("river_approvement".
"meta_id" = "river_approvementmeta".
"id") INNER JOIN "river_transition"
ON("river_approvementmeta".
"transition_id" = "river_transition".
"id") WHERE("river_approvement".
"field" = ? AND "river_transition".
"source_state_id"
IN(SELECT AB0.
"id"
FROM "river_state"
AB0 WHERE AB0.
"id"
IN(SELECT AA2.
"destination_state_id"
FROM "river_approvement"
AA0 INNER JOIN "river_approvementmeta"
AA1 ON(AA0.
"meta_id" = AA1.
"id") INNER JOIN "river_transition"
AA2 ON(AA1.
"transition_id" = AA2.
"id") WHERE(AA0.
"field" = ? AND AA2.
"source_state_id"
IN(SELECT Z0.
"id"
FROM "river_state"
Z0 WHERE Z0.
"id"
IN(SELECT Y2.
"destination_state_id"
FROM "river_approvement"
Y0 INNER JOIN "river_approvementmeta"
Y1 ON(Y0.
"meta_id" = Y1.
"id") INNER JOIN "river_transition"
Y2 ON(Y1.
"transition_id" = Y2.
"id") WHERE(Y0.
"field" = ? AND Y2.
"source_state_id"
IN(SELECT X0.
"id"
FROM "river_state"
X0 WHERE X0.
"id"
IN(SELECT W2.
"destination_state_id"
FROM "river_approvement"
W0 INNER JOIN "river_approvementmeta"
W1 ON(W0.
"meta_id" = W1.
"id") INNER JOIN "river_transition"
W2 ON(W1.
"transition_id" = W2.
"id") WHERE(W0.
"field" = ? AND W2.
"source_state_id"
IN(SELECT V0.
"id"
FROM "river_state"
V0 WHERE V0.
"id"
IN(SELECT U2.
"destination_state_id"
FROM "river_approvement"
U0 INNER JOIN "river_approvementmeta"
U1 ON(U0.
"meta_id" = U1.
"id") INNER JOIN "river_transition"
U2 ON(U1.
"transition_id" = U2.
"id") WHERE(U0.
"field" = ? AND U2.
"source_state_id"
IN( ? ) AND U0.
"object_id" = ? AND U0.
"content_type_id" = ? ))) AND W0.
"object_id" = ? AND W0.
"content_type_id" = ? ))) AND Y0.
"object_id" = ? AND Y0.
"content_type_id" = ? ))) AND AA0.
"object_id" = ? AND AA0.
"content_type_id" = ? ))) AND "river_approvement".
"object_id" = ? AND "river_approvement".
"content_type_id" = ? )
答案 0 :(得分:0)
默认sqlite3 parser stack size是100个词汇项。他们认为"它很可能远远超出任何人理解的能力。。我在你的例子中看到了许多嵌套级别:15个parenheses,9" SELECT",9" WHERE",9" IN",5" AND&#34 ;。这是我可以用任何可能的解析器graologic在堆栈上想象的最小必要术语。也许连接或隐形的东西被计入,但100的大小是有道理的。可以使用选项YYSTACKDEPTH = -1或大正数来重新编译Sqlite3(-1是从100开始并每次加倍的动态深度堆栈),但它不是可重用公共应用程序的解决方案。
通过在AND
之前移动复杂的术语(子选择)作为布尔表达式的第一项,可以稍微改进一下。它可以通过以下方式完成:
MyModel.objects. \
filter(meta__transition__destination_state_id__in=
MyModel.objects.filter(...)
).filter(field=...)
它可以将堆栈大小稍微提高5" AND" 100项。
您可能会在一个过滤器中使用包含更多条件的过滤器表达式:filter(field_1=value_1, field_2=value_2)
与filter(**{'field_1': value_1, 'field_2': value_2})
相同。字典中项目的顺序取决于相应CPython版本中hash
函数的实现,甚至取决于pypy上字典本身的实现细节。这就是为什么只有某些Python版本才会引发异常的原因。如果添加一个类似复杂的附加子选择,则每个Python都必须引发异常。
Django queryset使用的结果可以很容易地检查而不运行它:
print(my_complicated_queryset.query.get_compiler('default').as_sql())
'default'
是settings.DATABASES
中的连接别名。