简体   繁体   中英

Django sql query with None in field of WHERE clause not working

I am having issues when writing sql query for django.

If the query is Books.objects.filter(id=1, name='ABC') , the sql query using django.db.connection would be:

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

This works if there is a value in the name field but returns [] if name is None. So what should the equivalent be for Books.objects.filter(id=1, name=None) .

What would be the query to accommodate both None and other values?

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

I was wondering if there would be a query that could be used in place of '????' in the above code.

What would be the query to accommodate both None and other values.

Django actually accommodates both None and other values. If we look at the query that is generated, it will look like:

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

If you thus pass None in the filter, then it will translate this to IS NULL .

and for a specific string:

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

You can make it more explicit by using the __isnull lookup [Django-doc] :

Book.objects.filter(id=4, )

In SQL, you can not check with NULL by writing = , since:

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 |
+-------------+--------------+---------------+--------------+

Indeed, checks with NULL result in NULL as well.

I was wondering if there would be a query that could be used in place of '????' in the above code

You could make a more sophisticated check, like:

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

But this makes it more complex and harder to read, and probably it will make the query slower than formatting it properly.

If you want to select all values that satisfy a 2-tuple, you could generate a query like:

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_, )
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM