templatetags: add |getlistdict filter (#63559)

This commit is contained in:
Valentin Deniaud 2022-04-21 16:41:26 +02:00
parent f6fd194b70
commit 204d176571
4 changed files with 121 additions and 0 deletions

View File

@ -1571,6 +1571,47 @@ def test_lazy_formdata_queryset_filter(pub, variable_test_data):
assert tmpl.render(context) == '\n OK\n '
assert 'not a date' not in LazyFormData(formdata).objects.getlist('datefield')
# test |getlistdict
tmpl = Template('{{ form_objects|order_by:"id"|getlistdict:"foo_foo" }}', autoescape=False)
assert tmpl.render(context) == str(
[
{'foo_foo': 'bar'},
{'foo_foo': 'bar'},
{'foo_foo': 'bar'},
{'foo_foo': 'bar'},
{'foo_foo': 'bar'},
{'foo_foo': 'bar'},
{'foo_foo': 'bar'},
{'foo_foo': 'foo'},
{'foo_foo': 'foo'},
{'foo_foo': 'foo'},
{'foo_foo': 'foo'},
]
)
tmpl = Template(
'{{ form_objects|order_by:"id"|getlistdict:"foo_foo:test, boolfield, unknown" }}', autoescape=False
)
assert tmpl.render(context) == str(
[
{'test': 'bar', 'boolfield': False, 'unknown': None},
{'test': 'bar', 'boolfield': True, 'unknown': None},
{'test': 'bar', 'boolfield': True, 'unknown': None},
{'test': 'bar', 'boolfield': True, 'unknown': None},
{'test': 'bar', 'boolfield': True, 'unknown': None},
{'test': 'bar', 'boolfield': True, 'unknown': None},
{'test': 'bar', 'boolfield': True, 'unknown': None},
{'test': 'foo', 'boolfield': False, 'unknown': None},
{'test': 'foo', 'boolfield': False, 'unknown': None},
{'test': 'foo', 'boolfield': False, 'unknown': None},
{'test': 'foo', 'boolfield': False, 'unknown': None},
]
)
tmpl = Template(
'{{ form_objects|order_by:"id"|getlistdict:"datefield"|first|get:"datefield"|date }}',
autoescape=False,
)
assert tmpl.render(context) == '2018-07-31'
def test_lazy_formdata_queryset_filter_non_unique_varname(pub, variable_test_data):
lazy_formdata = variable_test_data
@ -3325,6 +3366,12 @@ def test_block_variables(pub):
tmpl = Template('{{ form_var_block|getlist:"foo"|sum }} {{ form_var_block|getlist:"bar"|sum }}')
assert tmpl.render(context) == '9 2'
tmpl = Template('{{ form_var_block|getlistdict:"foo:test, bar, unknown" }}', autoescape=False)
assert (
tmpl.render(context)
== "[{'test': '2', 'bar': '2', 'unknown': None}, {'test': '7', 'bar': 'bla', 'unknown': None}]"
)
# check another count of elements
formdata.data = {
'1': {
@ -3449,6 +3496,9 @@ def test_items_field_getlist(pub):
tmpl = Template('{% for x in form_var_items2field|getlist:"text" %}{{x}},{% endfor %}')
assert tmpl.render(context) == 'un,trois,'
tmpl = Template('{{ form_var_items2field|getlistdict:"text, unknown" }}', autoescape=False)
assert tmpl.render(context) == "[{'text': 'un', 'unknown': None}, {'text': 'trois', 'unknown': None}]"
def test_getlist_of_lazyformdata_field(pub):
CardDef.wipe()

View File

@ -1218,6 +1218,29 @@ def test_getlist():
assert tmpl.render({'egg': 42}) == '0'
def test_getlistdict():
class FakeBlock:
def getlistdict(self, keys):
data = [
{'foo': 'foo1', 'bar': 'bar1'},
{'foo': 'foo2', 'bar': 'bar2'},
]
return [{k: v for k, v in d.items() if k in keys} for d in data]
tmpl = Template('{{ egg|getlistdict:coin }}', autoescape=False)
assert tmpl.render({'egg': FakeBlock(), 'coin': 'foo'}) == "[{'foo': 'foo1'}, {'foo': 'foo2'}]"
assert (
tmpl.render({'egg': FakeBlock(), 'coin': 'bar : test, foo:hop, ,,'})
== "[{'hop': 'foo1', 'test': 'bar1'}, {'hop': 'foo2', 'test': 'bar2'}]"
)
tmpl = Template('{{ egg|getlistdict:"foo"|length }}')
assert tmpl.render({'egg': FakeBlock()}) == '2'
assert tmpl.render({}) == '0'
assert tmpl.render({'egg': None}) == '0'
assert tmpl.render({'egg': 'spam'}) == '0'
assert tmpl.render({'egg': 42}) == '0'
def test_django_contrib_humanize_filters():
tmpl = Template('{{ foo|intcomma }}')
assert tmpl.render({'foo': 10000}) == '10,000'

View File

@ -85,6 +85,25 @@ def getlist(mapping, key):
return mapping.getlist(key)
@register.filter
def getlistdict(mapping, keys):
if mapping is None or not hasattr(mapping, 'getlistdict'):
return []
parsed_keys = {}
for key in unlazy(keys).split(','):
if not key.strip():
continue
try:
name, new_name = key.split(':', 1)
except ValueError:
name = new_name = key
parsed_keys[name.strip()] = new_name.strip()
results = mapping.getlistdict(parsed_keys.keys())
return [{parsed_keys[k]: v for k, v in result.items()} for result in results]
@register.filter
def startswith(string, substring):
return string and force_text(string).startswith(force_text(substring))

View File

@ -248,6 +248,20 @@ class LazyFormDefObjectsManager:
def getlist(self, key):
return LazyList(self, key)
def getlistdict(self, keys):
results = []
for lazy_formdata in self:
result = {}
for key in keys:
value = lazy_formdata.get(key)
if hasattr(value, 'timetuple'):
value = value.timetuple()
elif hasattr(value, 'get_value'):
value = value.get_value()
result[key] = value
results.append(result)
return results
def _populate_cache(self):
if self._cached_resultset is not None:
return
@ -1113,6 +1127,9 @@ class LazyFieldVarItems(LazyFieldVarStructured):
return self.raw or []
return []
def getlistdict(self, keys):
return [{key: str(x.get(key, '')) or None for key in keys} for x in self.structured or []]
def __contains__(self, value):
return str(value) in self.getlist('id') or (self.structured and str(value) in self.getlist('text'))
@ -1213,6 +1230,18 @@ class LazyFieldVarBlock(LazyFieldVar):
raise AttributeError('No such attribute %r' % key)
return [data.get(field.id) for data in self._formdata.data.get(self._field.id)['data']]
def getlistdict(self, keys):
fields = []
for key in keys:
matchings_fields = [field for field in self._field.block.fields if field.varname == key]
matching_field_id = matchings_fields[0].id if matchings_fields else None
fields.append((key, matching_field_id))
return [
{key: data.get(field_id) if field_id else None for key, field_id in fields}
for data in self._formdata.data.get(self._field.id)['data']
]
class LazyUser:
def __init__(self, user):