mirror of
https://github.com/Infinidat/infi.clickhouse_orm.git
synced 2024-11-22 00:56:34 +03:00
1) Fixed bugs
2) Edited the docs 3) Added test for prewhere
This commit is contained in:
parent
95055996ad
commit
12463c61b8
|
@ -17,21 +17,29 @@ The `filter` and `exclude` methods are used for filtering the matching instances
|
||||||
|
|
||||||
>>> qs = Person.objects_in(database)
|
>>> qs = Person.objects_in(database)
|
||||||
>>> qs = qs.filter(first_name__startswith='V').exclude(birthday__lt='2000-01-01')
|
>>> qs = qs.filter(first_name__startswith='V').exclude(birthday__lt='2000-01-01')
|
||||||
>>> qs.conditions_as_sql()
|
>>> qs.conditions_as_sql(qs._where)
|
||||||
u"first_name LIKE 'V%' AND NOT (birthday < '2000-01-01')"
|
u"first_name LIKE 'V%' AND NOT (birthday < '2000-01-01')"
|
||||||
|
|
||||||
It is possible to specify several fields to filter or exclude by:
|
It is possible to specify several fields to filter or exclude by:
|
||||||
|
|
||||||
>>> qs = Person.objects_in(database).filter(last_name='Smith', height__gt=1.75)
|
>>> qs = Person.objects_in(database).filter(last_name='Smith', height__gt=1.75)
|
||||||
>>> qs.conditions_as_sql()
|
>>> qs.conditions_as_sql(qs._where)
|
||||||
u"last_name = 'Smith' AND height > 1.75"
|
u"last_name = 'Smith' AND height > 1.75"
|
||||||
|
|
||||||
For filters with compound conditions you can use `Q` objects inside `filter` with overloaded operators `&` (AND), `|` (OR) and `~` (NOT):
|
For filters with compound conditions you can use `Q` objects inside `filter` with overloaded operators `&` (AND), `|` (OR) and `~` (NOT):
|
||||||
|
|
||||||
>>> qs = Person.objects_in(database).filter((Q(first_name='Ciaran', last_name='Carver') | Q(height_lte=1.8)) & ~Q(first_name='David'))
|
>>> qs = Person.objects_in(database).filter((Q(first_name='Ciaran', last_name='Carver') | Q(height_lte=1.8)) & ~Q(first_name='David'))
|
||||||
>>> qs.conditions_as_sql()
|
>>> qs.conditions_as_sql(qs._where)
|
||||||
u"((first_name = 'Ciaran' AND last_name = 'Carver') OR height <= 1.8) AND (NOT (first_name = 'David'))"
|
u"((first_name = 'Ciaran' AND last_name = 'Carver') OR height <= 1.8) AND (NOT (first_name = 'David'))"
|
||||||
|
|
||||||
|
By default conditions from `filter` and `exclude` methods are add to `WHERE` clause.
|
||||||
|
For better aggregation performance you can add them to `PREWHERE` section using `prewhere=True` parameter
|
||||||
|
|
||||||
|
>>> qs = Person.objects_in(database)
|
||||||
|
>>> qs = qs.filter(first_name__startswith='V', prewhere=True)
|
||||||
|
>>> qs.conditions_as_sql(qs._prewhere)
|
||||||
|
u"first_name LIKE 'V%'"
|
||||||
|
|
||||||
There are different operators that can be used, by passing `<fieldname>__<operator>=<value>` (two underscores separate the field name from the operator). In case no operator is given, `eq` is used by default. Below are all the supported operators.
|
There are different operators that can be used, by passing `<fieldname>__<operator>=<value>` (two underscores separate the field name from the operator). In case no operator is given, `eq` is used by default. Below are all the supported operators.
|
||||||
|
|
||||||
| Operator | Equivalent SQL | Comments |
|
| Operator | Equivalent SQL | Comments |
|
||||||
|
|
|
@ -189,14 +189,14 @@ class Q(object):
|
||||||
Checks if there are any conditions in Q object
|
Checks if there are any conditions in Q object
|
||||||
:return: Boolean
|
:return: Boolean
|
||||||
"""
|
"""
|
||||||
return bool(self._fovs or self._l_child or self._r_child)
|
return not bool(self._fovs or self._l_child or self._r_child)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _construct_from(cls, l_child, r_child, mode):
|
def _construct_from(cls, l_child, r_child, mode):
|
||||||
q = Q()
|
q = Q()
|
||||||
q._l_child = l_child
|
q._l_child = l_child
|
||||||
q._r_child = r_child
|
q._r_child = r_child
|
||||||
q._mode = mode # AND/OR
|
q._mode = mode # AND/OR
|
||||||
return q
|
return q
|
||||||
|
|
||||||
def _build_fov(self, key, value):
|
def _build_fov(self, key, value):
|
||||||
|
@ -209,14 +209,17 @@ class Q(object):
|
||||||
def to_sql(self, model_cls):
|
def to_sql(self, model_cls):
|
||||||
if self._fovs:
|
if self._fovs:
|
||||||
sql = ' {} '.format(self._mode).join(fov.to_sql(model_cls) for fov in self._fovs)
|
sql = ' {} '.format(self._mode).join(fov.to_sql(model_cls) for fov in self._fovs)
|
||||||
|
elif self._l_child and self._r_child:
|
||||||
|
sql = '({}) {} ({})'.format(self._l_child.to_sql(model_cls), self._mode, self._r_child.to_sql(model_cls))
|
||||||
|
elif self._l_child or self._r_child:
|
||||||
|
# Return existing condition
|
||||||
|
sql = (self._l_child or self._r_child).to_sql(model_cls)
|
||||||
else:
|
else:
|
||||||
if self._l_child and self._r_child:
|
sql = '1'
|
||||||
sql = '({}) {} ({})'.format(
|
|
||||||
self._l_child.to_sql(model_cls), self._mode, self._r_child.to_sql(model_cls))
|
|
||||||
else:
|
|
||||||
return '1'
|
|
||||||
if self._negate:
|
if self._negate:
|
||||||
sql = 'NOT (%s)' % sql
|
sql = 'NOT (%s)' % sql
|
||||||
|
|
||||||
return sql
|
return sql
|
||||||
|
|
||||||
def __or__(self, other):
|
def __or__(self, other):
|
||||||
|
@ -303,7 +306,7 @@ class QuerySet(object):
|
||||||
distinct = 'DISTINCT ' if self._distinct else ''
|
distinct = 'DISTINCT ' if self._distinct else ''
|
||||||
|
|
||||||
params = (distinct, self.select_fields_as_sql(), self._model_cls.table_name())
|
params = (distinct, self.select_fields_as_sql(), self._model_cls.table_name())
|
||||||
sql = u'SELECT %s%s\nFROM `%s`\n' % params
|
sql = u'SELECT %s%s\nFROM `%s`' % params
|
||||||
|
|
||||||
if self._prewhere_q:
|
if self._prewhere_q:
|
||||||
sql += '\nPREWHERE ' + self.conditions_as_sql(self._prewhere_q)
|
sql += '\nPREWHERE ' + self.conditions_as_sql(self._prewhere_q)
|
||||||
|
@ -320,7 +323,7 @@ class QuerySet(object):
|
||||||
if self._limits:
|
if self._limits:
|
||||||
sql += '\nLIMIT %d, %d' % self._limits
|
sql += '\nLIMIT %d, %d' % self._limits
|
||||||
|
|
||||||
return
|
return sql
|
||||||
|
|
||||||
def order_by_as_sql(self):
|
def order_by_as_sql(self):
|
||||||
"""
|
"""
|
||||||
|
@ -335,10 +338,7 @@ class QuerySet(object):
|
||||||
"""
|
"""
|
||||||
Returns the contents of the query's `WHERE` or `PREWHERE` clause as a string.
|
Returns the contents of the query's `WHERE` or `PREWHERE` clause as a string.
|
||||||
"""
|
"""
|
||||||
if q_object:
|
return q_object.to_sql(self._model_cls)
|
||||||
return u' AND '.join([q.to_sql(self._model_cls) for q in q_object])
|
|
||||||
else:
|
|
||||||
return u''
|
|
||||||
|
|
||||||
def count(self):
|
def count(self):
|
||||||
"""
|
"""
|
||||||
|
@ -378,8 +378,8 @@ class QuerySet(object):
|
||||||
condition = copy(self._where_q)
|
condition = copy(self._where_q)
|
||||||
qs = copy(self)
|
qs = copy(self)
|
||||||
|
|
||||||
if q:
|
for q_obj in q:
|
||||||
condition &= q
|
condition &= q_obj
|
||||||
|
|
||||||
if kwargs:
|
if kwargs:
|
||||||
condition &= Q(**kwargs)
|
condition &= Q(**kwargs)
|
||||||
|
@ -487,7 +487,8 @@ class AggregateQuerySet(QuerySet):
|
||||||
self._grouping_fields = grouping_fields
|
self._grouping_fields = grouping_fields
|
||||||
self._calculated_fields = calculated_fields
|
self._calculated_fields = calculated_fields
|
||||||
self._order_by = list(base_qs._order_by)
|
self._order_by = list(base_qs._order_by)
|
||||||
self._q = list(base_qs._q)
|
self._where_q = base_qs._where_q
|
||||||
|
self._prewhere_q = base_qs._prewhere_q
|
||||||
self._limits = base_qs._limits
|
self._limits = base_qs._limits
|
||||||
self._distinct = base_qs._distinct
|
self._distinct = base_qs._distinct
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ from datetime import date, datetime
|
||||||
try:
|
try:
|
||||||
Enum # exists in Python 3.4+
|
Enum # exists in Python 3.4+
|
||||||
except NameError:
|
except NameError:
|
||||||
from enum import Enum # use the enum34 library instead
|
from enum import Enum # use the enum34 library instead
|
||||||
|
|
||||||
|
|
||||||
class QuerySetTestCase(TestCaseWithData):
|
class QuerySetTestCase(TestCaseWithData):
|
||||||
|
@ -29,6 +29,13 @@ class QuerySetTestCase(TestCaseWithData):
|
||||||
self.assertEqual(count, expected_count)
|
self.assertEqual(count, expected_count)
|
||||||
self.assertEqual(qs.count(), expected_count)
|
self.assertEqual(qs.count(), expected_count)
|
||||||
|
|
||||||
|
def test_prewhere(self):
|
||||||
|
# We can't distinguish prewhere and where results, it affects performance only.
|
||||||
|
# So let's control prewhere acts like where does
|
||||||
|
qs = Person.objects_in(self.database)
|
||||||
|
self.assertTrue(qs.filter(first_name='Connor', prewhere=True))
|
||||||
|
self.assertFalse(qs.filter(first_name='Willy', prewhere=True))
|
||||||
|
|
||||||
def test_no_filtering(self):
|
def test_no_filtering(self):
|
||||||
qs = Person.objects_in(self.database)
|
qs = Person.objects_in(self.database)
|
||||||
self._test_qs(qs, len(data))
|
self._test_qs(qs, len(data))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user