From 35aa9cbe70ffecb3c3c6a041809eb6878328c858 Mon Sep 17 00:00:00 2001 From: Dana Lambert Date: Mon, 8 Nov 2021 17:00:04 +1300 Subject: [PATCH] Create csv download endpoint --- backend/right_tree/api/csv_utils.py | 130 +++++++++++++++++++++ backend/right_tree/api/views.py | 23 +++- backend/right_tree/urls.py | 1 + frontend/src/repository/PlantRepository.js | 4 + 4 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 backend/right_tree/api/csv_utils.py diff --git a/backend/right_tree/api/csv_utils.py b/backend/right_tree/api/csv_utils.py new file mode 100644 index 0000000..266be6a --- /dev/null +++ b/backend/right_tree/api/csv_utils.py @@ -0,0 +1,130 @@ +import csv +from pathlib import Path + +import right_tree.api.data +from .filters import * +from .utils import get_address_from_coordinates, get_point_from_coordinates + + +CSV_FILENAME = 'plants.csv' +HEADER_FIELDS = ['Names', 'Growth form/max height (m)/spacing (m)', 'Preferred moisture regime', + 'Tolerances (Water / Drought / Frost / Salinity)', 'Ecosystem services', 'Carbon Sequestration Rate', 'Planting Stage'] + + +def get_plant_csv_filepath(): + """ Retrives the filepath for the plant csv file. + """ + return Path(right_tree.api.data.__file__).resolve().parent / 'resources' / CSV_FILENAME + + +def get_location_filters(request): + """ Retrives the selected location data from the request. + """ + filter_rows = [['LOCATION FILTERS:']] + coordinates = request.query_params.get('coordinates') + + if coordinates is not None: + print('coords not none') + eco_district_layer = ecological_district_coordinate_filter( + coordinates).first() + print(eco_district_layer) + point = get_point_from_coordinates(coordinates) + + filter_rows.append(['Point coordinates:', point]) + filter_rows.append( + ['Ecological region:', eco_district_layer.ecologic_1 or '']) + filter_rows.append( + ['Ecological district:', eco_district_layer.ecologic_2 or '']) + filter_rows.append( + ['Property address:', get_address_from_coordinates(coordinates) or '']) + else: + filter_rows.append(["None specified"]) + + return filter_rows + + +def get_soil_filters(request): + """ Retrives the selected soil type data from the request. + """ + filter_rows = [['SOIL FILTERS:']] + soil_variant = request.query_params.get('soilVariant') + coordinates = request.query_params.get('coordinates') + + if soil_variant is not None and coordinates is not None: + soil_order_obj = soil_order_coordinate_filter(coordinates).first() + + filter_rows.append( + ['Soil Order:', f"{soil_order_obj.name or ''} ({soil_order_obj.code or ''})"]) + filter_rows.append(['Soil Variant:', soil_variant]) + else: + filter_rows.append(["None specified"]) + + return filter_rows + + +def get_site_filters(request): + """ Retrives the selected site data from the request. + """ + filter_rows = [['SITE FILTERS:']] + + habitat = request.query_params.get('habitat') + zone = request.query_params.get('zone') + if zone is not None and habitat is not None: + habitat_json = json.loads(habitat) + zone_json = json.loads(zone) + + filter_rows.append(['Habitat:', habitat_json.get("name", "")]) + filter_rows.append(['Zone Name:', zone_json.get("name", "")]) + filter_rows.append(['Zone Variant:', zone_json.get("variant", "")]) + filter_rows.append( + ['Zone Refined Variant:', zone_json.get("refined_variant", "")]) + else: + filter_rows.append(["None specified"]) + + return filter_rows + + +def get_filter_values(request): + """ Retrives all selected values/filters from the request. + """ + filter_rows = [] + + # Add all the location filters + filter_rows += get_location_filters(request) + filter_rows.append(['']) + + # Add the soil filters + filter_rows += get_soil_filters(request) + filter_rows.append(['']) + + # Add the project site filters + filter_rows += get_site_filters(request) + filter_rows.append(['']) + + return filter_rows + + +def create_plant_csv_file(request, plant_data): + """ Constructs a csv file that contains selected filter values and the resulting plant list. + """ + with open(get_plant_csv_filepath(), 'w', encoding='UTF8') as f: + writer = csv.writer(f) + + # Write filter/selected values + for filter_row in get_filter_values(request): + writer.writerow(filter_row) + + # Write the plant data + writer.writerow(HEADER_FIELDS) + for plant in plant_data: + plant_data_row = [ + plant.display_name, + plant.display_growth_form, + plant.moisture_preferences, + plant.plant_tolerances, + plant.ecosystem_services, + plant.carbon_sequestration, + plant.stage + ] + + writer.writerow(plant_data_row) diff --git a/backend/right_tree/api/views.py b/backend/right_tree/api/views.py index c318f39..80521c9 100644 --- a/backend/right_tree/api/views.py +++ b/backend/right_tree/api/views.py @@ -1,8 +1,4 @@ -import json - -from django.contrib.gis.geos import Point -from django.contrib.gis.db import models -from django.http import HttpResponseBadRequest +from django.http import HttpResponseBadRequest, HttpResponse, HttpRequest from django.shortcuts import get_object_or_404 from rest_framework import viewsets @@ -13,6 +9,7 @@ from right_tree.api.serializers import HabitatImageSerializer, HabitatSerializer from .filters import * from .utils import get_address_from_coordinates +from .csv_utils import create_plant_csv_file, get_plant_csv_filepath class PlantViewSet(viewsets.ModelViewSet): @@ -104,3 +101,19 @@ class HabitatImageViewSet(viewsets.ViewSet): habitat_image = get_object_or_404(queryset, pk=pk) serializer = HabitatImageSerializer(habitat_image) return Response(serializer.data) + + +class CSVDownloadView(viewsets.ViewSet): + + def list(self, request, *args, **kwargs): + filtered_plants = Plant.objects.all() + filtered_plants = coordinate_filter(request, filtered_plants) + filtered_plants = soil_variant_filter(request, filtered_plants) + filtered_plants = zone_filter(request, filtered_plants) + + create_plant_csv_file(request, filtered_plants) + + csv_file = open(get_plant_csv_filepath(), 'rb') + response = HttpResponse(csv_file, content_type='text/csv') + response['Content-Disposition'] = 'attachment; filename="test.csv"' + return response diff --git a/backend/right_tree/urls.py b/backend/right_tree/urls.py index ebc0365..1c421ba 100644 --- a/backend/right_tree/urls.py +++ b/backend/right_tree/urls.py @@ -26,6 +26,7 @@ router.register(r'ecologicaldistrict', views.EcologicalDistrictViewSet, basename router.register(r'address', views.LINZPropertyViewSet, basename='address') router.register(r'habitats', views.HabitatViewSet, basename='habitats') router.register(r'habitatimage', views.HabitatImageViewSet,basename='habitatimage') +router.register(r'downloadcsv', views.CSVDownloadView ,basename='downloadcsv') urlpatterns = [ path('admin/', admin.site.urls), diff --git a/frontend/src/repository/PlantRepository.js b/frontend/src/repository/PlantRepository.js index a39ec09..17ee954 100644 --- a/frontend/src/repository/PlantRepository.js +++ b/frontend/src/repository/PlantRepository.js @@ -4,6 +4,10 @@ const PlantRepository = { getFilteredPlants(filters) { return Repository.get(`/plants/`, { params: filters }); + }, + + getPlantsCSV(filters) { + return Repository.get('/downloadcsv/', { params: filters }) } }