Skip to content
Snippets Groups Projects
Commit e8fbdf9c authored by Bastien Abadie's avatar Bastien Abadie
Browse files

Merge branch 'recursive-option' into 'master'

Add recursive option on ElementParents and ElementChildren

See merge request !477
parents 75722ee5 9da1aa12
No related branches found
No related tags found
1 merge request!477Add recursive option on ElementParents and ElementChildren
......@@ -7,7 +7,7 @@ from rest_framework.generics import (
)
from arkindex_common.enums import TranscriptionType
from arkindex.documents.models import Classification, Corpus, Element, Right, Transcription, Region
from arkindex.documents.models import Classification, Corpus, Element, ElementPath, Right, Transcription, Region
from arkindex.documents.serializers.elements import (
CorpusSerializer, ElementCreateSerializer, ElementSerializer, ElementSlimSerializer,
RegionSerializer, RegionCreateSerializer, ElementNeighborsSerializer
......@@ -137,7 +137,17 @@ class ElementParents(ListAPIView):
'schema': {
'type': 'string',
}
}
},
{
'name': 'recursive',
'in': 'query',
'description': 'List recursively (children, grandchildren, etc.)',
'required': False,
'schema': {
'type': 'boolean',
'default': False
}
},
]
}
......@@ -150,6 +160,17 @@ class ElementParents(ListAPIView):
if type_param is not None:
filters['new_type__slug'] = type_param
recursive_param = self.request.query_params.get('recursive')
if recursive_param is None or recursive_param.lower() in ('false', '0'):
# List direct parents only: elements whose IDs are the last in the element's paths
return Element.objects.filter(
id__in=ElementPath.objects
.filter(element_id=self.kwargs['pk'])
.values('path__last'),
**filters,
).prefetch_related('zone__image__server', 'corpus', 'new_type')
parents = Element.objects.get_ascending(self.kwargs['pk'], **filters)
prefetch_related_objects(parents, 'zone__image__server', 'corpus', 'new_type')
return parents
......@@ -174,20 +195,43 @@ class ElementChildren(ListAPIView):
'schema': {
'type': 'string',
}
}
},
{
'name': 'recursive',
'in': 'query',
'description': 'List recursively (parents, grandparents, etc.)',
'required': False,
'schema': {
'type': 'boolean',
'default': False
}
},
]
}
def get_queryset(self):
qs = Element.objects.get_descending(self.kwargs['pk']).filter(
corpus__in=Corpus.objects.readable(self.request.user)
)
filters = {
'corpus__in': Corpus.objects.readable(self.request.user)
}
type_param = self.request.query_params.get('type')
if type_param is not None:
qs = qs.filter(new_type__slug=type_param)
filters['new_type__slug'] = type_param
recursive_param = self.request.query_params.get('recursive')
if recursive_param is None or recursive_param.lower() in ('false', '0'):
# Only list direct children
# We could use Element.objects.filter(paths__path__last=volid) directly,
# but it is 100× slower due to the implementation of path__last.
# get_descending uses 'path @> ARRAY[element.id]', which is much faster,
# so we append the __last filter to it.
filters['paths__path__last'] = self.kwargs['pk']
return qs.prefetch_related('zone__image__server', 'corpus', 'new_type')
return Element.objects \
.get_descending(self.kwargs['pk']) \
.filter(**filters) \
.prefetch_related('zone__image__server', 'corpus', 'new_type')
class CorpusList(ListCreateAPIView):
......
......@@ -525,6 +525,19 @@ class TestElementsAPI(FixtureAPITestCase):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertListEqual(response.json()['results'], [])
surface = Element.objects.get(name='Surface A')
response = self.client.get(reverse('api:elements-parents', kwargs={'pk': str(surface.id)}))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.json()['results']), 1)
self.assertEqual(response.json()['results'][0]['name'], 'Act 1')
response = self.client.get(reverse('api:elements-parents', kwargs={'pk': str(surface.id)}) + '?recursive')
self.assertEqual(len(response.json()['results']), 2)
self.assertListEqual(
[r['name'] for r in response.json()['results']],
['Volume 1', 'Act 1']
)
def test_element_children(self):
response = self.client.get(reverse('api:elements-children', kwargs={'pk': str(self.page.id)}))
self.assertEqual(response.status_code, status.HTTP_200_OK)
......@@ -532,7 +545,19 @@ class TestElementsAPI(FixtureAPITestCase):
response = self.client.get(reverse('api:elements-children', kwargs={'pk': str(self.vol.id)}))
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.json()['results']), 8)
self.assertSetEqual(
{r['type'] for r in response.json()['results']},
{'act', 'page'},
)
response = self.client.get(reverse('api:elements-children', kwargs={'pk': str(self.vol.id)}) + '?recursive')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.json()['results']), 14)
self.assertSetEqual(
{r['type'] for r in response.json()['results']},
{'act', 'page', 'surface'},
)
response = self.client.get(reverse('api:elements-children', kwargs={'pk': str(self.vol.id)}) + '?type=page')
self.assertEqual(response.status_code, status.HTTP_200_OK)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment