From b8e7bb9bccef679f4f592a0536a9c351e7535727 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 10 Nov 2017 11:16:17 -0700 Subject: [PATCH] ENH: Collection filterings (#30) Fixes #29 --- ccdb/api/middleware.py | 13 ++++++++ ccdb/api/urls.py | 2 ++ ccdb/collections_ccdb/filters.py | 44 ++++++++++++++++++++++++++++ ccdb/collections_ccdb/serializers.py | 1 + ccdb/collections_ccdb/viewsets.py | 4 +++ ccdb/locations/serializers.py | 24 +++++++++++++-- ccdb/locations/viewsets.py | 15 ++++++++-- config/settings/base.py | 2 ++ requirements/base.txt | 2 +- 9 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 ccdb/api/middleware.py create mode 100644 ccdb/collections_ccdb/filters.py diff --git a/ccdb/api/middleware.py b/ccdb/api/middleware.py new file mode 100644 index 0000000..e61d597 --- /dev/null +++ b/ccdb/api/middleware.py @@ -0,0 +1,13 @@ +class DeBracketifyMiddleware(object): + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + cleaned = request.GET.copy() + for key in cleaned: + if key.endswith('[]'): + val = cleaned.pop(key) + cleaned_key = key.replace('[]', '') + cleaned.setlist(cleaned_key, val) + request.GET = cleaned + return self.get_response(request) diff --git a/ccdb/api/urls.py b/ccdb/api/urls.py index 70e301d..7aab9ca 100644 --- a/ccdb/api/urls.py +++ b/ccdb/api/urls.py @@ -24,6 +24,8 @@ router.register(r'collection-flaws', # Projects router.register(r'projects', projects_viewsets.ProjectViewSet) # Locations +router.register(r'regions', locations_viewsets.RegionViewSet) +router.register(r'sites', locations_viewsets.SiteViewSet) router.register(r'study-locations', locations_viewsets.StudyLocationViewSet) urlpatterns = [ diff --git a/ccdb/collections_ccdb/filters.py b/ccdb/collections_ccdb/filters.py new file mode 100644 index 0000000..e031b69 --- /dev/null +++ b/ccdb/collections_ccdb/filters.py @@ -0,0 +1,44 @@ +from django_filters.filters import ModelMultipleChoiceFilter +from django_filters import rest_framework as filters + +from .models import Collection, CollectionMethod +from ccdb.projects.models import Project +from ccdb.locations.models import Region, Site, StudyLocation + + +class CollectionFilter(filters.FilterSet): + project = ModelMultipleChoiceFilter( + name='project__id', + to_field_name='id', + queryset=Project.objects.all(), + ) + + region = ModelMultipleChoiceFilter( + name='study_location__site__region__id', + to_field_name='id', + queryset=Region.objects.all(), + ) + + site = ModelMultipleChoiceFilter( + name='study_location__site__id', + to_field_name='id', + queryset=Site.objects.all(), + ) + + study_location = ModelMultipleChoiceFilter( + name='study_location__id', + to_field_name='id', + queryset=StudyLocation.objects.all(), + ) + + collection_method = ModelMultipleChoiceFilter( + name='collection_method__id', + to_field_name='id', + queryset=CollectionMethod.objects.all(), + ) + + class Meta: + model = Collection + fields = ['project', 'region', 'site', 'study_location', + 'collection_method', 'number_of_traps', + 'collection_start_date', 'collection_end_date'] diff --git a/ccdb/collections_ccdb/serializers.py b/ccdb/collections_ccdb/serializers.py index 2f4533f..5f3ccc4 100644 --- a/ccdb/collections_ccdb/serializers.py +++ b/ccdb/collections_ccdb/serializers.py @@ -6,6 +6,7 @@ from .models import Collection, CollectionMethod, CollectionType, Flaw class CollectionSerializer(serializers.ModelSerializer): included_serializers = { 'project': 'ccdb.projects.serializers.ProjectSerializer', + 'site': 'ccdb.locations.serializers.SiteSerializer', 'study_location': 'ccdb.locations.serializers.StudyLocationSerializer', 'collection_method': 'ccdb.collections_ccdb.serializers.CollectionMethodSerializer', diff --git a/ccdb/collections_ccdb/viewsets.py b/ccdb/collections_ccdb/viewsets.py index 6001dee..1581e6c 100644 --- a/ccdb/collections_ccdb/viewsets.py +++ b/ccdb/collections_ccdb/viewsets.py @@ -1,5 +1,7 @@ from rest_framework import viewsets +from django_filters import rest_framework as filters +from .filters import CollectionFilter from .models import Collection, CollectionMethod, CollectionType, Flaw from .serializers import (CollectionSerializer, CollectionMethodSerializer, CollectionTypeSerializer, FlawSerializer) @@ -8,6 +10,8 @@ from .serializers import (CollectionSerializer, CollectionMethodSerializer, class CollectionViewSet(viewsets.ModelViewSet): queryset = Collection.objects.all() serializer_class = CollectionSerializer + filter_backends = (filters.DjangoFilterBackend,) + filter_class = CollectionFilter class CollectionMethodViewSet(viewsets.ModelViewSet): diff --git a/ccdb/locations/serializers.py b/ccdb/locations/serializers.py index 008e199..5729f7b 100644 --- a/ccdb/locations/serializers.py +++ b/ccdb/locations/serializers.py @@ -1,10 +1,30 @@ from rest_framework import serializers -from .models import StudyLocation +from .models import Region, Site, StudyLocation + + +class RegionSerializer(serializers.ModelSerializer): + class Meta: + model = Region + fields = ('name', 'code', 'sort_order') + + +class SiteSerializer(serializers.ModelSerializer): + included_serializers = { + 'region': 'ccdb.locations.serializers.RegionSerializer', + } + + class Meta: + model = Site + fields = ('name', 'code', 'description', 'sort_order', 'region') class StudyLocationSerializer(serializers.ModelSerializer): + included_serializers = { + 'site': 'ccdb.locations.serializers.SiteSerializer', + } + class Meta: model = StudyLocation fields = ('name', 'code', 'study_location_type', 'treatment_type', - 'collecting_location', 'description', 'sort_order') + 'collecting_location', 'description', 'sort_order', 'site') diff --git a/ccdb/locations/viewsets.py b/ccdb/locations/viewsets.py index 06d99dd..2debef3 100644 --- a/ccdb/locations/viewsets.py +++ b/ccdb/locations/viewsets.py @@ -1,7 +1,18 @@ from rest_framework import viewsets -from .models import StudyLocation -from .serializers import StudyLocationSerializer +from .models import Region, Site, StudyLocation +from .serializers import ( + RegionSerializer, SiteSerializer, StudyLocationSerializer) + + +class RegionViewSet(viewsets.ModelViewSet): + queryset = Region.objects.all() + serializer_class = RegionSerializer + + +class SiteViewSet(viewsets.ModelViewSet): + queryset = Site.objects.all() + serializer_class = SiteSerializer class StudyLocationViewSet(viewsets.ModelViewSet): diff --git a/config/settings/base.py b/config/settings/base.py index 90fa450..deab383 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -19,6 +19,7 @@ THIRD_PARTY_APPS = ( 'rest_framework.authtoken', 'corsheaders', 'djoser', + 'django_filters', ) LOCAL_APPS = ( 'ccdb.utils', @@ -43,6 +44,7 @@ MIDDLEWARE = ( 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'ccdb.api.middleware.DeBracketifyMiddleware', ) DEBUG = env.bool("DJANGO_DEBUG", False) diff --git a/requirements/base.txt b/requirements/base.txt index 5bc5f1f..05a6197 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -19,6 +19,6 @@ requests==2.11.0 # REST djangorestframework==3.6.4 django-cors-headers==1.3.1 -django-filter==1.0.4 +django-filter==1.1 djoser==0.7.0 djangorestframework-jsonapi==2.1.1