mirror of
https://github.com/Infinidat/infi.clickhouse_orm.git
synced 2025-02-16 16:30:34 +03:00
1) Unified QuerySet filter and exclude methods,
so both can load *q and **kwargs at the same time and accept prewhere flag 2) Added ability to add prewhere clause in QuerySet.filter() and QuerySet.exclude() methods 3) Added ability to check, if Q() object is empty (including bool check) 4) Refactored QuerySet.as_sql() method: + don't add GROUP BY and WHERE if it's not needed + ability to add PREWHERE condition + Common style of adding optional query parts
This commit is contained in:
parent
41cf4c3a79
commit
3bc5f27cda
|
@ -183,6 +183,14 @@ class Q(object):
|
|||
self._negate = False
|
||||
self._mode = self.AND_MODE
|
||||
|
||||
@property
|
||||
def is_empty(self):
|
||||
"""
|
||||
Checks if there are any conditions in Q object
|
||||
:return: Boolean
|
||||
"""
|
||||
return bool(self._fovs or self._l_child or self._r_child)
|
||||
|
||||
@classmethod
|
||||
def _construct_from(cls, l_child, r_child, mode):
|
||||
q = Q()
|
||||
|
@ -203,7 +211,7 @@ class Q(object):
|
|||
sql = ' {} '.format(self._mode).join(fov.to_sql(model_cls) for fov in self._fovs)
|
||||
else:
|
||||
if self._l_child and self._r_child:
|
||||
sql = '({} {} {})'.format(
|
||||
sql = '({}) {} ({})'.format(
|
||||
self._l_child.to_sql(model_cls), self._mode, self._r_child.to_sql(model_cls))
|
||||
else:
|
||||
return '1'
|
||||
|
@ -222,6 +230,9 @@ class Q(object):
|
|||
q._negate = True
|
||||
return q
|
||||
|
||||
def __bool__(self):
|
||||
return not self.is_empty
|
||||
|
||||
|
||||
@six.python_2_unicode_compatible
|
||||
class QuerySet(object):
|
||||
|
@ -239,7 +250,8 @@ class QuerySet(object):
|
|||
self._model_cls = model_cls
|
||||
self._database = database
|
||||
self._order_by = []
|
||||
self._q = []
|
||||
self._where_q = Q()
|
||||
self._prewhere_q = Q()
|
||||
self._fields = model_cls.fields().keys()
|
||||
self._limits = None
|
||||
self._distinct = False
|
||||
|
@ -303,14 +315,14 @@ class QuerySet(object):
|
|||
for field in self._order_by
|
||||
])
|
||||
|
||||
def conditions_as_sql(self):
|
||||
def conditions_as_sql(self, q_object):
|
||||
"""
|
||||
Returns the contents of the query's `WHERE` clause as a string.
|
||||
Returns the contents of the query's `WHERE` or `PREWHERE` clause as a string.
|
||||
"""
|
||||
if self._q:
|
||||
return u' AND '.join([q.to_sql(self._model_cls) for q in self._q])
|
||||
if q_object:
|
||||
return u' AND '.join([q.to_sql(self._model_cls) for q in q_object])
|
||||
else:
|
||||
return u'1'
|
||||
return u''
|
||||
|
||||
def count(self):
|
||||
"""
|
||||
|
@ -342,25 +354,40 @@ class QuerySet(object):
|
|||
qs._fields = field_names
|
||||
return qs
|
||||
|
||||
def filter(self, *q, **filter_fields):
|
||||
def _filter_or_exclude(self, *q, **kwargs):
|
||||
reverse = kwargs.pop('reverse', False)
|
||||
prewhere = kwargs.pop('prewhere', False)
|
||||
condition = copy(self._where_q)
|
||||
qs = copy(self)
|
||||
|
||||
if q:
|
||||
condition &= q
|
||||
|
||||
if kwargs:
|
||||
condition &= Q(**kwargs)
|
||||
|
||||
if reverse:
|
||||
condition = ~condition
|
||||
|
||||
if prewhere:
|
||||
qs._prewhere_q = condition
|
||||
else:
|
||||
qs._where_q = condition
|
||||
|
||||
return qs
|
||||
|
||||
def filter(self, *q, **kwargs):
|
||||
"""
|
||||
Returns a copy of this queryset that includes only rows matching the conditions.
|
||||
Add q object to query if it specified.
|
||||
"""
|
||||
qs = copy(self)
|
||||
if q:
|
||||
qs._q = list(self._q) + list(q)
|
||||
else:
|
||||
qs._q = list(self._q) + [Q(**filter_fields)]
|
||||
return qs
|
||||
return self._filter_or_exclude(*q, **kwargs)
|
||||
|
||||
def exclude(self, **filter_fields):
|
||||
def exclude(self, *q, **kwargs):
|
||||
"""
|
||||
Returns a copy of this queryset that excludes all rows matching the conditions.
|
||||
"""
|
||||
qs = copy(self)
|
||||
qs._q = list(self._q) + [~Q(**filter_fields)]
|
||||
return qs
|
||||
return self._filter_or_exclude(*q, reverse=True, **kwargs)
|
||||
|
||||
def paginate(self, page_num=1, page_size=100):
|
||||
"""
|
||||
|
@ -476,20 +503,30 @@ class AggregateQuerySet(QuerySet):
|
|||
Returns the whole query as a SQL string.
|
||||
"""
|
||||
distinct = 'DISTINCT ' if self._distinct else ''
|
||||
grouping = comma_join('`%s`' % field for field in self._grouping_fields)
|
||||
fields = comma_join(list(self._fields) + ['%s AS %s' % (v, k) for k, v in self._calculated_fields.items()])
|
||||
|
||||
params = dict(
|
||||
distinct=distinct,
|
||||
grouping=grouping or "''",
|
||||
fields=fields,
|
||||
table=self._model_cls.table_name(),
|
||||
conds=self.conditions_as_sql()
|
||||
)
|
||||
sql = u'SELECT %(distinct)s%(fields)s\nFROM `%(table)s`\nWHERE %(conds)s\nGROUP BY %(grouping)s' % params
|
||||
sql = u'SELECT %(distinct)s%(fields)s\nFROM `%(table)s`' % params
|
||||
|
||||
if self._prewhere_q:
|
||||
sql += '\nPREWHERE ' + self.conditions_as_sql(self._prewhere_q)
|
||||
|
||||
if self._where_q:
|
||||
sql += '\nWHERE ' + self.conditions_as_sql(self._where_q)
|
||||
|
||||
if self._grouping_fields:
|
||||
sql += '\nGROUP BY %s' % comma_join('`%s`' % field for field in self._grouping_fields)
|
||||
|
||||
if self._order_by:
|
||||
sql += '\nORDER BY ' + self.order_by_as_sql()
|
||||
|
||||
if self._limits:
|
||||
sql += '\nLIMIT %d, %d' % self._limits
|
||||
|
||||
return sql
|
||||
|
||||
def __iter__(self):
|
||||
|
|
Loading…
Reference in New Issue
Block a user