0.18
This commit is contained in:
@@ -8,7 +8,7 @@ PYTHON3 = True
|
|||||||
if sys.version_info[0] < 3:
|
if sys.version_info[0] < 3:
|
||||||
PYTHON3 = False
|
PYTHON3 = False
|
||||||
|
|
||||||
VERSION = "0.0.14"
|
VERSION = "0.0.18"
|
||||||
|
|
||||||
|
|
||||||
def is_map(obj):
|
def is_map(obj):
|
||||||
@@ -23,13 +23,12 @@ def ensureUtf(s):
|
|||||||
if isinstance(s, str):
|
if isinstance(s, str):
|
||||||
return s
|
return s
|
||||||
else:
|
else:
|
||||||
return s.encode('utf8', 'ignore')
|
return s.encode("utf8", "ignore")
|
||||||
except:
|
except:
|
||||||
return str(s)
|
return str(s)
|
||||||
|
|
||||||
|
|
||||||
class classproperty(object):
|
class classproperty(object):
|
||||||
|
|
||||||
def __init__(self, getter):
|
def __init__(self, getter):
|
||||||
self.getter = getter
|
self.getter = getter
|
||||||
|
|
||||||
@@ -38,10 +37,10 @@ class classproperty(object):
|
|||||||
|
|
||||||
|
|
||||||
class QMixin(object):
|
class QMixin(object):
|
||||||
AND = 'AND'
|
AND = "AND"
|
||||||
OR = 'OR'
|
OR = "OR"
|
||||||
NOT = 'NOT'
|
NOT = "NOT"
|
||||||
UNION = 'UNION'
|
UNION = "UNION"
|
||||||
|
|
||||||
def _combine(self, other, conn):
|
def _combine(self, other, conn):
|
||||||
return Operator(conn, self, other)
|
return Operator(conn, self, other)
|
||||||
@@ -54,18 +53,21 @@ class QMixin(object):
|
|||||||
def __and__(self, other):
|
def __and__(self, other):
|
||||||
return self._combine(other, self.AND)
|
return self._combine(other, self.AND)
|
||||||
|
|
||||||
def __invert__(self,):
|
def __invert__(
|
||||||
|
self,
|
||||||
|
):
|
||||||
return Operator(self.NOT, self)
|
return Operator(self.NOT, self)
|
||||||
|
|
||||||
|
|
||||||
class Operator(QMixin):
|
class Operator(QMixin):
|
||||||
|
|
||||||
def __init__(self, op=None, left=None, right=None):
|
def __init__(self, op=None, left=None, right=None):
|
||||||
self.op = op
|
self.op = op
|
||||||
self.left = left
|
self.left = left
|
||||||
self.right = right
|
self.right = right
|
||||||
|
|
||||||
def __repr__(self,):
|
def __repr__(
|
||||||
|
self,
|
||||||
|
):
|
||||||
if self.left and self.right:
|
if self.left and self.right:
|
||||||
return "(%s %s %s)" % (self.left, self.op, self.right)
|
return "(%s %s %s)" % (self.left, self.op, self.right)
|
||||||
|
|
||||||
@@ -86,11 +88,12 @@ class Operator(QMixin):
|
|||||||
|
|
||||||
|
|
||||||
class F(object):
|
class F(object):
|
||||||
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def __repr__(self,):
|
def __repr__(
|
||||||
|
self,
|
||||||
|
):
|
||||||
return "%s" % self.value
|
return "%s" % self.value
|
||||||
|
|
||||||
__str__ = __repr__
|
__str__ = __repr__
|
||||||
@@ -105,16 +108,28 @@ class Q(QMixin):
|
|||||||
_mode = "MYSQL"
|
_mode = "MYSQL"
|
||||||
|
|
||||||
lookup_types = [
|
lookup_types = [
|
||||||
'icontains', 'istartswith', 'iendswith',
|
"icontains",
|
||||||
'contains', 'startswith', 'endswith',
|
"istartswith",
|
||||||
'year', 'month', 'day', 'week_day', 'hour', 'minute', 'second',
|
"iendswith",
|
||||||
'isnull', 'in']
|
"contains",
|
||||||
|
"startswith",
|
||||||
|
"endswith",
|
||||||
|
"year",
|
||||||
|
"month",
|
||||||
|
"day",
|
||||||
|
"week_day",
|
||||||
|
"hour",
|
||||||
|
"minute",
|
||||||
|
"second",
|
||||||
|
"isnull",
|
||||||
|
"in",
|
||||||
|
]
|
||||||
|
|
||||||
op_map = {
|
op_map = {
|
||||||
'lte': '<=',
|
"lte": "<=",
|
||||||
'gte': '>=',
|
"gte": ">=",
|
||||||
'lt': '<',
|
"lt": "<",
|
||||||
'gt': '>',
|
"gt": ">",
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -122,7 +137,9 @@ class Q(QMixin):
|
|||||||
for arg in args:
|
for arg in args:
|
||||||
self.conditions[arg] = None
|
self.conditions[arg] = None
|
||||||
|
|
||||||
def __repr__(self,):
|
def __repr__(
|
||||||
|
self,
|
||||||
|
):
|
||||||
return self._compile()
|
return self._compile()
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
@@ -132,13 +149,13 @@ class Q(QMixin):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def date_format(self):
|
def date_format(self):
|
||||||
if self._mode == 'SQL_SERVER':
|
if self._mode == "SQL_SERVER":
|
||||||
return "%Y-%d-%m"
|
return "%Y-%d-%m"
|
||||||
return "%Y-%m-%d"
|
return "%Y-%m-%d"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def datetime_format(self):
|
def datetime_format(self):
|
||||||
if self._mode == 'SQL_SERVER':
|
if self._mode == "SQL_SERVER":
|
||||||
return "%Y-%d-%m %H:%M:%S"
|
return "%Y-%d-%m %H:%M:%S"
|
||||||
return "%Y-%m-%d %H:%M:%S"
|
return "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
@@ -155,7 +172,11 @@ class Q(QMixin):
|
|||||||
if isinstance(value, list) or isinstance(value, set) or is_map(value):
|
if isinstance(value, list) or isinstance(value, set) or is_map(value):
|
||||||
return ", ".join([self._get_value(item) for item in value])
|
return ", ".join([self._get_value(item) for item in value])
|
||||||
|
|
||||||
if isinstance(value, F) or isinstance(value, QMixin) or isinstance(value, SQLQuery):
|
if (
|
||||||
|
isinstance(value, F)
|
||||||
|
or isinstance(value, QMixin)
|
||||||
|
or isinstance(value, SQLQuery)
|
||||||
|
):
|
||||||
return ensureUtf(value)
|
return ensureUtf(value)
|
||||||
|
|
||||||
return "'%s'" % value
|
return "'%s'" % value
|
||||||
@@ -163,7 +184,7 @@ class Q(QMixin):
|
|||||||
def _process(self, compose_column, value):
|
def _process(self, compose_column, value):
|
||||||
arr = compose_column.split("__")
|
arr = compose_column.split("__")
|
||||||
column = arr.pop(0)
|
column = arr.pop(0)
|
||||||
if column == '':
|
if column == "":
|
||||||
column += "__" + arr.pop(0)
|
column += "__" + arr.pop(0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -193,28 +214,34 @@ class Q(QMixin):
|
|||||||
if lookup == "in":
|
if lookup == "in":
|
||||||
return "{0} in ({1})".format(column, self._get_value(value))
|
return "{0} in ({1})".format(column, self._get_value(value))
|
||||||
|
|
||||||
if lookup == 'isnull':
|
if lookup == "isnull":
|
||||||
op = ""
|
op = ""
|
||||||
if not value:
|
if not value:
|
||||||
op = "NOT "
|
op = "NOT "
|
||||||
return "{0} is {1}NULL".format(column, op)
|
return "{0} is {1}NULL".format(column, op)
|
||||||
|
|
||||||
if lookup in ['year', 'month', 'day', 'hour', 'minute', 'second']:
|
if lookup in ["year", "month", "day", "hour", "minute", "second"]:
|
||||||
if arr:
|
if arr:
|
||||||
column = "DATEPART({0}, {1})__{2}".format(lookup, column, arr.pop(0))
|
column = "DATEPART({0}, {1})__{2}".format(
|
||||||
|
lookup, column, arr.pop(0)
|
||||||
|
)
|
||||||
return self._process(column, value)
|
return self._process(column, value)
|
||||||
else:
|
else:
|
||||||
return "DATEPART({0}, {1})={2}".format(lookup, column, value)
|
return "DATEPART({0}, {1})={2}".format(lookup, column, value)
|
||||||
|
|
||||||
if lookup in self.op_map.keys():
|
if lookup in self.op_map.keys():
|
||||||
return "{0}{1}{2}".format(column, self.op_map[lookup], self._get_value(value))
|
return "{0}{1}{2}".format(
|
||||||
|
column, self.op_map[lookup], self._get_value(value)
|
||||||
|
)
|
||||||
|
|
||||||
if value is not None:
|
if value is not None:
|
||||||
return "{0}{1}{2}".format(column, "=", self._get_value(value))
|
return "{0}{1}{2}".format(column, "=", self._get_value(value))
|
||||||
|
|
||||||
return column
|
return column
|
||||||
|
|
||||||
def _compile(self,):
|
def _compile(
|
||||||
|
self,
|
||||||
|
):
|
||||||
filters = []
|
filters = []
|
||||||
for k, v in self.conditions.items():
|
for k, v in self.conditions.items():
|
||||||
filters.append(self._process(k, v))
|
filters.append(self._process(k, v))
|
||||||
@@ -226,7 +253,6 @@ class Q(QMixin):
|
|||||||
|
|
||||||
|
|
||||||
class SQLQuery(object):
|
class SQLQuery(object):
|
||||||
|
|
||||||
def __init__(self, table=None, sql_mode="MYSQL", sql=None, **kwargs):
|
def __init__(self, table=None, sql_mode="MYSQL", sql=None, **kwargs):
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
self._table = table
|
self._table = table
|
||||||
@@ -241,11 +267,19 @@ class SQLQuery(object):
|
|||||||
self._limits = None
|
self._limits = None
|
||||||
self._sql = sql
|
self._sql = sql
|
||||||
self._nolock = False
|
self._nolock = False
|
||||||
|
self._distinct = False
|
||||||
|
|
||||||
def has_filters(self,):
|
def has_filters(self):
|
||||||
return self._order_by or self._group_by or self._joins\
|
return (
|
||||||
or self._filters or self._excludes or self._extra \
|
self._order_by
|
||||||
or self._limits or self._values != ['*']
|
or self._group_by
|
||||||
|
or self._joins
|
||||||
|
or self._filters
|
||||||
|
or self._excludes
|
||||||
|
or self._extra
|
||||||
|
or self._limits
|
||||||
|
or self._values != ["*"]
|
||||||
|
)
|
||||||
|
|
||||||
def _q(self, *args, **kwargs):
|
def _q(self, *args, **kwargs):
|
||||||
conds = Q()
|
conds = Q()
|
||||||
@@ -259,7 +293,7 @@ class SQLQuery(object):
|
|||||||
_conds._mode = self.sql_mode
|
_conds._mode = self.sql_mode
|
||||||
return conds & _conds
|
return conds & _conds
|
||||||
|
|
||||||
def _clone(self,):
|
def _clone(self):
|
||||||
return copy.deepcopy(self)
|
return copy.deepcopy(self)
|
||||||
|
|
||||||
def values(self, *args):
|
def values(self, *args):
|
||||||
@@ -277,6 +311,11 @@ class SQLQuery(object):
|
|||||||
clone._filters &= self._q(*args, **kwargs)
|
clone._filters &= self._q(*args, **kwargs)
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
|
def distinct(self, enabled=True):
|
||||||
|
clone = self._clone()
|
||||||
|
clone._distinct = enabled
|
||||||
|
return clone
|
||||||
|
|
||||||
def exclude(self, *args, **kwargs):
|
def exclude(self, *args, **kwargs):
|
||||||
clone = self._clone()
|
clone = self._clone()
|
||||||
clone._excludes &= self._q(*args, **kwargs)
|
clone._excludes &= self._q(*args, **kwargs)
|
||||||
@@ -299,7 +338,9 @@ class SQLQuery(object):
|
|||||||
clone = self._clone()
|
clone = self._clone()
|
||||||
if on:
|
if on:
|
||||||
on = "ON " + on.format(table=self._table)
|
on = "ON " + on.format(table=self._table)
|
||||||
clone._joins.append("{how} {table} {on}".format(how=how, table=table, on=on))
|
clone._joins.append(
|
||||||
|
"{how} {table} {on}".format(how=how, table=table, on=on)
|
||||||
|
)
|
||||||
return clone
|
return clone
|
||||||
|
|
||||||
def extra(self, extra=None, **kwargs):
|
def extra(self, extra=None, **kwargs):
|
||||||
@@ -317,21 +358,22 @@ class SQLQuery(object):
|
|||||||
|
|
||||||
|
|
||||||
class SQLCompiler(object):
|
class SQLCompiler(object):
|
||||||
|
def get_columns(self):
|
||||||
def get_columns(self,):
|
|
||||||
extra_columns = self.get_extra_columns()
|
extra_columns = self.get_extra_columns()
|
||||||
columns = ", ".join(self._values)
|
columns = ", ".join(self._values)
|
||||||
return ", ".join([item for item in [columns, extra_columns] if item])
|
return ", ".join([item for item in [columns, extra_columns] if item])
|
||||||
|
|
||||||
def get_extra_columns(self,):
|
def get_extra_columns(self):
|
||||||
return self._extra.get("select", "")
|
return self._extra.get("select", "")
|
||||||
|
|
||||||
def get_extra_where(self,):
|
def get_extra_where(self):
|
||||||
where = self._extra.get("where", [])
|
where = self._extra.get("where", [])
|
||||||
if where:
|
if where:
|
||||||
return " AND ".join(where)
|
return " AND ".join(where)
|
||||||
|
|
||||||
def get_table(self,):
|
def get_table(
|
||||||
|
self,
|
||||||
|
):
|
||||||
return self._table
|
return self._table
|
||||||
|
|
||||||
def get_where(self):
|
def get_where(self):
|
||||||
@@ -339,9 +381,13 @@ class SQLCompiler(object):
|
|||||||
extra_where = self.get_extra_where()
|
extra_where = self.get_extra_where()
|
||||||
|
|
||||||
if filters or extra_where:
|
if filters or extra_where:
|
||||||
return "WHERE " + " AND ".join([item for item in [filters, extra_where] if item])
|
return "WHERE " + " AND ".join(
|
||||||
|
[item for item in [filters, extra_where] if item]
|
||||||
|
)
|
||||||
|
|
||||||
def get_order_by(self,):
|
def get_order_by(
|
||||||
|
self,
|
||||||
|
):
|
||||||
conds = []
|
conds = []
|
||||||
for cond in self._order_by:
|
for cond in self._order_by:
|
||||||
order = ""
|
order = ""
|
||||||
@@ -361,20 +407,22 @@ class SQLCompiler(object):
|
|||||||
if conds:
|
if conds:
|
||||||
return "ORDER BY " + ", ".join(conds)
|
return "ORDER BY " + ", ".join(conds)
|
||||||
|
|
||||||
def get_group_by(self,):
|
def get_group_by(
|
||||||
|
self,
|
||||||
|
):
|
||||||
if self._group_by:
|
if self._group_by:
|
||||||
return "GROUP BY " + ", ".join(self._group_by)
|
return "GROUP BY " + ", ".join(self._group_by)
|
||||||
|
|
||||||
def get_joins(self,):
|
def get_joins(self):
|
||||||
if self._joins:
|
if self._joins:
|
||||||
return " ".join(self._joins)
|
return " ".join(self._joins)
|
||||||
|
|
||||||
def get_nolock(self,):
|
def get_nolock(self):
|
||||||
if self._nolock:
|
if self._nolock:
|
||||||
return " WITH (NOLOCK)"
|
return " WITH (NOLOCK)"
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def get_limits(self,):
|
def get_limits(self):
|
||||||
if self._limits and self.sql_mode != "SQL_SERVER":
|
if self._limits and self.sql_mode != "SQL_SERVER":
|
||||||
offset = self._limits.start
|
offset = self._limits.start
|
||||||
limit = self._limits.stop
|
limit = self._limits.stop
|
||||||
@@ -385,7 +433,12 @@ class SQLCompiler(object):
|
|||||||
str += " OFFSET {0}".format(offset)
|
str += " OFFSET {0}".format(offset)
|
||||||
return str
|
return str
|
||||||
|
|
||||||
def get_top(self,):
|
def get_distinct(self):
|
||||||
|
if self._distinct:
|
||||||
|
return " DISTINCT "
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def get_top(self):
|
||||||
if self._limits and self.sql_mode == "SQL_SERVER" and not self._limits.start:
|
if self._limits and self.sql_mode == "SQL_SERVER" and not self._limits.start:
|
||||||
return "TOP {0}".format(self._limits.stop)
|
return "TOP {0}".format(self._limits.stop)
|
||||||
|
|
||||||
@@ -397,15 +450,27 @@ class SQLCompiler(object):
|
|||||||
else:
|
else:
|
||||||
table = self.get_table()
|
table = self.get_table()
|
||||||
|
|
||||||
sql = ["SELECT", self.get_top(), self.get_columns(),
|
sql = [
|
||||||
"FROM", table,
|
"SELECT",
|
||||||
self.get_nolock(),
|
self.get_distinct(),
|
||||||
self.get_joins(), self.get_where(),
|
self.get_top(),
|
||||||
self.get_group_by(), self.get_order_by(),
|
self.get_columns(),
|
||||||
self.get_limits()]
|
"FROM",
|
||||||
|
table,
|
||||||
|
self.get_nolock(),
|
||||||
|
self.get_joins(),
|
||||||
|
self.get_where(),
|
||||||
|
self.get_group_by(),
|
||||||
|
self.get_order_by(),
|
||||||
|
self.get_limits(),
|
||||||
|
]
|
||||||
|
|
||||||
if self.sql_mode == "SQL_SERVER" and self._limits and \
|
if (
|
||||||
self._limits.start is not None and self._limits.stop is not None:
|
self.sql_mode == "SQL_SERVER"
|
||||||
|
and self._limits
|
||||||
|
and self._limits.start is not None
|
||||||
|
and self._limits.stop is not None
|
||||||
|
):
|
||||||
conds = []
|
conds = []
|
||||||
if self._limits.start is not None:
|
if self._limits.start is not None:
|
||||||
conds.append("row_number > %s" % self._limits.start)
|
conds.append("row_number > %s" % self._limits.start)
|
||||||
@@ -416,12 +481,19 @@ class SQLCompiler(object):
|
|||||||
conds = " AND ".join(conds)
|
conds = " AND ".join(conds)
|
||||||
paginate = "ROW_NUMBER() OVER (%s) as row_number" % self.get_order_by()
|
paginate = "ROW_NUMBER() OVER (%s) as row_number" % self.get_order_by()
|
||||||
|
|
||||||
return ["SELECT * FROM (", "SELECT", ",".join([paginate, self.get_columns()]),
|
return [
|
||||||
"FROM", table,
|
"SELECT * FROM (",
|
||||||
self.get_joins(),
|
"SELECT",
|
||||||
self.get_where(),
|
",".join([paginate, self.get_columns()]),
|
||||||
self.get_group_by(),
|
"FROM",
|
||||||
self.get_limits(), ") as tbl_paginated WHERE ", conds]
|
table,
|
||||||
|
self.get_joins(),
|
||||||
|
self.get_where(),
|
||||||
|
self.get_group_by(),
|
||||||
|
self.get_limits(),
|
||||||
|
") as tbl_paginated WHERE ",
|
||||||
|
conds,
|
||||||
|
]
|
||||||
|
|
||||||
return sql
|
return sql
|
||||||
|
|
||||||
@@ -434,7 +506,7 @@ class SQLCompiler(object):
|
|||||||
__str__ = __repr__
|
__str__ = __repr__
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sql(self,):
|
def sql(self):
|
||||||
return self.__str__()
|
return self.__str__()
|
||||||
|
|
||||||
def __or__(self, other):
|
def __or__(self, other):
|
||||||
@@ -446,7 +518,6 @@ class Queryset(SQLCompiler, SQLQuery):
|
|||||||
|
|
||||||
|
|
||||||
class SQLModel(object):
|
class SQLModel(object):
|
||||||
|
|
||||||
@classproperty
|
@classproperty
|
||||||
def objects(cls):
|
def objects(cls):
|
||||||
return Queryset(cls.table, getattr(cls, 'sql_mode', None))
|
return Queryset(cls.table, getattr(cls, "sql_mode", None))
|
||||||
|
|||||||
Reference in New Issue
Block a user