general: add filtering methods to lazy querysets (#43328)

This commit is contained in:
Frédéric Péters 2020-06-28 08:51:38 +02:00
parent 981528a0e6
commit 7087f4a061
3 changed files with 100 additions and 1 deletions

View File

@ -883,6 +883,57 @@ def test_lazy_formdata_queryset_distance(pub, variable_test_data):
assert len(nearby) == 0
def test_lazy_formdata_queryset_filter(pub, variable_test_data):
lazy_formdata = variable_test_data
formdef = lazy_formdata._formdef
formdef.store()
data_class = lazy_formdata._formdef.data_class()
for i in range(6):
formdata = data_class()
formdata.data = {'0': 'bar'}
formdata.just_created()
formdata.store()
for i in range(4):
formdata = data_class()
formdata.data = {'0': 'foo'}
formdata.just_created()
formdata.jump_status('finished')
formdata.store()
formdata = data_class()
formdata.data = {'0': 'bar'}
formdata.status = 'draft'
formdata.store()
# filter function
queryset = lazy_formdata.objects.filter_by('foo_foo').apply_filter_value('bar')
assert queryset.count == 7
queryset = lazy_formdata.objects.filter_by('foo_foo').apply_filter_value('foo')
assert queryset.count == 4
queryset = lazy_formdata.objects.filter_by('foo_foo').apply_filter_value('X')
assert queryset.count == 0
# filter using attribute name
queryset = lazy_formdata.objects.filter_by_foo_foo().apply_filter_value('bar')
assert queryset.count == 7
# filter + exclude current formdata
queryset = lazy_formdata.objects.exclude_self().filter_by('foo_foo').apply_filter_value('bar')
assert queryset.count == 6
queryset = lazy_formdata.objects.exclude_self().filter_by('foo_foo').apply_filter_value('foo')
assert queryset.count == 4
# template tags
context = pub.substitutions.get_context_variables(mode='lazy')
tmpl = Template('{{form_objects|filter_by:"foo_foo"|filter_value:"bar"|count}}')
assert tmpl.render(context) == '7'
pub.substitutions.feed(formdata)
tmpl = Template('{{form_objects|filter_by:"foo_foo"|filter_value:form_var_foo_foo|count}}')
assert tmpl.render(context) == '7'
def test_lazy_variables(pub, variable_test_data):
formdata = FormDef.select()[0].data_class().select()[0]
for mode in (None, 'lazy'):

View File

@ -518,9 +518,30 @@ def distance_filter(queryset, distance=1000):
@register.filter
def order_by(queryset, attribute):
if hasattr(attribute, 'get_value'):
attribute = attribute.get_value() # unlazy
return queryset.order_by(attribute)
@register.filter
def filter_by(queryset, attribute):
if hasattr(attribute, 'get_value'):
attribute = attribute.get_value() # unlazy
return queryset.filter_by(attribute)
@register.filter
def filter_value(queryset, value):
if hasattr(value, 'get_value'):
value = value.get_value() # unlazy
return queryset.apply_filter_value(value)
@register.filter
def count(queryset):
return queryset.count
@register.filter
def reproj(coords, projection_name):
proj = pyproj.Proj(init='EPSG:4326')

View File

@ -74,6 +74,10 @@ class LazyFormDefObjectsManager(object):
user = get_request().user
return self._clone(self._criterias + [Equal('user_id', str(user.id) if user else '-1')])
def exclude_self(self):
assert self._formdata
return self._clone(self._criterias + [NotEqual('id', str(self._formdata.id))])
def drafts(self):
criterias = [x for x in self._criterias if not getattr(x, 'exclude_drafts', False)]
return self._clone(criterias + [Equal('status', 'draft')])
@ -97,12 +101,31 @@ class LazyFormDefObjectsManager(object):
return bool(obj._distance < distance)
return self._clone(self._criterias + [distance_check])
def filter_by(self, attribute):
qs = self._clone(self._criterias)
qs.pending_attr = attribute
return qs
def apply_filter_value(self, value):
assert self.pending_attr
for field in self._formdef.fields:
if getattr(field, 'varname', None) == self.pending_attr:
from wcs import sql
criteria = Equal(sql.get_field_id(field), value)
break
else:
raise Exception('invalid filter')
return self._clone(self._criterias + [criteria])
def __getattr__(self, attribute):
# backward compatibility
if attribute.startswith('count_status_'):
# backward compatibility
status = attribute[len('count_status_'):]
return len(self._formdef.data_class().get_ids_with_indexed_value(
'status', 'wf-%s' % status))
if attribute.startswith('filter_by_'):
attribute_name = attribute[len('filter_by_'):]
return lambda: self.filter_by(attribute_name)
if attribute == 'formdef':
warnings.warn('Deprecated access to formdef', DeprecationWarning)
return self._formdef
@ -421,6 +444,10 @@ class LazyFormData(LazyFormDef):
# this gets used to generate an email attachment :/
return self._formdata.export_to_json(include_files=include_files)
def get(self, key):
# compatibility with |get filter, to return a field by varname
return getattr(self.var, key, None)
def __getitem__(self, key):
try:
return getattr(self, key)