在WHERE子句字段中没有None的Django SQL查询不起作用

时间:2019-07-17 22:35:36

标签: sql django

为django编写sql查询时遇到问题。

如果查询为Books.objects.filter(id=1, name='ABC'),则使用django.db.connection的sql查询将是:

cur = connection.cursor()
cur.execute('SELECT title FROM book WHERE id = %s AND name = %s',[id, name])

如果名称字段中有值,则此方法有效,但如果名称为None,则返回[]。那么Books.objects.filter(id=1, name=None)的等效值应该是什么。

将同时包含None和其他值的查询是什么?

cur = connection.cursor()
for id, name in [(1, 'A'),(2, None),(3, 'TEST')]:
    cur.execute('????',[id, name])

我想知道是否可以在上面的代码中使用查询代替'????'

1 个答案:

答案 0 :(得分:2)

  

将同时包含None和其他值的查询是什么。

Django实际上容纳None和其他值。如果我们查看生成的查询,它将看起来像:

>>> print(Book.objects.filter(id=4, name=None).query)
SELECT `app_book`.`id`, `app_book`.`name` FROM `app_book` WHERE (`app_book`.`id` = 4 AND `app_book`.`name` IS NULL)

如果您因此在过滤器中传递了None,那么它将把它转换为IS NULL

以及特定字符串:

>>> print(Book.objects.filter(id=4, name='Book name').query)
SELECT `app_book`.`id`, `app_book`.`name` FROM `app_book` WHERE (`app_book`.`id` = 4 AND `app_book`.`name` = Book name)

您可以使用__isnull lookup [Django-doc]使其更明确:

Book.objects.filter(id=4, name__isnull=True)

在SQL中,您不能通过写NULL=进行检查,原因是:

mysql> select NULL = NULL, NULL is NULL, 'foo' is NULL, 'foo' = NULL;
+-------------+--------------+---------------+--------------+
| NULL = NULL | NULL is NULL | 'foo' is NULL | 'foo' = NULL |
+-------------+--------------+---------------+--------------+
|        NULL |            1 |             0 |         NULL |
+-------------+--------------+---------------+--------------+

实际上,用NULL进行检查也会导致NULL

  

我想知道是否会有查询可以代替'????'在上面的代码中

您可以进行更复杂的检查,例如:

cur.execute(
    'SELECT title FROM book WHERE id = %s AND (name = %s or (name = %s) is NULL)',
    [id, name, name]
)

但这会使它变得更复杂且更难阅读,并且可能会使查询的速度比正确格式化它的速度慢。

如果要选择满足2个元组的所有值,则可以生成如下查询:

from django.db.models import Q
from functools import reduce
from operator import or_

data = [(1, 'A'),(2, None),(3, 'TEST')]

Book.objects.filter(
    reduce(or_, [Q(id=id, name=name) for id, name in data])
)