3

我有一个列表,当在外部表的非主键“测试”中找到任何这些项目时,我想过滤我的查询集。所以我写了这样的东西:

test_list = ['test1', 'test2', 'test3', 'test4', 'test5']
return cls.objects.filter(reduce(lambda x, y: x | y, [models.Q(next_task__test = item) for item in test_list]))[:20]

这将返回一个空列表。当我查看它生成的 SQL 查询时,我得到:

SELECT ...
FROM ...
WHERE "job"."next_task_id" IN (test1, test2, test3, test4, test5) LIMIT 20;

而它应该是这样的:

SELECT ...
FROM ...
WHERE "job"."next_task_id" IN ('test1', 'test2', 'test3', 'test4', 'test5') LIMIT 20;

没有引号,SQLite3 认为这些是列名,并且不返回任何内容。当我在没有 Django 的情况下手动添加引号并在表上执行 SQLite3 查询时,我得到了想要的结果。如何让 Django 正确发出查询?

4

3 回答 3

6

这个问题很有趣,它似乎只发生在 SQLite 上。在这里众所周知:https ://code.djangoproject.com/ticket/14091和docs

所以基本上查询可能没有错,但是当你用 Django 取回查询时,它看起来是错误的:

>>> test_list = ['test1', 'test2', 'test3', 'test4', 'test5']
>>> cls.objects.filter(next_task__test__in=test_list).query.__str__()

SELECT ...
FROM ...
WHERE "job"."next_task_id" IN (test1, test2, test3, test4, test5);

解决方法:如果您确实认为查询错误,请为列表提供更多报价,例如:

>>> test_list = ["'test1'", "'test2'", "'test3'", "'test4'", "'test5'"]
>>> cls.objects.filter(next_task__test__in=test_list).query.__str__()

SELECT ...
FROM ...
WHERE "job"."next_task_id" IN ('test1', 'test2', 'test3', 'test4', 'test5');

无论如何,我都会依赖标准的,上面的工作太老套了。

于 2013-08-06T12:32:51.650 回答
1

我真的很喜欢@Andrey-St 的回答,但一位同事指出,这需要往返数据库来完成这项工作。因此,我们将其更改为仅从光标中获取格式化的查询。

 def stringify_queryset(qs):
     sql, params = qs.query.sql_with_params()
     with connection.cursor() as cursor:
         return cursor.mogrify(sql, params)

(我们将 psycopg2 用于 Postgres——我不确定是否mogrify()可以在其他数据库引擎上使用)。

于 2020-11-30T20:56:34.003 回答
0
def stringify_queryset(qs: QuerySet) -> str:
    sql, params = qs.query.sql_with_params()
    with connection.cursor() as cursor:
        cursor.execute('EXPLAIN ' + sql, params)
        raw_sql =  cursor.db.ops.last_executed_query(cursor, sql, params)
    raw_sql = raw_sql[len('EXPLAIN '):]
    return raw_sql

(取自https://code.djangoproject.com/ticket/17741

于 2020-06-05T12:28:41.637 回答