From 5a19fbf01c9eebb4c8103e9cf92b618a9a07dedc Mon Sep 17 00:00:00 2001 From: Bruno Martin Date: Fri, 25 May 2018 19:21:35 -0300 Subject: [PATCH] uber refactor of cities, states and countries. They now are direct relatade to Lands, Villages and Acheological sites. --- mapaguarani/core/admin.py | 17 +-- .../management/commands/set_boundaries.py | 43 +++++++ .../migrations/0040_auto_20180501_2217.py | 51 ++++++++ .../migrations/0041_auto_20180509_2132.py | 62 ++++++++++ mapaguarani/core/models.py | 108 +++++----------- mapaguarani/core/serializers.py | 115 ++++++++---------- mapaguarani/static/views/single-village.html | 12 +- 7 files changed, 254 insertions(+), 154 deletions(-) create mode 100644 mapaguarani/core/management/commands/set_boundaries.py create mode 100644 mapaguarani/core/migrations/0040_auto_20180501_2217.py create mode 100644 mapaguarani/core/migrations/0041_auto_20180509_2132.py diff --git a/mapaguarani/core/admin.py b/mapaguarani/core/admin.py index 99a4a66..60f269f 100644 --- a/mapaguarani/core/admin.py +++ b/mapaguarani/core/admin.py @@ -60,6 +60,7 @@ def get_prominent_subgroup(self, obj): class IndigenousVillageAdmin(IndigenousPlaceAdmin): # extra_js = [GMAP.api_url + GMAP.key] # map_template = 'gis/admin/google.html' + exclude = ['cities', 'states', 'country'] list_display = ('name', 'status', 'other_names', 'get_ethnic_groups', 'get_prominent_subgroup', 'population', 'get_guarani_presence', 'position_precision', 'position_source', 'geometry', @@ -114,17 +115,17 @@ def get_form(self, request, obj=None, **kwargs): form.base_fields['other_names'].help_text = """Coloque aqui todos os outros nomes pelos quais a Terra Indígena é conhecida, separados por vírgula""" form.base_fields['ethnic_groups'].help_text = 'Selecione o(s) povo(s) indígenas que habitam o local.\n' - form.base_fields['prominent_subgroup'].help_text = """Preencha apenas se a terra indígena tiver presença do + form.base_fields['prominent_subgroup'].help_text = """Preencha apenas se a terra indígena tiver presença do povo guarani, qual(is) subgrupo(s) deste povo habita(m) o local.""" - form.base_fields['public_comments'].help_text = """Acrescente aqui informações textuais adicionais relevantes - para o público amplo. Qualquer pessoa mesmo sem login + form.base_fields['public_comments'].help_text = """Acrescente aqui informações textuais adicionais relevantes + para o público amplo. Qualquer pessoa mesmo sem login poderá visualizá-las.""" - form.base_fields['private_comments'].help_text = """Acrescente aqui informações textuais adicionais relevantes - para os administradores do site, como descrições de como foi - desenhado o polígono da terra indígena, ou eventuais necessidades - futuras de revisão de dados, e etc… Essas observações só serão + form.base_fields['private_comments'].help_text = """Acrescente aqui informações textuais adicionais relevantes + para os administradores do site, como descrições de como foi + desenhado o polígono da terra indígena, ou eventuais necessidades + futuras de revisão de dados, e etc… Essas observações só serão visualizadas pelos administradores, colaboradores e editores logados.""" - form.base_fields['status'].help_text = """Você pode deixar essa terra indígena restrita, para visualização apenas + form.base_fields['status'].help_text = """Você pode deixar essa terra indígena restrita, para visualização apenas de pessoas logadas, ou pública, para visualização de qualquer visitante.""" form.base_fields['layer'].queryset = form.base_fields['layer'].queryset.filter(type__in=('generic','land')) return form diff --git a/mapaguarani/core/management/commands/set_boundaries.py b/mapaguarani/core/management/commands/set_boundaries.py new file mode 100644 index 0000000..ae551ec --- /dev/null +++ b/mapaguarani/core/management/commands/set_boundaries.py @@ -0,0 +1,43 @@ +from django.core.management.base import BaseCommand +from boundaries.models import City, State, Country +from core.models import IndigenousLand, ArchaeologicalPlace, IndigenousVillage + + +class Command(BaseCommand): + help = 'Set Cities, States and Country for Villages, Lands and ArchaeologicalPlaces' + + def set_place_boundaries(self, queryset): + + for instance in queryset: + instance.cities = City.objects.filter(geometry__covers=instance.geometry) + instance.states = State.objects.filter(geometry__covers=instance.geometry) + try: + instance.country = Country.objects.get(geometry__covers=instance.geometry) + except Country.DoesNotExist: + self.stdout.write('Place {0} is not in any country!!!'.format(instance.name)) + instance.save() + + def handle(self, *args, **options): + + self.stdout.write('Starting set villages...') + self.set_place_boundaries(IndigenousVillage.objects.all()) + self.stdout.write('Finished set villages!') + self.stdout.write('Starting set Archaeological...') + self.set_place_boundaries(ArchaeologicalPlace.objects.all()) + self.stdout.write('Finished set Archaeological!') + + self.stdout.write('Starting set lands...') + for land in IndigenousLand.objects.all(): + land.cities = City.objects.filter(geometry__intersects=land.geometry) + land.states = State.objects.filter(geometry__intersects=land.geometry) + try: + land.country = Country.objects.get(geometry__covers=land.geometry) + except Country.DoesNotExist: + self.stdout.write('Land {0} is not in any counry!!!'.format(land.name)) + land.save() + self.stdout.write('Finished set lands!') + + self.stdout.write('\n') + self.stdout.write( + 'Cities, States and Country for Villages, Lands and ArchaeologicalPlaces succesfull set!!!') + self.stdout.write('\n') diff --git a/mapaguarani/core/migrations/0040_auto_20180501_2217.py b/mapaguarani/core/migrations/0040_auto_20180501_2217.py new file mode 100644 index 0000000..ae5a931 --- /dev/null +++ b/mapaguarani/core/migrations/0040_auto_20180501_2217.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2018-05-01 22:17 +from __future__ import unicode_literals + +import django.contrib.gis.db.models.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0039_auto_20180412_1241'), + ] + + operations = [ + migrations.AlterField( + model_name='indigenousland', + name='documents', + field=models.ManyToManyField(blank=True, help_text='Acrescente a documentação oficial sobre a terra indígena (decretos de homologação, portarias declaratórias,etc.).\n Caso o mesmo documento se refira a mais de uma terra indígena, ele pode já estar cadastrado e você pode apenas selecioná-lo.\n Confira na lista antes de adicionar. ', related_name='indigenousland_documentation', to='core.Document', verbose_name='documentation'), + ), + migrations.AlterField( + model_name='indigenousland', + name='geometry', + field=django.contrib.gis.db.models.fields.MultiPolygonField(help_text='Inclua aqui o polígono da terra indígena apenas em formato *.KML.\n Certifique-se de que apenas a terra indígena correspondente está no arquivo. ', srid=4326, verbose_name='Indigenous Land Spatial Data'), + ), + migrations.AlterField( + model_name='indigenousland', + name='guarani_exclusive_possession_area_portion', + field=models.FloatField(blank=True, help_text='Em caso de terras ainda em processo de regularização, caso tenha informação de qual porção da área já foi desintrusada incluir.\n Em áreas em que não se iniciou o processo de desintrusão colocar 0.', null=True, verbose_name='Guarani full and exclusive portion area possession'), + ), + migrations.AlterField( + model_name='indigenousland', + name='others_exclusive_possession_area_portion', + field=models.FloatField(blank=True, help_text='Em caso de terras ainda em processo de regularização, caso tenha informação de qual porção da área já foi desintrusada incluir.\n Em áreas em que não se iniciou o processo de desintrusão colocar 0. ', null=True, verbose_name="Other peoples' full and exclusive portion area possession"), + ), + migrations.AlterField( + model_name='indigenousland', + name='prominent_subgroup', + field=models.ManyToManyField(blank=True, related_name='indigenousland_prominent_subgroup_layers', to='core.ProminentEthnicSubGroup', verbose_name='Guarani ethnic sub-group'), + ), + migrations.AlterField( + model_name='indigenousvillage', + name='geometry', + field=django.contrib.gis.db.models.fields.PointField(help_text='Localize o ponto da aldeia.\n Você pode incluir as coordenadas geográficas (em graus decimais) ou\n localizar o ponto olhando o mapa ou a foto aérea do Google.', srid=4326, verbose_name='Geometry'), + ), + migrations.AlterField( + model_name='indigenousvillage', + name='prominent_subgroup', + field=models.ManyToManyField(blank=True, related_name='indigenousvillage_prominent_subgroup_layers', to='core.ProminentEthnicSubGroup', verbose_name='Guarani ethnic sub-group'), + ), + ] diff --git a/mapaguarani/core/migrations/0041_auto_20180509_2132.py b/mapaguarani/core/migrations/0041_auto_20180509_2132.py new file mode 100644 index 0000000..c307e3c --- /dev/null +++ b/mapaguarani/core/migrations/0041_auto_20180509_2132.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2018-05-09 21:32 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('boundaries', '0005_auto_20180501_2240'), + ('core', '0040_auto_20180501_2217'), + ] + + operations = [ + migrations.AddField( + model_name='archaeologicalplace', + name='cities', + field=models.ManyToManyField(blank=True, related_name='archaeologicalplace_ethnic_groups_layers', to='boundaries.City', verbose_name='Cities'), + ), + migrations.AddField( + model_name='archaeologicalplace', + name='country', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='archaeologicalplace_ethnic_groups_layers', to='boundaries.Country', verbose_name='Country'), + ), + migrations.AddField( + model_name='archaeologicalplace', + name='states', + field=models.ManyToManyField(blank=True, related_name='archaeologicalplace_ethnic_groups_layers', to='boundaries.State', verbose_name='States'), + ), + migrations.AddField( + model_name='indigenousland', + name='cities', + field=models.ManyToManyField(blank=True, related_name='indigenousland_ethnic_groups_layers', to='boundaries.City', verbose_name='Cities'), + ), + migrations.AddField( + model_name='indigenousland', + name='country', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='indigenousland_ethnic_groups_layers', to='boundaries.Country', verbose_name='Country'), + ), + migrations.AddField( + model_name='indigenousland', + name='states', + field=models.ManyToManyField(blank=True, related_name='indigenousland_ethnic_groups_layers', to='boundaries.State', verbose_name='States'), + ), + migrations.AddField( + model_name='indigenousvillage', + name='cities', + field=models.ManyToManyField(blank=True, related_name='indigenousvillage_ethnic_groups_layers', to='boundaries.City', verbose_name='Cities'), + ), + migrations.AddField( + model_name='indigenousvillage', + name='country', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='indigenousvillage_ethnic_groups_layers', to='boundaries.Country', verbose_name='Country'), + ), + migrations.AddField( + model_name='indigenousvillage', + name='states', + field=models.ManyToManyField(blank=True, related_name='indigenousvillage_ethnic_groups_layers', to='boundaries.State', verbose_name='States'), + ), + ] diff --git a/mapaguarani/core/models.py b/mapaguarani/core/models.py index a002b65..6394276 100644 --- a/mapaguarani/core/models.py +++ b/mapaguarani/core/models.py @@ -255,6 +255,32 @@ def __str__(self): return self.name +class AdministrativeBoundaries(models.Model): + + country = models.ForeignKey( + Country, + verbose_name=_('Country'), + related_name='%(class)s_ethnic_groups_layers', + blank=True, + null=True + ) + states = models.ManyToManyField( + State, + verbose_name=_('States'), + related_name='%(class)s_ethnic_groups_layers', + blank=True + ) + cities = models.ManyToManyField( + City, + verbose_name=_('Cities'), + related_name='%(class)s_ethnic_groups_layers', + blank=True + ) + + class Meta: + abstract = True + + class IndigenousPlace(models.Model): STATUS = ( @@ -293,12 +319,7 @@ def __str__(self): return self.name -class IndigenousVillage(IndigenousPlace): - - # def __init__(self, *args, **kwargs): - # super().__init__(*args, **kwargs) - # self._meta.get_field('name').help_text="""Coloque aqui o nome pelo qual a própria comunidade reconhece a aldeia, sempre - # com primeira letra maiúscula e as demais minúsculas""" +class IndigenousVillage(IndigenousPlace, AdministrativeBoundaries): POSITION_PRECISION = ( ('exact', _('Exact')), @@ -351,32 +372,6 @@ def land(self): def protected_areas(self): return BaseProtectedArea.objects.filter(geometry__covers=self.geometry) - @property - def city(self): - try: - return City.objects.get(geometry__covers=self.geometry) - except City.DoesNotExist: - return - - @property - def state(self): - try: - return State.objects.get(geometry__covers=self.geometry) - except State.DoesNotExist: - return - except State.MultipleObjectsReturned: - return State.objects.filter(geometry__covers=self.geometry).first() - - @property - def country(self): - try: - return Country.objects.get(geometry__covers=self.geometry) - except Country.DoesNotExist: - return - except Country.MultipleObjectsReturned: - # import ipdb;ipdb.set_trace() - return - @property def layer_projects(self): return self.layer.projects @@ -465,7 +460,7 @@ def __str__(self): return self.name -class IndigenousLand(IndigenousPlace): +class IndigenousLand(AdministrativeBoundaries, IndigenousPlace): documents = models.ManyToManyField( Document, @@ -582,17 +577,6 @@ def get_cities_intersected(self): def get_states_intersected(self): return State.objects.filter(geometry__intersects=self.geometry) - @property - def country(self): - try: - return Country.objects.get(geometry__covers=self.geometry) - except Country.DoesNotExist: - return - except Country.MultipleObjectsReturned: - # countries = Country.objects.filter(geometry__covers=self.geometry) - # import ipdb;ipdb.set_trace() - return - @property def layer_projects(self): return self.layer.projects @@ -618,7 +602,7 @@ def __str__(self): return self.name -class ArchaeologicalPlace(models.Model): +class ArchaeologicalPlace(AdministrativeBoundaries): POSITION_PRECISION_CHOICES = ( ('exact', _('Exact')), ('approximate', _('Approximate')), @@ -667,44 +651,10 @@ class Meta: verbose_name = _('Archaeological Place') verbose_name_plural = _('Archaeological Places') - # def has_change_permission(self, request, obj=None): - # eita = super().has_change_permission(request, obj) - # raise Exception('PARATUDO') - - # def clean(self): - # if not rules.has_perm('core.add_archaeologicalplace', self.request.user, self.obj): - # raise ValidationError('User does not have permission to add model') - # pass - @property def protected_areas(self): return BaseProtectedArea.objects.filter(geometry__covers=self.geometry) - @property - def city(self): - try: - return City.objects.get(geometry__covers=self.geometry) - except City.DoesNotExist: - return - - @property - def state(self): - try: - return State.objects.get(geometry__covers=self.geometry) - except State.DoesNotExist: - return - - @property - def country(self): - try: - return Country.objects.get(geometry__covers=self.geometry) - except Country.DoesNotExist: - return - except Country.MultipleObjectsReturned: - # countries = Country.objects.filter(geometry__covers=self.geometry) - # import ipdb;ipdb.set_trace() - return - @property def land(self): return IndigenousLand.objects.filter(geometry__covers=self.geometry) diff --git a/mapaguarani/core/serializers.py b/mapaguarani/core/serializers.py index 8a85718..0322d20 100644 --- a/mapaguarani/core/serializers.py +++ b/mapaguarani/core/serializers.py @@ -96,7 +96,7 @@ def update(self, instance, validated_data): class ListIndigenousVillageSerializer(BaseListSerializerMixin): exclude_field = ['land', 'population', 'protected_areas_integral', 'protected_areas_conservation', - 'city', 'state', 'country', 'projects', 'layer_projects', ] + 'cities', 'states', 'country', 'projects', 'layer_projects', ] class IndigenousLandListSerializer(BaseListSerializerMixin): @@ -111,43 +111,16 @@ class IndigenousLandListSerializer(BaseListSerializerMixin): class ListArchaeologicalSiteSerializer(BaseListSerializerMixin): exclude_field = ['land', 'protected_areas_integral', 'protected_areas_conservation', - 'city', 'state', 'country', 'projects', 'layer_projects', ] + 'cities', 'states', 'country', 'projects', 'layer_projects', ] -class BasePointMixinSerializer(serializers.ModelSerializer): - - city = serializers.SerializerMethodField() - state = serializers.SerializerMethodField() - country = serializers.SerializerMethodField() - land = serializers.SerializerMethodField() - projects = SimpleProjectSerializer(many=True) - - @staticmethod - def get_city(obj): - if obj.city: - return obj.city.name - - @staticmethod - def get_state(obj): - if obj.state: - return obj.state.name or obj.state.acronym - - @staticmethod - def get_country(obj): - if obj.country: - return obj.country.name - - @staticmethod - def get_land(obj): - if obj.land: - land = obj.land[0] - return SimpleIndigenousLandSerializer(land).data - class GeoBaseMixinSerializer(serializers.ModelSerializer): protected_areas_integral = serializers.SerializerMethodField() protected_areas_conservation = serializers.SerializerMethodField() layer_projects = serializers.SerializerMethodField() + country = serializers.SerializerMethodField() + projects = SimpleProjectSerializer(many=True) @staticmethod def get_protected_areas_integral(obj): @@ -164,8 +137,28 @@ def get_layer_projects(obj): if obj.layer_projects: return SimpleProjectSerializer(obj.layer_projects, many=True).data + @staticmethod + def get_country(obj): + if obj.country: + return obj.country.name + + +class PlaceExportSerializer(serializers.ModelSerializer): + + cities = serializers.SerializerMethodField() + states = serializers.SerializerMethodField() + layer = serializers.SerializerMethodField() + + @staticmethod + def get_cities(obj): + if obj.cities: + return ', '.join([city.name for city in obj.cities.all()]) + + @staticmethod + def get_states(obj): + if obj.states: + return ', '.join([state.name for state in obj.states.all()]) -class PlaceExportSerializer(object): @staticmethod def get_layer(obj): if obj.layer: @@ -180,7 +173,6 @@ class IndigenousPlaceExportSerializer(PlaceExportSerializer): ethnic_groups = serializers.SerializerMethodField() prominent_subgroup = serializers.SerializerMethodField() - layer = serializers.SerializerMethodField() @staticmethod def get_ethnic_groups(obj): @@ -192,13 +184,13 @@ def get_prominent_subgroup(obj): class IndigenousVillageSerializer(FieldPermissionSerializerMixin, - GeoBaseMixinSerializer, - BasePointMixinSerializer): + GeoBaseMixinSerializer): position_precision = serializers.SerializerMethodField() population = serializers.SerializerMethodField() guarani_presence = serializers.SerializerMethodField() projects = SimpleProjectSerializer(many=True) + land = serializers.SerializerMethodField() # Private fields private_comments = fields.ReadOnlyField(permission_classes=(IsAuthenticated(), )) @@ -231,9 +223,15 @@ def get_guarani_presence(obj): return GuaraniPresenceSerializer(presence).data + # @staticmethod + # def get_villages(obj): + # return SimpleIndigenousVillageSerializer(obj.villages, many=True).data + @staticmethod - def get_villages(obj): - return SimpleIndigenousVillageSerializer(obj.villages, many=True).data + def get_land(obj): + if obj.land: + land = obj.land[0] + return SimpleIndigenousLandSerializer(land).data class IndigenousVillageCachedSerializer(IndigenousVillageSerializer, @@ -280,7 +278,7 @@ class Meta: # only the id field is excluded fields = ['id', 'name', 'other_names', 'land', 'guarani_presence', 'population', 'ethnic_groups', 'prominent_subgroup', - 'city', 'state', 'country', + 'cities', 'states', 'country', 'position_precision', 'public_comments', 'private_comments', 'layer', 'latitude', 'longitude'] @@ -335,7 +333,7 @@ class Meta: # only the id field is excluded fields = ['name', 'other_names', 'land', 'guarani_presence', 'population', 'ethnic_groups', 'prominent_subgroup', - 'city', 'state', 'country', + 'cities', 'states', 'country', 'position_precision', 'public_comments', 'private_comments', 'layer'] @@ -614,9 +612,10 @@ def get_land_tenure_status_dashed_border(obj): cache_registry.register(IndigenousLandProtobufSerializer) -class ArchaeologicalPlaceSerializer(GeoBaseMixinSerializer, BasePointMixinSerializer): +class ArchaeologicalPlaceSerializer(GeoBaseMixinSerializer): position_precision = serializers.SerializerMethodField() + land = serializers.SerializerMethodField() @staticmethod def get_position_precision(obj): @@ -630,8 +629,15 @@ class Meta: depth = 1 fields = '__all__' + @staticmethod + def get_land(obj): + if obj.land: + land = obj.land[0] + return SimpleIndigenousLandSerializer(land).data + -class ArchaeologicalPlaceExportSerializer(serializers.ModelSerializer): +class ArchaeologicalPlaceExportSerializer(PlaceExportSerializer, + ArchaeologicalPlaceSerializer): def get_latitude(self, obj): if obj.geometry: return obj.geometry.get_y() @@ -668,37 +674,24 @@ class Meta: 'dating_method', 'lab_code', 'latitude', - 'longitude') + 'longitude', + 'cities', + 'country') class ArchaeologicalPlaceGeojsonSerializer(PlaceExportSerializer, + GeoBaseMixinSerializer, GeoFeatureModelSerializer, CachedSerializerMixin): - city_name = serializers.SerializerMethodField() - country_name = serializers.SerializerMethodField() - - def get_city_name(self, obj): - if obj.city: - return obj.city.name - else: - return None - - def get_country_name(self, obj): - if obj.country: - return obj.country.name - else: - return None - class Meta: model = ArchaeologicalPlace geo_field = 'geometry' - fields = [#'id', - 'ap_date', + fields = ['ap_date', 'biblio_references', 'calibrated_dating', - 'city_name', - 'country_name', + 'cities', + 'country', 'dating', 'dating_method', 'name'] diff --git a/mapaguarani/static/views/single-village.html b/mapaguarani/static/views/single-village.html index 1509bfe..f3e35d3 100644 --- a/mapaguarani/static/views/single-village.html +++ b/mapaguarani/static/views/single-village.html @@ -76,13 +76,13 @@

{{data.name}}

Fonte da localização {{data.position_source}} - - Município - {{data.city}} + + {{city.label}} + {{city.name}} - - Estado - {{data.state}} + + {{state.label}} + {{state.name}} País