Skip to content

Commit 2ee80de

Browse files
authored
Merge pull request #1267 from TOMToolkit/1125-add-target-and-dataproduct-filters-to-the-reduceddatums-drf-api
add ReducedDatum filters
2 parents 68b4893 + 231d135 commit 2ee80de

9 files changed

Lines changed: 118 additions & 21 deletions

File tree

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
API Views
2-
=========
1+
Data API Views
2+
==============
33

44
.. warning:: Check your groups!
55

@@ -10,8 +10,13 @@ API Views
1010

1111
.. tip:: Better API documentation
1212

13-
The available parameters for RESTful API calls are not available here. However, if you navigate to ``/api/targets/``
14-
and click the ``OPTIONS`` button, you can easily view all of the available parameters.
13+
The available parameters for RESTful API calls are not available here. However, if you navigate to
14+
``/api/reduceddatums/`` and click the ``OPTIONS`` button, you can easily view all of the available parameters.
15+
16+
From the ``GET`` view, you can experiment with the available filters and see an example of the request.
1517

1618
.. automodule:: tom_dataproducts.api_views
17-
:members:
19+
:members:
20+
21+
.. automodule:: tom_dataproducts.filters
22+
:members:

docs/api/tom_targets/api_views.rst

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
API Views
2-
=========
1+
Target API Views
2+
================
33

44
.. warning:: Check your groups!
55

@@ -12,5 +12,10 @@ API Views
1212
The available parameters for RESTful API calls are not available here. However, if you navigate to ``/api/targets/``
1313
and click the ``OPTIONS`` button, you can easily view all of the available parameters.
1414

15+
From the ``GET`` view, you can experiment with the available filters and see an example of the request.
16+
1517
.. automodule:: tom_targets.api_views
16-
:members:
18+
:members:
19+
20+
.. automodule:: tom_targets.filters.TargetFilter
21+
:members:

docs/introduction/credits.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Austin Riba, David Collom and William Lindstrom.
1313

1414
Our team very much welcome input from the community, and we are grateful to
1515
the following people for their many contributions:
16+
1617
- Dan Avner, NOIRLab
1718
- Doug Arnold, Liverpool Telescope
1819
- Etienne Bachelet, IPAC/Caltech

