Fixed #29396 -- Added indirect values support to __year lookups.
Thanks Windson Yang for the initial patch.
This commit is contained in:
parent
4d1420947e
commit
2b582a7b84
|
@ -486,14 +486,18 @@ class YearLookup(Lookup):
|
||||||
|
|
||||||
class YearComparisonLookup(YearLookup):
|
class YearComparisonLookup(YearLookup):
|
||||||
def as_sql(self, compiler, connection):
|
def as_sql(self, compiler, connection):
|
||||||
# We will need to skip the extract part and instead go
|
# Avoid the extract operation if the rhs is a direct value to allow
|
||||||
# directly with the originating field, that is self.lhs.lhs.
|
# indexes to be used.
|
||||||
lhs_sql, params = self.process_lhs(compiler, connection, self.lhs.lhs)
|
if self.rhs_is_direct_value():
|
||||||
rhs_sql, rhs_params = self.process_rhs(compiler, connection)
|
# Skip the extract part by directly using the originating field,
|
||||||
rhs_sql = self.get_rhs_op(connection, rhs_sql)
|
# that is self.lhs.lhs.
|
||||||
start, finish = self.year_lookup_bounds(connection, rhs_params[0])
|
lhs_sql, params = self.process_lhs(compiler, connection, self.lhs.lhs)
|
||||||
params.append(self.get_bound(start, finish))
|
rhs_sql, _ = self.process_rhs(compiler, connection)
|
||||||
return '%s %s' % (lhs_sql, rhs_sql), params
|
rhs_sql = self.get_rhs_op(connection, rhs_sql)
|
||||||
|
start, finish = self.year_lookup_bounds(connection, self.rhs)
|
||||||
|
params.append(self.get_bound(start, finish))
|
||||||
|
return '%s %s' % (lhs_sql, rhs_sql), params
|
||||||
|
return super().as_sql(compiler, connection)
|
||||||
|
|
||||||
def get_rhs_op(self, connection, rhs):
|
def get_rhs_op(self, connection, rhs):
|
||||||
return connection.operators[self.lookup_name] % rhs
|
return connection.operators[self.lookup_name] % rhs
|
||||||
|
@ -520,29 +524,22 @@ class YearExact(YearLookup, Exact):
|
||||||
return super().as_sql(compiler, connection)
|
return super().as_sql(compiler, connection)
|
||||||
|
|
||||||
|
|
||||||
class YearGt(YearComparisonLookup):
|
|
||||||
lookup_name = 'gt'
|
|
||||||
|
|
||||||
|
class YearGt(YearComparisonLookup, GreaterThan):
|
||||||
def get_bound(self, start, finish):
|
def get_bound(self, start, finish):
|
||||||
return finish
|
return finish
|
||||||
|
|
||||||
|
|
||||||
class YearGte(YearComparisonLookup):
|
class YearGte(YearComparisonLookup, GreaterThanOrEqual):
|
||||||
lookup_name = 'gte'
|
|
||||||
|
|
||||||
def get_bound(self, start, finish):
|
def get_bound(self, start, finish):
|
||||||
return start
|
return start
|
||||||
|
|
||||||
|
|
||||||
class YearLt(YearComparisonLookup):
|
class YearLt(YearComparisonLookup, LessThan):
|
||||||
lookup_name = 'lt'
|
|
||||||
|
|
||||||
def get_bound(self, start, finish):
|
def get_bound(self, start, finish):
|
||||||
return start
|
return start
|
||||||
|
|
||||||
|
|
||||||
class YearLte(YearComparisonLookup):
|
class YearLte(YearComparisonLookup, LessThanOrEqual):
|
||||||
lookup_name = 'lte'
|
|
||||||
|
|
||||||
def get_bound(self, start, finish):
|
def get_bound(self, start, finish):
|
||||||
return finish
|
return finish
|
||||||
|
|
|
@ -135,6 +135,11 @@ class DateFunctionTests(TestCase):
|
||||||
qs = DTModel.objects.filter(**{'start_datetime__%s__gte' % lookup: 2015})
|
qs = DTModel.objects.filter(**{'start_datetime__%s__gte' % lookup: 2015})
|
||||||
self.assertEqual(qs.count(), 2)
|
self.assertEqual(qs.count(), 2)
|
||||||
self.assertEqual(str(qs.query).lower().count('extract'), 0)
|
self.assertEqual(str(qs.query).lower().count('extract'), 0)
|
||||||
|
qs = DTModel.objects.annotate(
|
||||||
|
start_year=ExtractYear('start_datetime'),
|
||||||
|
).filter(**{'end_datetime__%s__gte' % lookup: F('start_year')})
|
||||||
|
self.assertEqual(qs.count(), 1)
|
||||||
|
self.assertGreaterEqual(str(qs.query).lower().count('extract'), 2)
|
||||||
|
|
||||||
def test_extract_year_lessthan_lookup(self):
|
def test_extract_year_lessthan_lookup(self):
|
||||||
start_datetime = datetime(2015, 6, 15, 14, 10)
|
start_datetime = datetime(2015, 6, 15, 14, 10)
|
||||||
|
@ -153,6 +158,11 @@ class DateFunctionTests(TestCase):
|
||||||
qs = DTModel.objects.filter(**{'start_datetime__%s__lte' % lookup: 2016})
|
qs = DTModel.objects.filter(**{'start_datetime__%s__lte' % lookup: 2016})
|
||||||
self.assertEqual(qs.count(), 2)
|
self.assertEqual(qs.count(), 2)
|
||||||
self.assertEqual(str(qs.query).count('extract'), 0)
|
self.assertEqual(str(qs.query).count('extract'), 0)
|
||||||
|
qs = DTModel.objects.annotate(
|
||||||
|
end_year=ExtractYear('end_datetime'),
|
||||||
|
).filter(**{'start_datetime__%s__lte' % lookup: F('end_year')})
|
||||||
|
self.assertEqual(qs.count(), 1)
|
||||||
|
self.assertGreaterEqual(str(qs.query).lower().count('extract'), 2)
|
||||||
|
|
||||||
def test_extract_func(self):
|
def test_extract_func(self):
|
||||||
start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
|
start_datetime = datetime(2015, 6, 15, 14, 30, 50, 321)
|
||||||
|
|
Loading…
Reference in New Issue