diff --git a/django/climate_change_api/climate_change_api/settings.py b/django/climate_change_api/climate_change_api/settings.py index 113e4dda..b30a1a16 100644 --- a/django/climate_change_api/climate_change_api/settings.py +++ b/django/climate_change_api/climate_change_api/settings.py @@ -70,6 +70,7 @@ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', + 'django.contrib.gis', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', diff --git a/django/climate_change_api/climate_data/admin.py b/django/climate_change_api/climate_data/admin.py new file mode 100644 index 00000000..df04cf3c --- /dev/null +++ b/django/climate_change_api/climate_data/admin.py @@ -0,0 +1,10 @@ +from django.contrib import admin + +from climate_data.models import City + + +class CityAdmin(admin.ModelAdmin): + exclude = ('_geog',) + + +admin.site.register(City, CityAdmin) diff --git a/django/climate_change_api/climate_data/migrations/0066_auto_20180627_2016.py b/django/climate_change_api/climate_data/migrations/0066_auto_20180627_2016.py new file mode 100644 index 00000000..b7a5e650 --- /dev/null +++ b/django/climate_change_api/climate_data/migrations/0066_auto_20180627_2016.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.8 on 2018-06-27 20:16 +from __future__ import unicode_literals + +import climate_data.models +import django.contrib.postgres.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('climate_data', '0065_scenario_alias'), + ] + + operations = [ + migrations.AlterModelOptions( + name='city', + options={'verbose_name_plural': 'cities'}, + ), + migrations.AddField( + model_name='city', + name='datasets', + field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('LOCA', 'LOCA'), ('NEX-GDDP', 'NEX-GDDP')], max_length=48), default=climate_data.models.get_datasets, size=2), + ), + migrations.AlterField( + model_name='climatedataset', + name='name', + field=models.CharField(choices=[('LOCA', 'LOCA'), ('NEX-GDDP', 'NEX-GDDP')], max_length=48, unique=True), + ), + ] diff --git a/django/climate_change_api/climate_data/models.py b/django/climate_change_api/climate_data/models.py index 64ae71c8..43f68d6a 100644 --- a/django/climate_change_api/climate_data/models.py +++ b/django/climate_change_api/climate_data/models.py @@ -1,6 +1,6 @@ from django.contrib.gis.db import models from django.contrib.postgres.fields.array import ArrayField -from django.core.exceptions import ObjectDoesNotExist +from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.db.models import CASCADE, SET_NULL from climate_data.geo_boundary import census @@ -16,10 +16,23 @@ def db_type(self, connection): return models.SmallIntegerField().db_type(connection=connection) +def get_datasets(): + return [ClimateDataset.Datasets.LOCA, ClimateDataset.Datasets.NEX_GDDP] + + class ClimateDataset(models.Model): """Model representing a particular climate projection dataset.""" - name = models.CharField(max_length=48, unique=True) + class Datasets: + LOCA = 'LOCA' + NEX_GDDP = 'NEX-GDDP' + + CHOICES = ( + (LOCA, LOCA), + (NEX_GDDP, NEX_GDDP), + ) + + name = models.CharField(max_length=48, unique=True, choices=Datasets.CHOICES) label = models.CharField(max_length=128, blank=True, null=True) description = models.CharField(max_length=4096, blank=True, null=True) url = models.URLField(blank=True, null=True) @@ -286,6 +299,12 @@ class City(models.Model): is_coastal = models.BooleanField(default=False) population = models.IntegerField(null=True) + datasets = ArrayField( + models.CharField(max_length=48, choices=ClimateDataset.Datasets.CHOICES), + size=2, + default=get_datasets + ) + region = models.ForeignKey(Region, on_delete=SET_NULL, null=True) objects = CityManager() @@ -296,6 +315,7 @@ def __str__(self): class Meta: unique_together = ('name', 'admin') + verbose_name_plural = 'cities' def get_map_cell(self, dataset): """Get the map cell for a given dataset for a given city. @@ -309,6 +329,11 @@ def get_map_cell(self, dataset): def natural_key(self): return (self.name, self.admin) + def clean(self): + super().clean() + if len(self.datasets) != len(set(self.datasets)): + raise ValidationError({'datasets': 'Cannot contain duplicate datasets'}) + def save(self, *args, **kwargs): """Override save to keep the geography field up to date.""" self._geog = self.geom diff --git a/django/climate_change_api/climate_data/serializers.py b/django/climate_change_api/climate_data/serializers.py index 29c51761..37afe522 100644 --- a/django/climate_change_api/climate_data/serializers.py +++ b/django/climate_change_api/climate_data/serializers.py @@ -62,11 +62,6 @@ class Meta: class CitySerializer(GeoFeatureModelSerializer): - datasets = serializers.SerializerMethodField() - - def get_datasets(self, obj): - return [map_cell.dataset.name for map_cell in obj.map_cell_set.select_related('dataset')] - proximity = serializers.SerializerMethodField() def get_proximity(self, obj): diff --git a/django/climate_change_api/climate_data/views.py b/django/climate_change_api/climate_data/views.py index ae232a1b..f09c6d43 100644 --- a/django/climate_change_api/climate_data/views.py +++ b/django/climate_change_api/climate_data/views.py @@ -155,9 +155,7 @@ def datasets(self, request, pk=None): Returns 404 if the city object has no valid map cells. """ city = self.get_object() - map_cells = ClimateDataCityCell.objects.filter(city=city) - response = [map_cell.dataset.name for map_cell in map_cells] - return Response(response, status=status.HTTP_200_OK) + return Response(city.datasets, status=status.HTTP_200_OK) class CityMapCellListView(APIView):