from datetime import datetime from django.core.exceptions import FieldError from django.db.models import CharField, F, Q from django.db.models.expressions import SimpleCol from django.db.models.fields.related_lookups import RelatedIsNull from django.db.models.functions import Lower from django.db.models.lookups import Exact, GreaterThan, IsNull, LessThan from django.db.models.sql.query import Query from django.db.models.sql.where import OR from django.test import SimpleTestCase from django.test.utils import register_lookup from .models import Author, Item, ObjectC, Ranking class TestQuery(SimpleTestCase): def test_simple_query(self): query = Query(Author) where = query.build_where(Q(num__gt=2)) lookup = where.children[0] self.assertIsInstance(lookup, GreaterThan) self.assertEqual(lookup.rhs, 2) self.assertEqual(lookup.lhs.target, Author._meta.get_field('num')) def test_simplecol_query(self): query = Query(Author) where = query.build_where(Q(num__gt=2, name__isnull=False) | Q(num__lt=F('id'))) name_isnull_lookup, num_gt_lookup = where.children[0].children self.assertIsInstance(num_gt_lookup, GreaterThan) self.assertIsInstance(num_gt_lookup.lhs, SimpleCol) self.assertIsInstance(name_isnull_lookup, IsNull) self.assertIsInstance(name_isnull_lookup.lhs, SimpleCol) num_lt_lookup = where.children[1] self.assertIsInstance(num_lt_lookup, LessThan) self.assertIsInstance(num_lt_lookup.rhs, SimpleCol) self.assertIsInstance(num_lt_lookup.lhs, SimpleCol) def test_complex_query(self): query = Query(Author) where = query.build_where(Q(num__gt=2) | Q(num__lt=0)) self.assertEqual(where.connector, OR) lookup = where.children[0] self.assertIsInstance(lookup, GreaterThan) self.assertEqual(lookup.rhs, 2) self.assertEqual(lookup.lhs.target, Author._meta.get_field('num')) lookup = where.children[1] self.assertIsInstance(lookup, LessThan) self.assertEqual(lookup.rhs, 0) self.assertEqual(lookup.lhs.target, Author._meta.get_field('num')) def test_multiple_fields(self): query = Query(Item) where = query.build_where(Q(modified__gt=F('created'))) lookup = where.children[0] self.assertIsInstance(lookup, GreaterThan) self.assertIsInstance(lookup.rhs, SimpleCol) self.assertIsInstance(lookup.lhs, SimpleCol) self.assertEqual(lookup.rhs.target, Item._meta.get_field('created')) self.assertEqual(lookup.lhs.target, Item._meta.get_field('modified')) def test_transform(self): query = Query(Author) with register_lookup(CharField, Lower): where = query.build_where(~Q(name__lower='foo')) lookup = where.children[0] self.assertIsInstance(lookup, Exact) self.assertIsInstance(lookup.lhs, Lower) self.assertIsInstance(lookup.lhs.lhs, SimpleCol) self.assertEqual(lookup.lhs.lhs.target, Author._meta.get_field('name')) def test_negated_nullable(self): query = Query(Item) where = query.build_where(~Q(modified__lt=datetime(2017, 1, 1))) self.assertTrue(where.negated) lookup = where.children[0] self.assertIsInstance(lookup, LessThan) self.assertEqual(lookup.lhs.target, Item._meta.get_field('modified')) lookup = where.children[1] self.assertIsInstance(lookup, IsNull) self.assertEqual(lookup.lhs.target, Item._meta.get_field('modified')) def test_foreign_key(self): query = Query(Item) msg = 'Joined field references are not permitted in this query' with self.assertRaisesMessage(FieldError, msg): query.build_where(Q(creator__num__gt=2)) def test_foreign_key_f(self): query = Query(Ranking) with self.assertRaises(FieldError): query.build_where(Q(rank__gt=F('author__num'))) def test_foreign_key_exclusive(self): query = Query(ObjectC) where = query.build_where(Q(objecta=None) | Q(objectb=None)) a_isnull = where.children[0] self.assertIsInstance(a_isnull, RelatedIsNull) self.assertIsInstance(a_isnull.lhs, SimpleCol) self.assertEqual(a_isnull.lhs.target, ObjectC._meta.get_field('objecta')) b_isnull = where.children[1] self.assertIsInstance(b_isnull, RelatedIsNull) self.assertIsInstance(b_isnull.lhs, SimpleCol) self.assertEqual(b_isnull.lhs.target, ObjectC._meta.get_field('objectb')) def test_clone_select_related(self): query = Query(Item) query.add_select_related(['creator']) clone = query.clone() clone.add_select_related(['note', 'creator__extra']) self.assertEqual(query.select_related, {'creator': {}}) def test_iterable_lookup_value(self): query = Query(Item) where = query.build_where(Q(name=['a', 'b'])) name_exact = where.children[0] self.assertIsInstance(name_exact, Exact) self.assertEqual(name_exact.rhs, "['a', 'b']")