Improve grid filters for datetime fields.
Hopefully this makes these filters more intuitive, by allowing user to provide a date value but interpret in a datetime context.
This commit is contained in:
parent
68f7c418d6
commit
cd461aef51
|
@ -100,12 +100,14 @@ class AlchemyGrid(Grid):
|
|||
factory = filters.AlchemyNumericFilter
|
||||
elif isinstance(column.type, sa.Boolean):
|
||||
factory = filters.AlchemyBooleanFilter
|
||||
elif isinstance(column.type, (sa.Date, sa.DateTime)):
|
||||
elif isinstance(column.type, sa.Date):
|
||||
factory = filters.AlchemyDateFilter
|
||||
elif isinstance(column.type, sa.DateTime):
|
||||
factory = filters.AlchemyDateTimeFilter
|
||||
elif isinstance(column.type, GPCType):
|
||||
factory = filters.AlchemyGPCFilter
|
||||
factory = kwargs.pop('factory', factory)
|
||||
return factory(key, column=column, **kwargs)
|
||||
return factory(key, column=column, config=self.request.rattail_config, **kwargs)
|
||||
|
||||
def iter_filters(self):
|
||||
"""
|
||||
|
|
|
@ -26,6 +26,9 @@ Grid Filters
|
|||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
from edbob.util import prettify
|
||||
|
@ -33,12 +36,16 @@ from edbob.util import prettify
|
|||
from rattail.gpc import GPC
|
||||
from rattail.util import OrderedDict
|
||||
from rattail.core import UNSPECIFIED
|
||||
from rattail.time import localtime, make_utc
|
||||
|
||||
from pyramid_simpleform import Form
|
||||
from pyramid_simpleform.renderers import FormRenderer
|
||||
from webhelpers.html import HTML, tags
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FilterValueRenderer(object):
|
||||
"""
|
||||
Base class for all filter renderers.
|
||||
|
@ -350,6 +357,17 @@ class AlchemyDateFilter(AlchemyGridFilter):
|
|||
"""
|
||||
value_renderer_factory = DateValueRenderer
|
||||
|
||||
verb_labels = {
|
||||
'equal': "on",
|
||||
'not_equal': "not on",
|
||||
'greater_than': "after",
|
||||
'greater_equal': "on or after",
|
||||
'less_than': "before",
|
||||
'less_equal': "on or before",
|
||||
'is_null': "is null",
|
||||
'is_not_null': "is not null",
|
||||
}
|
||||
|
||||
def default_verbs(self):
|
||||
"""
|
||||
Expose greater-than / less-than verbs in addition to core.
|
||||
|
@ -357,17 +375,106 @@ class AlchemyDateFilter(AlchemyGridFilter):
|
|||
return ['equal', 'not_equal', 'greater_than', 'greater_equal',
|
||||
'less_than', 'less_equal', 'is_null', 'is_not_null']
|
||||
|
||||
def filter_is_true(self, query, value):
|
||||
def make_date(self, value):
|
||||
"""
|
||||
Filter data with an "is true" query (alias for "is not null").
|
||||
Convert user input to a proper ``datetime.date`` object.
|
||||
"""
|
||||
return self.filter_is_not_null(query, value)
|
||||
if value:
|
||||
try:
|
||||
dt = datetime.datetime.strptime(value, '%Y-%m-%d')
|
||||
except ValueError:
|
||||
log.warning("invalid date value: {}".format(value))
|
||||
else:
|
||||
return dt.date()
|
||||
|
||||
def filter_is_false(self, query, value):
|
||||
|
||||
class AlchemyDateTimeFilter(AlchemyDateFilter):
|
||||
"""
|
||||
Filter data with an "is false" query (alias for "is null").
|
||||
SQLAlchemy filter for datetime values.
|
||||
"""
|
||||
return self.filter_is_null(query, value)
|
||||
|
||||
def filter_equal(self, query, value):
|
||||
"""
|
||||
Find all dateimes which fall on the given date.
|
||||
"""
|
||||
date = self.make_date(value)
|
||||
if not date:
|
||||
return query
|
||||
|
||||
start = datetime.datetime.combine(date, datetime.time(0))
|
||||
start = make_utc(localtime(self.config, start))
|
||||
|
||||
stop = datetime.datetime.combine(date + datetime.timedelta(days=1), datetime.time(0))
|
||||
stop = make_utc(localtime(self.config, stop))
|
||||
|
||||
return query.filter(self.column >= start)\
|
||||
.filter(self.column < stop)
|
||||
|
||||
def filter_not_equal(self, query, value):
|
||||
"""
|
||||
Find all dateimes which do *not* fall on the given date.
|
||||
"""
|
||||
date = self.make_date(value)
|
||||
if not date:
|
||||
return query
|
||||
|
||||
start = datetime.datetime.combine(date, datetime.time(0))
|
||||
start = make_utc(localtime(self.config, start))
|
||||
|
||||
stop = datetime.datetime.combine(date + datetime.timedelta(days=1), datetime.time(0))
|
||||
stop = make_utc(localtime(self.config, stop))
|
||||
|
||||
return query.filter(sa.or_(
|
||||
self.column < start,
|
||||
self.column <= stop))
|
||||
|
||||
def filter_greater_than(self, query, value):
|
||||
"""
|
||||
Find all datetimes which fall after the given date.
|
||||
"""
|
||||
date = self.make_date(value)
|
||||
if not date:
|
||||
return query
|
||||
|
||||
time = datetime.datetime.combine(date + datetime.timedelta(days=1), datetime.time(0))
|
||||
time = make_utc(localtime(self.config, time))
|
||||
return query.filter(self.column >= time)
|
||||
|
||||
def filter_greater_equal(self, query, value):
|
||||
"""
|
||||
Find all datetimes which fall on or after the given date.
|
||||
"""
|
||||
date = self.make_date(value)
|
||||
if not date:
|
||||
return query
|
||||
|
||||
time = datetime.datetime.combine(date, datetime.time(0))
|
||||
time = make_utc(localtime(self.config, time))
|
||||
return query.filter(self.column >= time)
|
||||
|
||||
def filter_less_than(self, query, value):
|
||||
"""
|
||||
Find all datetimes which fall before the given date.
|
||||
"""
|
||||
date = self.make_date(value)
|
||||
if not date:
|
||||
return query
|
||||
|
||||
time = datetime.datetime.combine(date, datetime.time(0))
|
||||
time = make_utc(localtime(self.config, time))
|
||||
return query.filter(self.column < time)
|
||||
|
||||
def filter_less_equal(self, query, value):
|
||||
"""
|
||||
Find all datetimes which fall on or before the given date.
|
||||
"""
|
||||
date = self.make_date(value)
|
||||
if not date:
|
||||
return query
|
||||
|
||||
time = datetime.datetime.combine(date + datetime.timedelta(days=1), datetime.time(0))
|
||||
time = make_utc(localtime(self.config, time))
|
||||
return query.filter(self.column < time)
|
||||
|
||||
|
||||
class AlchemyGPCFilter(AlchemyGridFilter):
|
||||
|
|
Loading…
Reference in a new issue