opendatasoft: add facet filters (#50212)

This commit is contained in:
Nicolas Roche 2021-04-09 11:39:17 +02:00
parent ecd314d714
commit cac06da89e
3 changed files with 87 additions and 14 deletions

View File

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.29 on 2021-06-25 16:52
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('opendatasoft', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='query',
name='filter_expression',
field=models.TextField(
blank=True,
help_text='Specify refine and exclude facet expressions separated lines',
verbose_name='filter',
),
),
migrations.AlterField(
model_name='opendatasoft',
name='service_url',
field=models.CharField(
help_text='URL without ending "api/records/1.0/search/"',
max_length=256,
verbose_name='Site URL',
),
),
]

View File

@ -64,18 +64,7 @@ class OpenDataSoft(BaseResource):
Query.objects.bulk_create(queries)
return instance
@endpoint(
perm='can_access',
description=_('Search'),
parameters={
'dataset': {'description': _('Dataset')},
'text_template': {'description': _('Text template')},
'id': {'description': _('Record identifier')},
'q': {'description': _('Full text query')},
'limit': {'description': _('Maximum items')},
},
)
def search(self, request, dataset=None, text_template='', id=None, q=None, limit=None, **kwargs):
def call_search(self, dataset=None, text_template='', filter_expression='', id=None, q=None, limit=None):
scheme, netloc, path, params, query, fragment = urlparse.urlparse(self.service_url)
path = urlparse.urljoin(path, 'api/records/1.0/search/')
url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
@ -92,6 +81,7 @@ class OpenDataSoft(BaseResource):
params.update({'apikey': self.api_key})
if limit:
params.update({'rows': limit})
params.update(urlparse.parse_qs(filter_expression))
result_response = self.requests.get(url, params=params)
err_desc = result_response.json().get('error')
@ -109,6 +99,21 @@ class OpenDataSoft(BaseResource):
data['text'] = render_to_string(text_template, data).strip()
result.append(data)
return result
@endpoint(
perm='can_access',
description=_('Search'),
parameters={
'dataset': {'description': _('Dataset')},
'text_template': {'description': _('Text template')},
'id': {'description': _('Record identifier')},
'q': {'description': _('Full text query')},
'limit': {'description': _('Maximum items')},
},
)
def search(self, request, dataset=None, text_template='', id=None, q=None, limit=None, **kwargs):
result = self.call_search(dataset, text_template, '', id, q, limit)
return {'data': result}
@endpoint(
@ -120,7 +125,8 @@ class OpenDataSoft(BaseResource):
)
def q(self, request, query_slug, **kwargs):
query = get_object_or_404(Query, resource=self, slug=query_slug)
return query.q(request, **kwargs)
result = query.q(request, **kwargs)
return {'data': result}
def create_query_url(self):
return reverse('opendatasoft-query-new', kwargs={'slug': self.slug})
@ -142,12 +148,26 @@ class Query(BaseQuery):
validators=[validate_template],
blank=True,
)
filter_expression = models.TextField(
verbose_name=_('filter'),
help_text=_('Specify refine and exclude facet expressions separated lines'),
blank=True,
)
delete_view = 'opendatasoft-query-delete'
edit_view = 'opendatasoft-query-edit'
def q(self, request, **kwargs):
return self.resource.search(request, dataset=self.dataset, text_template=self.text_template, **kwargs)
return self.resource.call_search(
dataset=self.dataset,
text_template=self.text_template,
filter_expression='&'.join(
[x.strip() for x in str(self.filter_expression).splitlines() if x.strip()]
),
id=kwargs.get('id'),
q=kwargs.get('q'),
limit=kwargs.get('limit'),
)
def as_endpoint(self):
endpoint = super(Query, self).as_endpoint(path=self.resource.q.endpoint_info.name)

View File

@ -143,6 +143,11 @@ def query(connector):
description='Rechercher une adresse',
dataset='referentiel-adresse-test',
text_template='{{numero}} {{nom_rue}} {{nom_commun}}',
filter_expression='''
refine.source=Ville et Eurométropole de Strasbourg
exclude.numero=42
exclude.numero=43
''',
)
@ -237,6 +242,14 @@ def test_query_q_using_q(mocked_get, app, query):
}
mocked_get.return_value = utils.FakedResponse(content=FAKED_CONTENT_Q_SEARCH, status_code=200)
resp = app.get(endpoint, params=params, status=200)
assert mocked_get.call_args[1]['params'] == {
'dataset': 'referentiel-adresse-test',
'q': "rue de l'aubepine",
'apikey': 'my_secret',
'rows': '3',
'refine.source': ['Ville et Eurométropole de Strasbourg'],
'exclude.numero': ['42', '43'],
}
assert not resp.json['err']
assert len(resp.json['data']) == 3
# check order is kept
@ -263,6 +276,13 @@ def test_query_q_using_id(mocked_get, app, query):
}
mocked_get.return_value = utils.FakedResponse(content=FAKED_CONTENT_ID_SEARCH, status_code=200)
resp = app.get(endpoint, params=params, status=200)
assert mocked_get.call_args[1]['params'] == {
'dataset': 'referentiel-adresse-test',
'q': 'recordid:7cafcd5c692773e8b863587b2d38d6be82e023d8',
'apikey': 'my_secret',
'refine.source': ['Ville et Eurométropole de Strasbourg'],
'exclude.numero': ['42', '43'],
}
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['text'] == "19 RUE DE L'AUBEPINE Lipsheim"