Source code for tom_dataproducts.api_views

from django.conf import settings
from django.http import Http404
from django_filters import rest_framework as drf_filters
from guardian.mixins import PermissionListMixin
from guardian.shortcuts import assign_perm, get_objects_for_user
from rest_framework import status
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet

from tom_common.hooks import run_hook
from tom_dataproducts.data_processor import run_data_processor
from tom_dataproducts.filters import DataProductFilter, ReducedDatumFilter
from tom_dataproducts.models import (DataProduct, ReducedDatum, PhotometryReducedDatum,
                                     SpectroscopyReducedDatum, AstrometryReducedDatum,
                                     REDUCED_DATUM_MODELS)
from tom_dataproducts.serializers import DataProductSerializer, ReducedDatumSerializer
from tom_targets.models import Target


# Maps the data_type query param to the concrete model that holds those rows.
_DATA_TYPE_MODEL_MAP = {
    'photometry': PhotometryReducedDatum,
    'spectroscopy': SpectroscopyReducedDatum,
    'astrometry': AstrometryReducedDatum,
}


[docs] class DataProductViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, GenericViewSet, PermissionListMixin): """ Viewset for DataProduct objects. Supports list, create, and delete. To view supported query parameters, please use the OPTIONS endpoint, which can be accessed through the web UI. **Please note that ``groups`` are an accepted query parameters for the ``CREATE`` endpoint. The groups parameter will specify which ``groups`` can view the created ``DataProduct``. If no ``groups`` are specified, the ``DataProduct`` will only be visible to the user that created the ``DataProduct``. Make sure to check your ``groups``!!** """ queryset = DataProduct.objects.all() serializer_class = DataProductSerializer filter_backends = (drf_filters.DjangoFilterBackend,) filterset_class = DataProductFilter permission_required = 'tom_dataproducts.view_dataproduct' parser_classes = [MultiPartParser] def create(self, request, *args, **kwargs): request.data['data'] = request.FILES['file'] response = super().create(request, *args, **kwargs) if response.status_code == status.HTTP_201_CREATED: response.data['message'] = 'Data product successfully uploaded.' dp = DataProduct.objects.get(pk=response.data['id']) try: run_hook('data_product_post_upload', dp) reduced_data = run_data_processor(dp) if not settings.TARGET_PERMISSIONS_ONLY: for group in response.data['group']: assign_perm('tom_dataproducts.view_dataproduct', group, dp) assign_perm('tom_dataproducts.delete_dataproduct', group, dp) assign_perm('tom_dataproducts.view_reduceddatum', group, reduced_data) except Exception: for model in REDUCED_DATUM_MODELS: model.objects.filter(data_product=dp).delete() dp.delete() return Response({'Data processing error': '''There was an error in processing your DataProduct into \ individual ReducedDatum objects.'''}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) return response
[docs] def get_queryset(self): """ Gets the set of ``DataProduct`` objects that the user has permission to view. :returns: Set of ``DataProduct`` objects :rtype: QuerySet """ if settings.TARGET_PERMISSIONS_ONLY: return super().get_queryset().filter( target__in=get_objects_for_user(self.request.user, f'{Target._meta.app_label}.view_target') ) else: return get_objects_for_user(self.request.user, 'tom_dataproducts.view_dataproduct')
[docs] class ReducedDatumViewSet(CreateModelMixin, DestroyModelMixin, ListModelMixin, GenericViewSet, PermissionListMixin): """ Viewset for ReducedDatum objects. Supports list, create, and delete. To view supported query parameters, please use the OPTIONS endpoint, which can be accessed through the web UI. The list endpoint queries all concrete ReducedDatum and returns them in the legacy json format. TODO: Deprecate the legacy format and have seperate enpoints for each type? """ queryset = ReducedDatum.objects.all() serializer_class = ReducedDatumSerializer filter_backends = (drf_filters.DjangoFilterBackend,) filterset_class = ReducedDatumFilter permission_required = 'tom_dataproducts.view_reduceddatum' parser_classes = [FormParser, JSONParser]
[docs] def get_object(self): pk = self.kwargs.get(self.lookup_field) for model in REDUCED_DATUM_MODELS: try: obj = model.objects.get(pk=pk) self.check_object_permissions(self.request, obj) return obj except model.DoesNotExist: pass raise Http404
def _base_queryset_for_model(self, model): qs = model.objects.all() if settings.TARGET_PERMISSIONS_ONLY: qs = qs.filter( target__in=get_objects_for_user(self.request.user, f'{Target._meta.app_label}.view_target') ) return qs def list(self, request, *args, **kwargs): params = request.query_params requested_data_type = params.get('data_type', '').lower() # Determine which models to query if requested_data_type in _DATA_TYPE_MODEL_MAP: # A typed data_type models_to_query = [_DATA_TYPE_MODEL_MAP[requested_data_type]] elif requested_data_type: # An unmapped data_type is a generic ReducedDatum models_to_query = [ReducedDatum] else: models_to_query = REDUCED_DATUM_MODELS # Strip data_type before passing to ReducedDatumFilter it doesn't exist on concrete types filter_params = {k: v for k, v in params.items() if k != 'data_type'} all_instances = [] for model in models_to_query: qs = self._base_queryset_for_model(model) if model is ReducedDatum and requested_data_type: qs = qs.filter(data_type=requested_data_type) qs = ReducedDatumFilter(data=filter_params, queryset=qs).qs all_instances.extend(list(qs)) all_instances.sort(key=lambda x: x.timestamp, reverse=True) page = self.paginate_queryset(all_instances) if page is not None: return self.get_paginated_response(self.get_serializer(page, many=True).data) return Response(self.get_serializer(all_instances, many=True).data) def create(self, request, *args, **kwargs): response = super().create(request, *args, **kwargs) if response.status_code == status.HTTP_201_CREATED: response.data['message'] = 'Data successfully uploaded.' return response