Commit 5e46f3fa authored by Paul Brown's avatar Paul Brown

fix mongoengine and peewee exceptions when filtering for noninteger values

parent 0eff8c1e
...@@ -132,7 +132,55 @@ class BooleanNotEqualFilter(FilterNotEqual, filters.BaseBooleanFilter): ...@@ -132,7 +132,55 @@ class BooleanNotEqualFilter(FilterNotEqual, filters.BaseBooleanFilter):
def apply(self, query, value): def apply(self, query, value):
flt = {'%s' % self.column.name: value != '1'} flt = {'%s' % self.column.name: value != '1'}
return query.filter(**flt) return query.filter(**flt)
class IntEqualFilter(FilterEqual, filters.BaseIntFilter):
pass
class IntNotEqualFilter(FilterNotEqual, filters.BaseIntFilter):
pass
class IntGreaterFilter(FilterGreater, filters.BaseIntFilter):
pass
class IntSmallerFilter(FilterSmaller, filters.BaseIntFilter):
pass
class IntInListFilter(FilterInList, filters.BaseIntListFilter):
pass
class IntNotInListFilter(FilterNotInList, filters.BaseIntListFilter):
pass
class FloatEqualFilter(FilterEqual, filters.BaseFloatFilter):
pass
class FloatNotEqualFilter(FilterNotEqual, filters.BaseFloatFilter):
pass
class FloatGreaterFilter(FilterGreater, filters.BaseFloatFilter):
pass
class FloatSmallerFilter(FilterSmaller, filters.BaseFloatFilter):
pass
class FloatInListFilter(FilterInList, filters.BaseFloatListFilter):
pass
class FloatNotInListFilter(FilterNotInList, filters.BaseFloatListFilter):
pass
class DateTimeEqualFilter(FilterEqual, filters.BaseDateTimeFilter): class DateTimeEqualFilter(FilterEqual, filters.BaseDateTimeFilter):
pass pass
...@@ -150,31 +198,18 @@ class DateTimeSmallerFilter(FilterSmaller, filters.BaseDateTimeFilter): ...@@ -150,31 +198,18 @@ class DateTimeSmallerFilter(FilterSmaller, filters.BaseDateTimeFilter):
pass pass
class DateTimeBetweenFilter(BaseMongoEngineFilter): class DateTimeBetweenFilter(BaseMongoEngineFilter, filters.BaseDateTimeBetweenFilter):
def __init__(self, column, name, options=None, data_type=None): def __init__(self, column, name, options=None, data_type=None):
super(DateTimeBetweenFilter, self).__init__(column, name, options, data_type='datetimerangepicker') super(DateTimeBetweenFilter, self).__init__(column,
name,
def clean(self, value): options,
return [datetime.datetime.strptime(range, '%Y-%m-%d %H:%M:%S') for range in value.split(' to ')] data_type='datetimerangepicker')
def apply(self, query, value): def apply(self, query, value):
start, end = value start, end = value
flt = {'%s__gte' % self.column.name: start, '%s__lte' % self.column.name: end} flt = {'%s__gte' % self.column.name: start, '%s__lte' % self.column.name: end}
return query.filter(**flt) return query.filter(**flt)
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
value = [datetime.datetime.strptime(range, '%Y-%m-%d %H:%M:%S') for range in value.split(' to ')]
if (len(value) == 2) and (value[0] <= value[1]):
return True
else:
return False
except ValueError:
return False
class DateTimeNotBetweenFilter(DateTimeBetweenFilter): class DateTimeNotBetweenFilter(DateTimeBetweenFilter):
def apply(self, query, value): def apply(self, query, value):
...@@ -188,12 +223,19 @@ class DateTimeNotBetweenFilter(DateTimeBetweenFilter): ...@@ -188,12 +223,19 @@ class DateTimeNotBetweenFilter(DateTimeBetweenFilter):
# Base peewee filter field converter # Base peewee filter field converter
class FilterConverter(filters.BaseFilterConverter): class FilterConverter(filters.BaseFilterConverter):
strings = (FilterEqual, FilterNotEqual, FilterLike, FilterNotLike, FilterEmpty, FilterInList, FilterNotInList) strings = (FilterEqual, FilterNotEqual, FilterLike, FilterNotLike,
numeric = (FilterEqual, FilterNotEqual, FilterGreater, FilterSmaller, FilterEmpty, FilterInList, FilterNotInList) FilterEmpty, FilterInList, FilterNotInList)
bool = (BooleanEqualFilter, BooleanNotEqualFilter) int_filters = (IntEqualFilter, IntNotEqualFilter, IntGreaterFilter,
datetime_filters = (DateTimeEqualFilter, DateTimeNotEqualFilter, DateTimeGreaterFilter, IntSmallerFilter, FilterEmpty, IntInListFilter,
DateTimeSmallerFilter, DateTimeBetweenFilter, DateTimeNotBetweenFilter, IntNotInListFilter)
FilterEmpty) float_filters = (FloatEqualFilter, FloatNotEqualFilter, FloatGreaterFilter,
FloatSmallerFilter, FilterEmpty, FloatInListFilter,
FloatNotInListFilter)
bool_filters = (BooleanEqualFilter, BooleanNotEqualFilter)
datetime_filters = (DateTimeEqualFilter, DateTimeNotEqualFilter,
DateTimeGreaterFilter, DateTimeSmallerFilter,
DateTimeBetweenFilter, DateTimeNotBetweenFilter,
FilterEmpty)
def convert(self, type_name, column, name): def convert(self, type_name, column, name):
if type_name in self.converters: if type_name in self.converters:
...@@ -207,12 +249,16 @@ class FilterConverter(filters.BaseFilterConverter): ...@@ -207,12 +249,16 @@ class FilterConverter(filters.BaseFilterConverter):
@filters.convert('BooleanField') @filters.convert('BooleanField')
def conv_bool(self, column, name): def conv_bool(self, column, name):
return [f(column, name) for f in self.bool] return [f(column, name) for f in self.bool_filters]
@filters.convert('IntField', 'DecimalField', 'FloatField', 'LongField') @filters.convert('IntField', 'LongField')
def conv_int(self, column, name): def conv_int(self, column, name):
return [f(column, name) for f in self.numeric] return [f(column, name) for f in self.int_filters]
@filters.convert('DecimalField', 'FloatField')
def conv_float(self, column, name):
return [f(column, name) for f in self.float_filters]
@filters.convert('DateTimeField', 'ComplexDateTimeField') @filters.convert('DateTimeField', 'ComplexDateTimeField')
def conv_datetime(self, column, name): def conv_datetime(self, column, name):
return [f(column, name) for f in self.datetime_filters] return [f(column, name) for f in self.datetime_filters]
...@@ -123,6 +123,54 @@ class BooleanNotEqualFilter(FilterNotEqual, filters.BaseBooleanFilter): ...@@ -123,6 +123,54 @@ class BooleanNotEqualFilter(FilterNotEqual, filters.BaseBooleanFilter):
pass pass
class IntEqualFilter(FilterEqual, filters.BaseIntFilter):
pass
class IntNotEqualFilter(FilterNotEqual, filters.BaseIntFilter):
pass
class IntGreaterFilter(FilterGreater, filters.BaseIntFilter):
pass
class IntSmallerFilter(FilterSmaller, filters.BaseIntFilter):
pass
class IntInListFilter(FilterInList, filters.BaseIntListFilter):
pass
class IntNotInListFilter(FilterNotInList, filters.BaseIntListFilter):
pass
class FloatEqualFilter(FilterEqual, filters.BaseFloatFilter):
pass
class FloatNotEqualFilter(FilterNotEqual, filters.BaseFloatFilter):
pass
class FloatGreaterFilter(FilterGreater, filters.BaseFloatFilter):
pass
class FloatSmallerFilter(FilterSmaller, filters.BaseFloatFilter):
pass
class FloatInListFilter(FilterInList, filters.BaseFloatListFilter):
pass
class FloatNotInListFilter(FilterNotInList, filters.BaseFloatListFilter):
pass
class DateEqualFilter(FilterEqual, filters.BaseDateFilter): class DateEqualFilter(FilterEqual, filters.BaseDateFilter):
pass pass
...@@ -139,31 +187,16 @@ class DateSmallerFilter(FilterSmaller, filters.BaseDateFilter): ...@@ -139,31 +187,16 @@ class DateSmallerFilter(FilterSmaller, filters.BaseDateFilter):
pass pass
class DateBetweenFilter(BasePeeweeFilter): class DateBetweenFilter(BasePeeweeFilter, filters.BaseDateBetweenFilter):
def __init__(self, column, name, options=None, data_type=None): def __init__(self, column, name, options=None, data_type=None):
super(DateBetweenFilter, self).__init__(column, name, options, data_type='daterangepicker') super(DateBetweenFilter, self).__init__(column,
name,
def clean(self, value): options,
return [datetime.datetime.strptime(range, '%Y-%m-%d') for range in value.split(' to ')] data_type='daterangepicker')
def apply(self, query, value): def apply(self, query, value):
start, end = value start, end = value
return query.filter(self.column.between(start, end)) return query.filter(self.column.between(start, end))
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
value = [datetime.datetime.strptime(range, '%Y-%m-%d') for range in value.split(' to ')]
# if " to " is missing, fail validation
# if end date is before start date, fail validation
if (len(value) == 2) and (value[0] <= value[1]):
return True
else:
return False
except ValueError:
return False
class DateNotBetweenFilter(DateBetweenFilter): class DateNotBetweenFilter(DateBetweenFilter):
...@@ -191,29 +224,16 @@ class DateTimeSmallerFilter(FilterSmaller, filters.BaseDateTimeFilter): ...@@ -191,29 +224,16 @@ class DateTimeSmallerFilter(FilterSmaller, filters.BaseDateTimeFilter):
pass pass
class DateTimeBetweenFilter(BasePeeweeFilter): class DateTimeBetweenFilter(BasePeeweeFilter, filters.BaseDateTimeBetweenFilter):
def __init__(self, column, name, options=None, data_type=None): def __init__(self, column, name, options=None, data_type=None):
super(DateTimeBetweenFilter, self).__init__(column, name, options, data_type='datetimerangepicker') super(DateTimeBetweenFilter, self).__init__(column,
name,
def clean(self, value): options,
return [datetime.datetime.strptime(range, '%Y-%m-%d %H:%M:%S') for range in value.split(' to ')] data_type='datetimerangepicker')
def apply(self, query, value): def apply(self, query, value):
start, end = value start, end = value
return query.filter(self.column.between(start, end)) return query.filter(self.column.between(start, end))
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
value = [datetime.datetime.strptime(range, '%Y-%m-%d %H:%M:%S') for range in value.split(' to ')]
if (len(value) == 2) and (value[0] <= value[1]):
return True
else:
return False
except ValueError:
return False
class DateTimeNotBetweenFilter(DateTimeBetweenFilter): class DateTimeNotBetweenFilter(DateTimeBetweenFilter):
...@@ -241,36 +261,16 @@ class TimeSmallerFilter(FilterSmaller, filters.BaseTimeFilter): ...@@ -241,36 +261,16 @@ class TimeSmallerFilter(FilterSmaller, filters.BaseTimeFilter):
pass pass
class TimeBetweenFilter(BasePeeweeFilter): class TimeBetweenFilter(BasePeeweeFilter, filters.BaseTimeBetweenFilter):
def __init__(self, column, name, options=None, data_type=None): def __init__(self, column, name, options=None, data_type=None):
super(TimeBetweenFilter, self).__init__(column, name, options, data_type='timerangepicker') super(TimeBetweenFilter, self).__init__(column,
name,
def clean(self, value): options,
timetuples = [time.strptime(range, '%H:%M:%S') data_type='timerangepicker')
for range in value.split(' to ')]
return [datetime.time(timetuple.tm_hour,
timetuple.tm_min,
timetuple.tm_sec)
for timetuple in timetuples]
def apply(self, query, value): def apply(self, query, value):
start, end = value start, end = value
return query.filter(self.column.between(start, end)) return query.filter(self.column.between(start, end))
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
timetuples = [time.strptime(range, '%H:%M:%S')
for range in value.split(' to ')]
if (len(timetuples) == 2) and (timetuples[0] <= timetuples[1]):
return True
else:
return False
except ValueError:
raise
return False
class TimeNotBetweenFilter(TimeBetweenFilter): class TimeNotBetweenFilter(TimeBetweenFilter):
...@@ -284,16 +284,25 @@ class TimeNotBetweenFilter(TimeBetweenFilter): ...@@ -284,16 +284,25 @@ class TimeNotBetweenFilter(TimeBetweenFilter):
# Base peewee filter field converter # Base peewee filter field converter
class FilterConverter(filters.BaseFilterConverter): class FilterConverter(filters.BaseFilterConverter):
strings = (FilterEqual, FilterNotEqual, FilterLike, FilterNotLike, FilterEmpty, FilterInList, FilterNotInList) strings = (FilterEqual, FilterNotEqual, FilterLike, FilterNotLike,
numeric = (FilterEqual, FilterNotEqual, FilterGreater, FilterSmaller, FilterEmpty, FilterInList, FilterNotInList) FilterEmpty, FilterInList, FilterNotInList)
bool = (BooleanEqualFilter, BooleanNotEqualFilter) int_filters = (IntEqualFilter, IntNotEqualFilter, IntGreaterFilter,
date_filters = (DateEqualFilter, DateNotEqualFilter, DateGreaterFilter, DateSmallerFilter, IntSmallerFilter, FilterEmpty, IntInListFilter,
DateBetweenFilter, DateNotBetweenFilter, FilterEmpty) IntNotInListFilter)
datetime_filters = (DateTimeEqualFilter, DateTimeNotEqualFilter, DateTimeGreaterFilter, float_filters = (FloatEqualFilter, FloatNotEqualFilter, FloatGreaterFilter,
DateTimeSmallerFilter, DateTimeBetweenFilter, DateTimeNotBetweenFilter, FloatSmallerFilter, FilterEmpty, FloatInListFilter,
FilterEmpty) FloatNotInListFilter)
time_filters = (TimeEqualFilter, TimeNotEqualFilter, TimeGreaterFilter, TimeSmallerFilter, bool_filters = (BooleanEqualFilter, BooleanNotEqualFilter)
TimeBetweenFilter, TimeNotBetweenFilter, FilterEmpty) date_filters = (DateEqualFilter, DateNotEqualFilter, DateGreaterFilter,
DateSmallerFilter, DateBetweenFilter, DateNotBetweenFilter,
FilterEmpty)
datetime_filters = (DateTimeEqualFilter, DateTimeNotEqualFilter,
DateTimeGreaterFilter, DateTimeSmallerFilter,
DateTimeBetweenFilter, DateTimeNotBetweenFilter,
FilterEmpty)
time_filters = (TimeEqualFilter, TimeNotEqualFilter, TimeGreaterFilter,
TimeSmallerFilter, TimeBetweenFilter, TimeNotBetweenFilter,
FilterEmpty)
def convert(self, type_name, column, name): def convert(self, type_name, column, name):
if type_name in self.converters: if type_name in self.converters:
...@@ -307,13 +316,16 @@ class FilterConverter(filters.BaseFilterConverter): ...@@ -307,13 +316,16 @@ class FilterConverter(filters.BaseFilterConverter):
@filters.convert('BooleanField') @filters.convert('BooleanField')
def conv_bool(self, column, name): def conv_bool(self, column, name):
return [f(column, name) for f in self.bool] return [f(column, name) for f in self.bool_filters]
@filters.convert('IntegerField', 'DecimalField', 'FloatField', @filters.convert('IntegerField', 'BigIntegerField')
'DoubleField', 'BigIntegerField')
def conv_int(self, column, name): def conv_int(self, column, name):
return [f(column, name) for f in self.numeric] return [f(column, name) for f in self.int_filters]
@filters.convert('DecimalField', 'FloatField', 'DoubleField')
def conv_float(self, column, name):
return [f(column, name) for f in self.float_filters]
@filters.convert('DateField') @filters.convert('DateField')
def conv_date(self, column, name): def conv_date(self, column, name):
return [f(column, name) for f in self.date_filters] return [f(column, name) for f in self.date_filters]
......
...@@ -123,6 +123,54 @@ class BooleanNotEqualFilter(FilterNotEqual, filters.BaseBooleanFilter): ...@@ -123,6 +123,54 @@ class BooleanNotEqualFilter(FilterNotEqual, filters.BaseBooleanFilter):
pass pass
class IntEqualFilter(FilterEqual, filters.BaseIntFilter):
pass
class IntNotEqualFilter(FilterNotEqual, filters.BaseIntFilter):
pass
class IntGreaterFilter(FilterGreater, filters.BaseIntFilter):
pass
class IntSmallerFilter(FilterSmaller, filters.BaseIntFilter):
pass
class IntInListFilter(FilterInList, filters.BaseIntListFilter):
pass
class IntNotInListFilter(FilterNotInList, filters.BaseIntListFilter):
pass
class FloatEqualFilter(FilterEqual, filters.BaseFloatFilter):
pass
class FloatNotEqualFilter(FilterNotEqual, filters.BaseFloatFilter):
pass
class FloatGreaterFilter(FilterGreater, filters.BaseFloatFilter):
pass
class FloatSmallerFilter(FilterSmaller, filters.BaseFloatFilter):
pass
class FloatInListFilter(FilterInList, filters.BaseFloatListFilter):
pass
class FloatNotInListFilter(FilterNotInList, filters.BaseFloatListFilter):
pass
class DateEqualFilter(FilterEqual, filters.BaseDateFilter): class DateEqualFilter(FilterEqual, filters.BaseDateFilter):
pass pass
...@@ -139,31 +187,16 @@ class DateSmallerFilter(FilterSmaller, filters.BaseDateFilter): ...@@ -139,31 +187,16 @@ class DateSmallerFilter(FilterSmaller, filters.BaseDateFilter):
pass pass
class DateBetweenFilter(BaseSQLAFilter): class DateBetweenFilter(BaseSQLAFilter, filters.BaseDateBetweenFilter):
def __init__(self, column, name, options=None, data_type=None): def __init__(self, column, name, options=None, data_type=None):
super(DateBetweenFilter, self).__init__(column, name, options, data_type='daterangepicker') super(DateBetweenFilter, self).__init__(column,
name,
def clean(self, value): options,
return [datetime.datetime.strptime(range, '%Y-%m-%d') for range in value.split(' to ')] data_type='daterangepicker')
def apply(self, query, value): def apply(self, query, value):
start, end = value start, end = value
return query.filter(self.column.between(start, end)) return query.filter(self.column.between(start, end))
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
value = [datetime.datetime.strptime(range, '%Y-%m-%d') for range in value.split(' to ')]
# if " to " is missing, fail validation
# sqlalchemy's .between() will not work if end date is before start date
if (len(value) == 2) and (value[0] <= value[1]):
return True
else:
return False
except ValueError:
return False
class DateNotBetweenFilter(DateBetweenFilter): class DateNotBetweenFilter(DateBetweenFilter):
...@@ -192,29 +225,16 @@ class DateTimeSmallerFilter(FilterSmaller, filters.BaseDateTimeFilter): ...@@ -192,29 +225,16 @@ class DateTimeSmallerFilter(FilterSmaller, filters.BaseDateTimeFilter):
pass pass
class DateTimeBetweenFilter(BaseSQLAFilter): class DateTimeBetweenFilter(BaseSQLAFilter, filters.BaseDateTimeBetweenFilter):
def __init__(self, column, name, options=None, data_type=None): def __init__(self, column, name, options=None, data_type=None):
super(DateTimeBetweenFilter, self).__init__(column, name, options, data_type='datetimerangepicker') super(DateTimeBetweenFilter, self).__init__(column,
name,
def clean(self, value): options,
return [datetime.datetime.strptime(range, '%Y-%m-%d %H:%M:%S') for range in value.split(' to ')] data_type='datetimerangepicker')
def apply(self, query, value): def apply(self, query, value):
start, end = value start, end = value
return query.filter(self.column.between(start, end)) return query.filter(self.column.between(start, end))
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
value = [datetime.datetime.strptime(range, '%Y-%m-%d %H:%M:%S') for range in value.split(' to ')]
if (len(value) == 2) and (value[0] <= value[1]):
return True
else:
return False
except ValueError:
return False
class DateTimeNotBetweenFilter(DateTimeBetweenFilter): class DateTimeNotBetweenFilter(DateTimeBetweenFilter):
...@@ -242,36 +262,16 @@ class TimeSmallerFilter(FilterSmaller, filters.BaseTimeFilter): ...@@ -242,36 +262,16 @@ class TimeSmallerFilter(FilterSmaller, filters.BaseTimeFilter):
pass pass
class TimeBetweenFilter(BaseSQLAFilter): class TimeBetweenFilter(BaseSQLAFilter, filters.BaseTimeBetweenFilter):
def __init__(self, column, name, options=None, data_type=None): def __init__(self, column, name, options=None, data_type=None):
super(TimeBetweenFilter, self).__init__(column, name, options, data_type='timerangepicker') super(TimeBetweenFilter, self).__init__(column,
name,
def clean(self, value): options,
timetuples = [time.strptime(range, '%H:%M:%S') data_type='timerangepicker')
for range in value.split(' to ')]
return [datetime.time(timetuple.tm_hour,
timetuple.tm_min,
timetuple.tm_sec)
for timetuple in timetuples]
def apply(self, query, value): def apply(self, query, value):
start, end = value start, end = value
return query.filter(self.column.between(start, end)) return query.filter(self.column.between(start, end))
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
timetuples = [time.strptime(range, '%H:%M:%S')
for range in value.split(' to ')]
if (len(timetuples) == 2) and (timetuples[0] <= timetuples[1]):
return True
else:
return False
except ValueError:
raise
return False
class TimeNotBetweenFilter(TimeBetweenFilter): class TimeNotBetweenFilter(TimeBetweenFilter):
...@@ -285,17 +285,27 @@ class TimeNotBetweenFilter(TimeBetweenFilter): ...@@ -285,17 +285,27 @@ class TimeNotBetweenFilter(TimeBetweenFilter):
# Base SQLA filter field converter # Base SQLA filter field converter
class FilterConverter(filters.BaseFilterConverter): class FilterConverter(filters.BaseFilterConverter):
strings = (FilterEqual, FilterNotEqual, FilterLike, FilterNotLike, FilterEmpty, FilterInList, FilterNotInList) strings = (FilterEqual, FilterNotEqual, FilterLike, FilterNotLike,
numeric = (FilterEqual, FilterNotEqual, FilterGreater, FilterSmaller, FilterEmpty, FilterInList, FilterNotInList) FilterEmpty, FilterInList, FilterNotInList)
bool = (BooleanEqualFilter, BooleanNotEqualFilter) int_filters = (IntEqualFilter, IntNotEqualFilter, IntGreaterFilter,
enum = (FilterEqual, FilterNotEqual, FilterEmpty, FilterInList, FilterNotInList) IntSmallerFilter, FilterEmpty, IntInListFilter,
date_filters = (DateEqualFilter, DateNotEqualFilter, DateGreaterFilter, DateSmallerFilter, IntNotInListFilter)
DateBetweenFilter, DateNotBetweenFilter, FilterEmpty) float_filters = (FloatEqualFilter, FloatNotEqualFilter, FloatGreaterFilter,
datetime_filters = (DateTimeEqualFilter, DateTimeNotEqualFilter, DateTimeGreaterFilter, FloatSmallerFilter, FilterEmpty, FloatInListFilter,
DateTimeSmallerFilter, DateTimeBetweenFilter, DateTimeNotBetweenFilter, FloatNotInListFilter)
FilterEmpty) bool_filters = (BooleanEqualFilter, BooleanNotEqualFilter)
time_filters = (TimeEqualFilter, TimeNotEqualFilter, TimeGreaterFilter, TimeSmallerFilter, enum = (FilterEqual, FilterNotEqual, FilterEmpty, FilterInList,
TimeBetweenFilter, TimeNotBetweenFilter, FilterEmpty) FilterNotInList)
date_filters = (DateEqualFilter, DateNotEqualFilter, DateGreaterFilter,
DateSmallerFilter, DateBetweenFilter, DateNotBetweenFilter,
FilterEmpty)
datetime_filters = (DateTimeEqualFilter, DateTimeNotEqualFilter,
DateTimeGreaterFilter, DateTimeSmallerFilter,
DateTimeBetweenFilter, DateTimeNotBetweenFilter,
FilterEmpty)
time_filters = (TimeEqualFilter, TimeNotEqualFilter, TimeGreaterFilter,
TimeSmallerFilter, TimeBetweenFilter, TimeNotBetweenFilter,
FilterEmpty)
def convert(self, type_name, column, name, **kwargs): def convert(self, type_name, column, name, **kwargs):
if type_name.lower() in self.converters: if type_name.lower() in self.converters:
...@@ -310,13 +320,16 @@ class FilterConverter(filters.BaseFilterConverter): ...@@ -310,13 +320,16 @@ class FilterConverter(filters.BaseFilterConverter):
@filters.convert('boolean', 'tinyint') @filters.convert('boolean', 'tinyint')
def conv_bool(self, column, name, **kwargs): def conv_bool(self, column, name, **kwargs):
return [f(column, name, **kwargs) for f in self.bool] return [f(column, name, **kwargs) for f in self.bool_filters]
@filters.convert('int', 'integer', 'smallinteger', 'smallint', 'numeric', @filters.convert('int', 'integer', 'smallinteger', 'smallint', 'numeric',
'float', 'real', 'biginteger', 'bigint', 'decimal', 'biginteger', 'bigint', 'mediumint')
'double_precision', 'double', 'mediumint')
def conv_int(self, column, name, **kwargs): def conv_int(self, column, name, **kwargs):
return [f(column, name, **kwargs) for f in self.numeric] return [f(column, name, **kwargs) for f in self.int_filters]
@filters.convert('float', 'real', 'decimal', 'double_precision', 'double')
def conv_float(self, column, name, **kwargs):
return [f(column, name, **kwargs) for f in self.float_filters]
@filters.convert('date') @filters.convert('date')
def conv_date(self, column, name, **kwargs): def conv_date(self, column, name, **kwargs):
......
...@@ -102,7 +102,39 @@ class BaseBooleanFilter(BaseFilter): ...@@ -102,7 +102,39 @@ class BaseBooleanFilter(BaseFilter):
def validate(self, value): def validate(self, value):
return value in ('0', '1') return value in ('0', '1')
class BaseIntFilter(BaseFilter):
"""
Base Int filter. Adds validation and changes value to python int.
"""
def clean(self, value):
return int(float(value))
class BaseFloatFilter(BaseFilter):
"""
Base Float filter. Adds validation and changes value to python float.
"""
def clean(self, value):
return float(value)
class BaseIntListFilter(BaseFilter):
"""
Base Integer list filter. Adds validation for int "In List" filter.
"""
def clean(self, value):
return [int(float(v.strip())) for v in value.split(',') if v.strip()]
class BaseFloatListFilter(BaseFilter):
"""
Base Float list filter. Adds validation for float "In List" filter.
"""
def clean(self, value):
return [float(v.strip()) for v in value.split(',') if v.strip()]
class BaseDateFilter(BaseFilter): class BaseDateFilter(BaseFilter):
""" """
...@@ -115,6 +147,32 @@ class BaseDateFilter(BaseFilter): ...@@ -115,6 +147,32 @@ class BaseDateFilter(BaseFilter):
def clean(self, value): def clean(self, value):
return datetime.datetime.strptime(value, '%Y-%m-%d').date() return datetime.datetime.strptime(value, '%Y-%m-%d').date()
class BaseDateBetweenFilter(BaseFilter):
"""
Base Date Between filter. Consolidates logic for validation and clean.
Apply method is different for each back-end.
"""
def clean(self, value):
return [datetime.datetime.strptime(range, '%Y-%m-%d')
for range in value.split(' to ')]
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
value = [datetime.datetime.strptime(range, '%Y-%m-%d')
for range in value.split(' to ')]
# if " to " is missing, fail validation
# sqlalchemy's .between() will not work if end date is before start date
if (len(value) == 2) and (value[0] <= value[1]):
return True
else:
return False
except ValueError:
return False
class BaseDateTimeFilter(BaseFilter): class BaseDateTimeFilter(BaseFilter):
...@@ -130,7 +188,31 @@ class BaseDateTimeFilter(BaseFilter): ...@@ -130,7 +188,31 @@ class BaseDateTimeFilter(BaseFilter):
# datetime filters will not work in SQLite + SQLAlchemy if value not converted to datetime # datetime filters will not work in SQLite + SQLAlchemy if value not converted to datetime
return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S') return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
class BaseDateTimeBetweenFilter(BaseFilter):
"""
Base DateTime Between filter. Consolidates logic for validation and clean.
Apply method is different for each back-end.
"""
def clean(self, value):
return [datetime.datetime.strptime(range, '%Y-%m-%d %H:%M:%S')
for range in value.split(' to ')]
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
value = [datetime.datetime.strptime(range, '%Y-%m-%d %H:%M:%S')
for range in value.split(' to ')]
if (len(value) == 2) and (value[0] <= value[1]):
return True
else:
return False
except ValueError:
return False
class BaseTimeFilter(BaseFilter): class BaseTimeFilter(BaseFilter):
""" """
Base Time filter. Uses client-side time picker control. Base Time filter. Uses client-side time picker control.
...@@ -148,6 +230,35 @@ class BaseTimeFilter(BaseFilter): ...@@ -148,6 +230,35 @@ class BaseTimeFilter(BaseFilter):
timetuple.tm_sec) timetuple.tm_sec)
class BaseTimeBetweenFilter(BaseFilter):
"""
Base Time Between filter. Consolidates logic for validation and clean.
Apply method is different for each back-end.
"""
def clean(self, value):
timetuples = [time.strptime(range, '%H:%M:%S')
for range in value.split(' to ')]
return [datetime.time(timetuple.tm_hour,
timetuple.tm_min,
timetuple.tm_sec)
for timetuple in timetuples]
def operation(self):
return lazy_gettext('between')
def validate(self, value):
try:
timetuples = [time.strptime(range, '%H:%M:%S')
for range in value.split(' to ')]
if (len(timetuples) == 2) and (timetuples[0] <= timetuples[1]):
return True
else:
return False
except ValueError:
raise
return False
def convert(*args): def convert(*args):
""" """
Decorator for field to filter conversion routine. Decorator for field to filter conversion routine.
......
...@@ -41,6 +41,7 @@ def create_models(db): ...@@ -41,6 +41,7 @@ def create_models(db):
class Model2(db.Document): class Model2(db.Document):
string_field = db.StringField() string_field = db.StringField()
int_field = db.IntField() int_field = db.IntField()
float_field = db.FloatField()
bool_field = db.BooleanField() bool_field = db.BooleanField()
model1 = db.ReferenceField(Model1) model1 = db.ReferenceField(Model1)
...@@ -135,10 +136,10 @@ def test_column_filters(): ...@@ -135,10 +136,10 @@ def test_column_filters():
Model1('test1_val_4', 'test2_val_4').save() Model1('test1_val_4', 'test2_val_4').save()
Model1(None, 'empty_obj').save() Model1(None, 'empty_obj').save()
Model2('string_field_val_1', None).save() Model2('string_field_val_1', None, None).save()
Model2('string_field_val_2', None).save() Model2('string_field_val_2', None, None).save()
Model2('string_field_val_3', 5000).save() Model2('string_field_val_3', 5000, 25.9).save()
Model2('string_field_val_4', 9000).save() Model2('string_field_val_4', 9000, 75.5).save()
Model1('datetime_obj1', datetime_field=datetime(2014,4,3,1,9,0)).save() Model1('datetime_obj1', datetime_field=datetime(2014,4,3,1,9,0)).save()
Model1('datetime_obj2', datetime_field=datetime(2013,3,2,0,8,0)).save() Model1('datetime_obj2', datetime_field=datetime(2013,3,2,0,8,0)).save()
...@@ -304,6 +305,86 @@ def test_column_filters(): ...@@ -304,6 +305,86 @@ def test_column_filters():
ok_('string_field_val_3' not in data) ok_('string_field_val_3' not in data)
ok_('string_field_val_4' not in data) ok_('string_field_val_4' not in data)
# Test float filter
view = CustomModelView(Model2, column_filters=['float_field'],
endpoint="_float")
admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Float Field']],
[
(0, 'equals'),
(1, 'not equal'),
(2, 'greater than'),
(3, 'smaller than'),
(4, 'empty'),
(5, 'in list'),
(6, 'not in list'),
])
# float - equals
rv = client.get('/admin/_float/?flt0_0=25.9')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('string_field_val_3' in data)
ok_('string_field_val_4' not in data)
# float - not equal
rv = client.get('/admin/_float/?flt0_1=25.9')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('string_field_val_3' not in data)
ok_('string_field_val_4' in data)
# float - greater
rv = client.get('/admin/_float/?flt0_2=60.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('string_field_val_3' not in data)
ok_('string_field_val_4' in data)
# float - smaller
rv = client.get('/admin/_float/?flt0_3=60.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('string_field_val_3' in data)
ok_('string_field_val_4' not in data)
# float - empty
rv = client.get('/admin/_float/?flt0_4=1')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('string_field_val_1' in data)
ok_('string_field_val_2' in data)
ok_('string_field_val_3' not in data)
ok_('string_field_val_4' not in data)
# float - not empty
rv = client.get('/admin/_float/?flt0_4=0')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('string_field_val_1' not in data)
ok_('string_field_val_2' not in data)
ok_('string_field_val_3' in data)
ok_('string_field_val_4' in data)
# float - in list
rv = client.get('/admin/_float/?flt0_5=25.9%2C75.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('string_field_val_1' not in data)
ok_('string_field_val_2' not in data)
ok_('string_field_val_3' in data)
ok_('string_field_val_4' in data)
# float - not in list
rv = client.get('/admin/_float/?flt0_6=25.9%2C75.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('string_field_val_1' in data)
ok_('string_field_val_2' in data)
ok_('string_field_val_3' not in data)
ok_('string_field_val_4' not in data)
# Test datetime filter # Test datetime filter
view = CustomModelView(Model1, view = CustomModelView(Model1,
column_filters=['datetime_field'], column_filters=['datetime_field'],
......
...@@ -62,15 +62,18 @@ def create_models(db): ...@@ -62,15 +62,18 @@ def create_models(db):
return self.test1 return self.test1
class Model2(BaseModel): class Model2(BaseModel):
def __init__(self, char_field=None, int_field=None, bool_field=0): def __init__(self, char_field=None, int_field=None, float_field=None,
bool_field=0):
super(Model2, self).__init__() super(Model2, self).__init__()
self.char_field = char_field self.char_field = char_field
self.int_field = int_field self.int_field = int_field
self.float_field = float_field
self.bool_field = bool_field self.bool_field = bool_field
char_field = peewee.CharField(max_length=20) char_field = peewee.CharField(max_length=20)
int_field = peewee.IntegerField(null=True) int_field = peewee.IntegerField(null=True)
float_field = peewee.FloatField(null=True)
bool_field = peewee.BooleanField() bool_field = peewee.BooleanField()
Model1.create_table() Model1.create_table()
...@@ -162,10 +165,10 @@ def test_column_filters(): ...@@ -162,10 +165,10 @@ def test_column_filters():
Model1('test1_val_4', 'test2_val_4').save() Model1('test1_val_4', 'test2_val_4').save()
Model1(None, 'empty_obj').save() Model1(None, 'empty_obj').save()
Model2('char_field_val_1', None).save() Model2('char_field_val_1', None, None).save()
Model2('char_field_val_2', None).save() Model2('char_field_val_2', None, None).save()
Model2('char_field_val_3', 5000).save() Model2('char_field_val_3', 5000, 25.9).save()
Model2('char_field_val_4', 9000).save() Model2('char_field_val_4', 9000, 75.5).save()
Model1('date_obj1', date_field=date(2014,11,17)).save() Model1('date_obj1', date_field=date(2014,11,17)).save()
Model1('date_obj2', date_field=date(2013,10,16)).save() Model1('date_obj2', date_field=date(2013,10,16)).save()
...@@ -256,7 +259,7 @@ def test_column_filters(): ...@@ -256,7 +259,7 @@ def test_column_filters():
ok_('test1_val_3' in data) ok_('test1_val_3' in data)
ok_('test1_val_4' in data) ok_('test1_val_4' in data)
# Test numeric filter # Test int filter
view = CustomModelView(Model2, column_filters=['int_field']) view = CustomModelView(Model2, column_filters=['int_field'])
admin.add_view(view) admin.add_view(view)
...@@ -335,6 +338,86 @@ def test_column_filters(): ...@@ -335,6 +338,86 @@ def test_column_filters():
ok_('char_field_val_3' not in data) ok_('char_field_val_3' not in data)
ok_('char_field_val_4' not in data) ok_('char_field_val_4' not in data)
# Test float filter
view = CustomModelView(Model2, column_filters=['float_field'],
endpoint="_float")
admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Float Field']],
[
(0, 'equals'),
(1, 'not equal'),
(2, 'greater than'),
(3, 'smaller than'),
(4, 'empty'),
(5, 'in list'),
(6, 'not in list'),
])
# float - equals
rv = client.get('/admin/_float/?flt0_0=25.9')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('char_field_val_3' in data)
ok_('char_field_val_4' not in data)
# float - not equal
rv = client.get('/admin/_float/?flt0_1=25.9')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('char_field_val_3' not in data)
ok_('char_field_val_4' in data)
# float - greater
rv = client.get('/admin/_float/?flt0_2=60.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('char_field_val_3' not in data)
ok_('char_field_val_4' in data)
# float - smaller
rv = client.get('/admin/_float/?flt0_3=60.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('char_field_val_3' in data)
ok_('char_field_val_4' not in data)
# float - empty
rv = client.get('/admin/_float/?flt0_4=1')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('char_field_val_1' in data)
ok_('char_field_val_2' in data)
ok_('char_field_val_3' not in data)
ok_('char_field_val_4' not in data)
# float - not empty
rv = client.get('/admin/_float/?flt0_4=0')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('char_field_val_1' not in data)
ok_('char_field_val_2' not in data)
ok_('char_field_val_3' in data)
ok_('char_field_val_4' in data)
# float - in list
rv = client.get('/admin/_float/?flt0_5=25.9%2C75.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('char_field_val_1' not in data)
ok_('char_field_val_2' not in data)
ok_('char_field_val_3' in data)
ok_('char_field_val_4' in data)
# float - not in list
rv = client.get('/admin/_float/?flt0_6=25.9%2C75.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('char_field_val_1' in data)
ok_('char_field_val_2' in data)
ok_('char_field_val_3' not in data)
ok_('char_field_val_4' not in data)
# Test date, time, and datetime filters # Test date, time, and datetime filters
view = CustomModelView(Model1, view = CustomModelView(Model1,
column_filters=['date_field', 'datetime_field', 'timeonly_field'], column_filters=['date_field', 'datetime_field', 'timeonly_field'],
......
...@@ -57,17 +57,20 @@ def create_models(db): ...@@ -57,17 +57,20 @@ def create_models(db):
return self.test1 return self.test1
class Model2(db.Model): class Model2(db.Model):
def __init__(self, string_field=None, int_field=None, bool_field=None, model1=None): def __init__(self, string_field=None, int_field=None, bool_field=None,
model1=None, float_field=None):
self.string_field = string_field self.string_field = string_field
self.int_field = int_field self.int_field = int_field
self.bool_field = bool_field self.bool_field = bool_field
self.model1 = model1 self.model1 = model1
self.float_field = float_field
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
string_field = db.Column(db.String) string_field = db.Column(db.String)
int_field = db.Column(db.Integer) int_field = db.Column(db.Integer)
bool_field = db.Column(db.Boolean) bool_field = db.Column(db.Boolean)
enum_field = db.Column(db.Enum('model2_v1', 'model2_v2'), nullable=True) enum_field = db.Column(db.Enum('model2_v1', 'model2_v2'), nullable=True)
float_field = db.Column(db.Float)
# Relation # Relation
model1_id = db.Column(db.Integer, db.ForeignKey(Model1.id)) model1_id = db.Column(db.Integer, db.ForeignKey(Model1.id))
...@@ -381,10 +384,10 @@ def test_column_filters(): ...@@ -381,10 +384,10 @@ def test_column_filters():
model1_obj3 = Model1('test1_val_3', 'test2_val_3') model1_obj3 = Model1('test1_val_3', 'test2_val_3')
model1_obj4 = Model1('test1_val_4', 'test2_val_4') model1_obj4 = Model1('test1_val_4', 'test2_val_4')
model2_obj1 = Model2('test2_val_1', model1=model1_obj1) model2_obj1 = Model2('test2_val_1', model1=model1_obj1, float_field=None)
model2_obj2 = Model2('test2_val_2', model1=model1_obj1) model2_obj2 = Model2('test2_val_2', model1=model1_obj1, float_field=None)
model2_obj3 = Model2('test2_val_3', int_field=5000) model2_obj3 = Model2('test2_val_3', int_field=5000, float_field=25.9)
model2_obj4 = Model2('test2_val_4', int_field=9000) model2_obj4 = Model2('test2_val_4', int_field=9000, float_field=75.5)
date_obj1 = Model1('date_obj1', date_field=date(2014,11,17)) date_obj1 = Model1('date_obj1', date_field=date(2014,11,17))
date_obj2 = Model1('date_obj2', date_field=date(2013,10,16)) date_obj2 = Model1('date_obj2', date_field=date(2013,10,16))
...@@ -501,7 +504,7 @@ def test_column_filters(): ...@@ -501,7 +504,7 @@ def test_column_filters():
ok_('test1_val_3' in data) ok_('test1_val_3' in data)
ok_('test1_val_4' in data) ok_('test1_val_4' in data)
# Test numeric filter # Test integer filter
view = CustomModelView(Model2, db.session, view = CustomModelView(Model2, db.session,
column_filters=['int_field']) column_filters=['int_field'])
admin.add_view(view) admin.add_view(view)
...@@ -579,7 +582,87 @@ def test_column_filters(): ...@@ -579,7 +582,87 @@ def test_column_filters():
ok_('test2_val_1' in data) ok_('test2_val_1' in data)
ok_('test2_val_2' in data) ok_('test2_val_2' in data)
ok_('test2_val_3' not in data) ok_('test2_val_3' not in data)
ok_('test2_val_4' not in data) ok_('test2_val_4' not in data)
# Test float filter
view = CustomModelView(Model2, db.session, column_filters=['float_field'],
endpoint="_float")
admin.add_view(view)
eq_([(f['index'], f['operation']) for f in view._filter_groups[u'Float Field']],
[
(0, 'equals'),
(1, 'not equal'),
(2, 'greater than'),
(3, 'smaller than'),
(4, 'empty'),
(5, 'in list'),
(6, 'not in list'),
])
# float - equals
rv = client.get('/admin/_float/?flt0_0=25.9')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('test2_val_3' in data)
ok_('test2_val_4' not in data)
# float - not equal
rv = client.get('/admin/_float/?flt0_1=25.9')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('test2_val_3' not in data)
ok_('test2_val_4' in data)
# float - greater
rv = client.get('/admin/_float/?flt0_2=60.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('test2_val_3' not in data)
ok_('test2_val_4' in data)
# float - smaller
rv = client.get('/admin/_float/?flt0_3=60.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('test2_val_3' in data)
ok_('test2_val_4' not in data)
# float - empty
rv = client.get('/admin/_float/?flt0_4=1')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('test2_val_1' in data)
ok_('test2_val_2' in data)
ok_('test2_val_3' not in data)
ok_('test2_val_4' not in data)
# float - not empty
rv = client.get('/admin/_float/?flt0_4=0')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('test2_val_1' not in data)
ok_('test2_val_2' not in data)
ok_('test2_val_3' in data)
ok_('test2_val_4' in data)
# float - in list
rv = client.get('/admin/_float/?flt0_5=25.9%2C75.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('test2_val_1' not in data)
ok_('test2_val_2' not in data)
ok_('test2_val_3' in data)
ok_('test2_val_4' in data)
# float - not in list
rv = client.get('/admin/_float/?flt0_6=25.9%2C75.5')
eq_(rv.status_code, 200)
data = rv.data.decode('utf-8')
ok_('test2_val_1' in data)
ok_('test2_val_2' in data)
ok_('test2_val_3' not in data)
ok_('test2_val_4' not in data)
# Test filters to joined table field # Test filters to joined table field
view = CustomModelView( view = CustomModelView(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment