datasource: data attribute can be "data/foo/bar/results" (#53911)

This commit is contained in:
Lauréline Guérin 2021-05-11 10:23:39 +02:00
parent 520355bd62
commit a5be377eb5
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
3 changed files with 30 additions and 3 deletions

View File

@ -338,6 +338,18 @@ def test_json_datasource(pub, requests_pub, http_requests):
get_request().datasources_cache = {}
assert data_sources.get_structured_items(datasource) == []
get_request().datasources_cache = {}
with open(json_file_path, 'w') as json_file:
json.dump({'data': {'results': [{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}]}}, json_file)
assert data_sources.get_structured_items(datasource) == []
datasource = {'type': 'json', 'value': ' {{ json_url }}', 'data_attribute': 'data.results'}
get_request().datasources_cache = {}
assert data_sources.get_structured_items(datasource) == [
{'id': '1', 'text': 'foo'},
{'id': '2', 'text': 'bar'},
]
# specify id_attribute
datasource = {'type': 'json', 'value': ' {{ json_url }}', 'id_attribute': 'pk'}
get_request().datasources_cache = {}

View File

@ -181,7 +181,10 @@ class NamedDataSourceUI:
'data_attribute',
value=self.datasource.data_attribute,
title=_('Data Attribute'),
hint=_('Name of the attribute containing the list of results (default: data)'),
hint=_(
'Name of the attribute containing the list of results (default: data). '
'Possibility to chain attributes with a dot separator (example: data.results)'
),
required=False,
advanced=True,
attrs={

View File

@ -171,6 +171,7 @@ def get_json_from_url(url, data_source=None, log_message_part='JSON data source'
geojson = data_source.get('type') == 'geojson'
error_summary = None
exc = None
try:
entries = misc.json_loads(misc.urlopen(url).read())
if not isinstance(entries, dict):
@ -181,7 +182,14 @@ def get_json_from_url(url, data_source=None, log_message_part='JSON data source'
if not isinstance(entries.get('features'), list):
raise ValueError('bad geojson format')
else:
if not isinstance(entries.get(data_key), list):
# data_key can be "data.foo.bar.results"
keys = data_key.split('.')
data = entries
for key in keys[:-1]:
if not isinstance(data.get(key), dict):
raise ValueError('not a json dict with a %s list attribute' % data_key)
data = data[key]
if not isinstance(data.get(keys[-1]), list):
raise ValueError('not a json dict with a %s list attribute' % data_key)
return entries
except misc.ConnectionError as e:
@ -213,8 +221,12 @@ def request_json_items(url, data_source):
data_key = data_source.get('data_attribute') or 'data'
id_attribute = data_source.get('id_attribute') or 'id'
text_attribute = data_source.get('text_attribute') or 'text'
# data_key can be "data.foo.bar.results"
keys = data_key.split('.')
for key in keys:
entries = entries[key]
items = []
for item in entries.get(data_key):
for item in entries:
# skip malformed items
if not isinstance(item, dict):
continue