business_logic/rest/views.py
# -*- coding: utf-8 -*-
import operator
from collections import OrderedDict
from functools import reduce
from django.apps import apps
from django.db import models
from rest_framework import generics, exceptions
from rest_framework.compat import distinct
from rest_framework.decorators import api_view
from rest_framework.filters import SearchFilter
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from .serializers import *
def format_url(_url):
return 'business-logic:rest:{}'.format(_url)
@api_view(('GET',))
def api_root(request, format=None):
from rest_framework.reverse import reverse
return Response(
OrderedDict((
('program-interface', reverse(format_url('program-interface-list'), request=request, format=format)),
('program', reverse(format_url('program-list'), request=request, format=format)),
('program-version', reverse(format_url('program-version-list'), request=request, format=format)),
('program-version-create', reverse(format_url('program-version-create'), request=request, format=format)),
('reference', reverse(format_url('reference-descriptor-list'), request=request, format=format)),
('execution', reverse(format_url('execution-list'), request=request, format=format)),
)))
class StandardResultsSetPagination(PageNumberPagination):
page_size = 50
page_size_query_param = 'page_size'
max_page_size = 1000
class ObjectList(generics.ListAPIView):
pagination_class = StandardResultsSetPagination
filter_backends = (DjangoFilterBackend,)
class ProgramInterfaceList(generics.ListAPIView):
queryset = ProgramInterface.objects.all()
serializer_class = ProgramInterfaceListSerializer
pagination_class = StandardResultsSetPagination
class ProgramInterfaceView(generics.RetrieveAPIView):
queryset = ProgramInterface.objects.all()
serializer_class = ProgramInterfaceSerializer
class ProgramList(ObjectList):
queryset = Program.objects.all()
serializer_class = ProgramListSerializer
filterset_fields = ('program_interface',)
class ProgramView(generics.RetrieveAPIView):
queryset = Program.objects.all()
serializer_class = ProgramSerializer
class ProgramVersionList(ObjectList):
queryset = ProgramVersion.objects.all()
serializer_class = ProgramVersionListSerializer
filterset_fields = ('program',)
class ProgramVersionCreate(generics.CreateAPIView):
queryset = ProgramVersion.objects.all()
serializer_class = ProgramVersionCreateSerializer
class ProgramVersionView(generics.RetrieveUpdateDestroyAPIView):
queryset = ProgramVersion.objects.all()
serializer_class = ProgramVersionSerializer
def perform_update(self, serializer):
instance = self.get_object()
instance.entry_point.delete()
super(ProgramVersionView, self).perform_update(serializer)
class ExecutionList(ObjectList):
queryset = Execution.objects.all()
serializer_class = ExecutionListSerializer
filterset_fields = ('program_version',)
class ExecutionView(generics.RetrieveDestroyAPIView):
queryset = Execution.objects.all()
serializer_class = ExecutionSerializer
class LogView(generics.RetrieveAPIView):
queryset = LogEntry.objects.all()
serializer_class = LogSerializer
lookup_field = 'execution__id'
class ReferenceDescriptorList(generics.ListAPIView):
queryset = ReferenceDescriptor.objects.all()
serializer_class = ReferenceDescriptorListSerializer
class ReferenceSearchFilter(SearchFilter):
def filter_queryset(self, request, queryset, view):
search_terms = self.get_search_terms(request)
if not search_terms:
return queryset
reference_descriptor = view.get_reference_descriptor()
search_fields = reference_descriptor.get_search_fields()
if not search_fields:
raise exceptions.ValidationError(
'ReferenceDescriptor for `{}` are not configured: incorrect `search_fields` field'.format(
view.get_reference_model_name()))
orm_lookups = [self.construct_search(str(search_field)) for search_field in search_fields]
base = queryset
for search_term in search_terms:
queries = [models.Q(**{orm_lookup: search_term}) for orm_lookup in orm_lookups]
queryset = queryset.filter(reduce(operator.or_, queries))
if self.must_call_distinct(queryset, search_fields):
# Filtering against a many-to-many field requires us to
# call queryset.distinct() in order to avoid duplicate items
# in the resulting queryset.
# We try to avoid this if possible, for performance reasons.
queryset = distinct(queryset, base)
return queryset
class ReferenceBaseView(object):
serializer_class = ReferenceSerializer
def get_queryset(self):
try:
self.get_reference_descriptor()
except ReferenceDescriptor.DoesNotExist:
raise exceptions.NotFound()
return self.get_reference_model().objects.all()
def get_reference_descriptor(self):
return ReferenceDescriptor.objects.get(
content_type=ContentType.objects.get_for_model(self.get_reference_model()))
def get_reference_model_name(self):
return self.kwargs['model']
def get_reference_model(self):
try:
app_name, model_name = self.get_reference_model_name().split('.')
model = apps.get_model(app_name, model_name)
except (ValueError, LookupError):
raise exceptions.NotFound()
return model
class ReferenceList(ReferenceBaseView, generics.ListAPIView):
pagination_class = StandardResultsSetPagination
filter_backends = [ReferenceSearchFilter]
class ReferenceView(ReferenceBaseView, generics.RetrieveAPIView):
serializer_class = ReferenceSerializer