Reputation: 981
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.
Upvotes: 1
Views: 759
Reputation: 476669
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=None).query)
SELECT `app_book`.`id`, `app_book`.`name` FROM `app_book` WHERE (`app_book`.`id` = 4 AND `app_book`.`name` IS NULL)
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='Book name').query)
SELECT `app_book`.`id`, `app_book`.`name` FROM `app_book` WHERE (`app_book`.`id` = 4 AND `app_book`.`name` = Book name)
You can make it more explicit by using the __isnull
lookup [Django-doc]:
Book.objects.filter(id=4, name__isnull=True)
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_, [Q(id=id, name=name) for id, name in data])
)
Upvotes: 2