docs/managing_data/single_target_data_service.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ as an asynchronous task manager. To use django-tasks you can enable it by adding
7272
7373
7474
.. code:: python
75+
7576
TASKS = {
7677
"default": {
7778
"BACKEND": "django_tasks.backends.database.DatabaseBackend"

tom_dataproducts/api_views.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from tom_common.hooks import run_hook
1212
from tom_dataproducts.data_processor import run_data_processor
13-
from tom_dataproducts.filters import DataProductFilter
13+
from tom_dataproducts.filters import DataProductFilter, ReducedDatumFilter
1414
from tom_dataproducts.models import DataProduct, ReducedDatum
1515
from tom_dataproducts.serializers import DataProductSerializer, ReducedDatumSerializer
1616
from tom_targets.models import Target
@@ -77,15 +77,11 @@ class ReducedDatumViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, G
7777
Viewset for ReducedDatum objects. Supports list, create, and delete.
7878
7979
To view supported query parameters, please use the OPTIONS endpoint, which can be accessed through the web UI.
80-
81-
**Please note that ``groups`` are an accepted query parameters for the ``CREATE`` endpoint. The groups parameter
82-
will specify which ``groups`` can view the created ``DataProduct``. If no ``groups`` are specified, the
83-
``ReducedDatum`` will only be visible to the user that created the ``DataProduct``. Make sure to check your
84-
``groups``!!**
8580
"""
8681
queryset = ReducedDatum.objects.all()
8782
serializer_class = ReducedDatumSerializer
8883
filter_backends = (drf_filters.DjangoFilterBackend,)
84+
filterset_class = ReducedDatumFilter
8985
permission_required = 'tom_dataproducts.view_reduceddatum'
9086
parser_classes = [FormParser, JSONParser]
9187

tom_dataproducts/filters.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
import django_filters
22
from django.db.models import Q
33

4-
from tom_dataproducts.models import DataProduct
4+
from tom_dataproducts.models import DataProduct, ReducedDatum
55

66

7-
class DataProductFilter(django_filters.FilterSet):
7+
class DataProductFilter(django_filters.rest_framework.FilterSet):
8+
"""
9+
Filters are available for DataProduct objects:
10+
- target_name: Filter by target name or alias.
11+
- facility: Filter by the facility of the observation record associated with the data product.
12+
13+
Access these filters via the API endpoint:
14+
`GET /api/dataproducts/?target_name=<name>&facility=<facility>`
15+
"""
816
target_name = django_filters.CharFilter(label='Target Name', method='filter_name')
917
facility = django_filters.CharFilter(field_name='observation_record__facility', label='Observation Record Facility')
1018

@@ -14,3 +22,31 @@ class Meta:
1422

1523
def filter_name(self, queryset, name, value):
1624
return queryset.filter(Q(target__name__icontains=value) | Q(target__aliases__name__icontains=value))
25+
26+
27+
class ReducedDatumFilter(django_filters.rest_framework.FilterSet):
28+
"""
29+
Filters are available for ReducedDatum objects:
30+
- target__id: Filter by target ID.
31+
- target_name: Filter by target name or alias.
32+
- data_product_pk: Filter by the primary key of the associated DataProduct.
33+
- data_product_product_id: Filter by the "Product ID" or filename of the associated DataProduct.
34+
- source_name: Filter by the name of the source.
35+
- data_type: Filter by the type of data (e.g., 'photometry', 'spectrum').
36+
37+
Access these filters via the API endpoint:
38+
`GET /api/reduceddatums/?target__id=<id>&data_type=<type>`
39+
"""
40+
target_name = django_filters.CharFilter(label='Target Name', method='filter_name')
41+
data_product_name = django_filters.CharFilter(method='filter_data_product_name', label='Data Product filename')
42+
43+
class Meta:
44+
model = ReducedDatum
45+
fields = ['target__id', 'target_name', 'data_product__id', 'source_name', 'data_type']
46+
47+
def filter_name(self, queryset, name, value):
48+
return queryset.filter(Q(target__name__icontains=value) | Q(target__aliases__name__icontains=value))
49+
50+
def filter_data_product_name(self, queryset, name, value):
51+
return queryset.filter(data_product__product_id__icontains=value) | \
52+
queryset.filter(data_product__data__icontains=value)

tom_dataproducts/tests/test_api.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,41 @@ def test_upload_reduced_datum_no_sharing_name(self):
157157
del self.rd_data['source_name']
158158
response = self.client.post(reverse('api:reduceddatums-list'), self.rd_data, format='json')
159159
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
160+
161+
def test_reduced_datum_list(self):
162+
rd = ReducedDatum.objects.create(
163+
target=self.st,
164+
data_type='photometry',
165+
source_name='TOM Toolkit',
166+
value={'magnitude': 15.582, 'filter': 'r', 'error': 0.005},
167+
)
168+
169+
response = self.client.get(reverse('api:reduceddatums-list'))
170+
self.assertContains(response, rd.data_type, status_code=status.HTTP_200_OK)
171+
172+
def test_reduced_datum_filter(self):
173+
rd1 = ReducedDatum.objects.create(
174+
target=self.st,
175+
data_type='photometry',
176+
source_name='TOM Toolkit',
177+
value={'magnitude': 15.582, 'filter': 'r', 'error': 0.005},
178+
)
179+
rd2 = ReducedDatum.objects.create(
180+
target=self.st,
181+
data_type='spectroscopy',
182+
source_name='TOM Toolkit',
183+
value={'wavelength': 150, 'flux': 12, 'error': 0.005},
184+
)
185+
186+
# test filter for one object
187+
response = self.client.get(reverse('api:reduceddatums-list'), QUERY_STRING='data_type=photometry')
188+
self.assertContains(response, rd1.data_type, status_code=status.HTTP_200_OK, count=1)
189+
190+
# test filter for both objects
191+
response2 = self.client.get(reverse('api:reduceddatums-list'), QUERY_STRING=f'target_name={self.st.name}')
192+
self.assertContains(response2, rd2.data_type, status_code=status.HTTP_200_OK, count=2)
193+
194+
# test filter for no objects
195+
response3 = self.client.get(reverse('api:reduceddatums-list'), QUERY_STRING='source_name=thin_air')
196+
self.assertEqual(response3.data['count'], 0)
197+
self.assertEqual(response3.data['results'], [])

tom_observations/views.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
from django.contrib import messages
1212
from django.contrib.auth.mixins import LoginRequiredMixin
1313
from django.core.management import call_command
14-
from django_filters import (CharFilter, ChoiceFilter, DateTimeFromToRangeFilter, FilterSet, ModelMultipleChoiceFilter,
15-
OrderingFilter, MultipleChoiceFilter)
14+
from django_filters import CharFilter, ChoiceFilter, DateTimeFromToRangeFilter, ModelMultipleChoiceFilter
15+
from django_filters import OrderingFilter, MultipleChoiceFilter, rest_framework
1616
from django_filters.views import FilterView
1717
from django.shortcuts import redirect
1818
from django.urls import reverse, reverse_lazy
@@ -38,7 +38,7 @@
3838
logger = logging.getLogger(__name__)
3939

4040

41-
class ObservationFilter(FilterSet):
41+
class ObservationFilter(rest_framework.FilterSet):
4242
"""
4343
Defines the available fields for filtering the list of ``ObservationRecord`` objects.
4444
"""
@@ -594,7 +594,7 @@ class ObservationGroupDeleteView(Raise403PermissionRequiredMixin, DeleteView):
594594
success_url = reverse_lazy('tom_observations:group-list')
595595

596596

597-
class ObservationTemplateFilter(FilterSet):
597+
class ObservationTemplateFilter(rest_framework.FilterSet):
598598
"""
599599
Defines the available fields for filtering the list of ``ObservationTemplate`` objects.
600600
"""

tom_targets/filters.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,22 @@ def filter_text(queryset, name, value):
4141
return queryset.filter(targetextra__key=name, targetextra__value__icontains=value)
4242

4343

44-
class TargetFilter(django_filters.FilterSet):
44+
class TargetFilter(django_filters.rest_framework.FilterSet):
45+
"""
46+
Filters are available for Target objects:
47+
- type: Filter by target type (e.g., 'SIDEREAL', 'NON_SIDEREAL').
48+
- name: Filter by target name or alias.
49+
- key: Filter by a specific key in the target's extra fields.
50+
- value: Filter by a specific value in the target's extra fields.
51+
- cone_search: Perform a cone search around a given position (RA,Dec,Radius).
52+
- targetlist__name: Filter by the name of the target list the target belongs to.
53+
- name_fuzzy: Perform a fuzzy search on the target name or aliases.
54+
- target_cone_search: Perform a cone search on the target's position (radius).
55+
- order: Order the results by a specific field ('name', 'created', 'modified')
56+
57+
Access these filters via the API endpoint:
58+
`GET /api/targets/?type=<type>&cone_search=<ra,dec,radius>`
59+
"""
4560
key = django_filters.CharFilter(field_name='targetextra__key', label='Key')
4661
value = django_filters.CharFilter(field_name='targetextra__value', label='Value')
4762

0 commit comments

Comments
 (0)