From 7f60ddf1a6fb4adca68c259f2f59f08c20b27730 Mon Sep 17 00:00:00 2001 From: LePetitTim Date: Wed, 1 Jun 2022 17:43:08 +0200 Subject: [PATCH 1/7] Add filter geometries --- geotrek/api/v2/functions.py | 7 ---- geotrek/api/v2/views/sensitivity.py | 3 +- geotrek/common/functions.py | 7 +++- geotrek/core/filters.py | 27 +++++++++++-- geotrek/core/models.py | 4 ++ geotrek/core/tests/test_filters.py | 62 +++++++++++++++++++++-------- geotrek/infrastructure/models.py | 2 + geotrek/land/models.py | 10 +++++ geotrek/maintenance/models.py | 2 + geotrek/sensitivity/views.py | 3 +- geotrek/signage/models.py | 2 + geotrek/trekking/models.py | 4 ++ 12 files changed, 103 insertions(+), 30 deletions(-) diff --git a/geotrek/api/v2/functions.py b/geotrek/api/v2/functions.py index ca648deabe..1e0c5fa39c 100644 --- a/geotrek/api/v2/functions.py +++ b/geotrek/api/v2/functions.py @@ -11,13 +11,6 @@ def Buffer(geom, radius, num_seg): return Func(geom, radius, num_seg, function='ST_Buffer', output_field=GeometryField()) -def GeometryType(geom): - """ - GeometryType postgis function - """ - return Func(geom, function='GeometryType', output_field=CharField()) - - class Length3D(Func): """ ST_3DLENGTH postgis function diff --git a/geotrek/api/v2/views/sensitivity.py b/geotrek/api/v2/views/sensitivity.py index f88befd22a..17e1630696 100644 --- a/geotrek/api/v2/views/sensitivity.py +++ b/geotrek/api/v2/views/sensitivity.py @@ -5,7 +5,8 @@ from geotrek.api.v2 import serializers as api_serializers, \ viewsets as api_viewsets -from geotrek.api.v2.functions import Buffer, GeometryType, Area +from geotrek.api.v2.functions import Buffer, Area +from geotrek.common.functions import GeometryType from geotrek.sensitivity import models as sensitivity_models from ..filters import GeotrekQueryParamsFilter, GeotrekQueryParamsDimensionFilter, GeotrekInBBoxFilter, GeotrekSensitiveAreaFilter, NearbyContentFilter, UpdateOrCreateDateFilter diff --git a/geotrek/common/functions.py b/geotrek/common/functions.py index 5bd3d5519f..4a040e0f67 100644 --- a/geotrek/common/functions.py +++ b/geotrek/common/functions.py @@ -1,7 +1,12 @@ from django.contrib.gis.db.models.functions import GeoFunc -from django.db.models import FloatField +from django.db.models import CharField, FloatField class Length(GeoFunc): """ ST_Length postgis function """ output_field = FloatField() + + +class GeometryType(GeoFunc): + """ ST_GeometryType postgis function """ + output_field = CharField() diff --git a/geotrek/core/filters.py b/geotrek/core/filters.py index debf1b1331..22fd418d05 100644 --- a/geotrek/core/filters.py +++ b/geotrek/core/filters.py @@ -8,22 +8,41 @@ from geotrek.altimetry.filters import AltimetryAllGeometriesFilterSet from geotrek.authent.filters import StructureRelatedFilterSet from geotrek.common.filters import RightFilter +from geotrek.common.functions import GeometryType from geotrek.maintenance import models as maintenance_models from geotrek.maintenance.filters import InterventionFilterSet, ProjectFilterSet from geotrek.zoning.filters import ZoningFilterSet class ValidTopologyFilterSet(FilterSet): - is_valid = BooleanFilter(label=_("Valid topology"), method='filter_valid_topology') + # Do not forget to add geometry_types_allowed on models if you add this filterset + # geometry_types_allowed = ["ST_LineString"] for example + # Types possible with topologies are linestring and points only + + if settings.TREKKING_TOPOLOGY_ENABLED: + is_valid_topology = BooleanFilter(label=_("Valid topology"), method='filter_valid_topology') + is_valid_geometry = BooleanFilter(label=_("Valid geometry"), method='filter_valid_geometry') def filter_valid_topology(self, qs, name, value): if value is not None: - qs = qs.annotate(distinct_same_order=Count('aggregations__order', distinct=True), + qs = qs.annotate(number_aggregations=Count('aggregations'), + distinct_same_order=Count('aggregations__order', distinct=True), same_order=Count('aggregations__order')) if value is True: - qs = qs.filter(geom__isvalid=True).exclude(geom__isnull=True).exclude(geom__isempty=True).filter(same_order=F('distinct_same_order')) + qs = qs.filter(number_aggregations__gt=0, same_order=F('distinct_same_order')) + elif value is False: + qs = qs.filter(Q(number_aggregations=0) | Q(distinct_same_order__lt=F('same_order'))) + return qs + + def filter_valid_geometry(self, qs, name, value): + if value is not None: + qs = qs.annotate(geometry_type=GeometryType('geom')) + if value is True: + qs = qs.filter(geom__isvalid=True).exclude(geom__isnull=True).exclude(geom__isempty=True).filter( + geometry_type__in=qs.model.geometry_types_allowed) elif value is False: - qs = qs.filter(Q(geom__isnull=True) | Q(geom__isvalid=False) | Q(geom__isempty=True) | Q(distinct_same_order__lt=F('same_order'))) + qs = qs.filter(Q(geom__isnull=True) | Q(geom__isvalid=False) | Q(geom__isempty=True) | ~Q( + geometry_type__in=qs.model.geometry_types_allowed)) return qs diff --git a/geotrek/core/models.py b/geotrek/core/models.py index 021073c081..cd14b0d498 100644 --- a/geotrek/core/models.py +++ b/geotrek/core/models.py @@ -387,6 +387,8 @@ class Topology(ZoningPropertiesMixin, AddPropertyMixin, AltimetryMixin, """ Fake srid attribute, that prevents transform() calls when using Django map widgets. """ srid = settings.API_SRID + geometry_types_allowed = ["ST_LineString", "ST_Point"] + class Meta: verbose_name = _("Topology") verbose_name_plural = _("Topologies") @@ -946,6 +948,8 @@ class Trail(MapEntityMixin, Topology, StructureRelated): comments = models.TextField(default="", blank=True, verbose_name=_("Comments")) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) + geometry_types_allowed = ["ST_LineString"] + class Meta: verbose_name = _("Trail") verbose_name_plural = _("Trails") diff --git a/geotrek/core/tests/test_filters.py b/geotrek/core/tests/test_filters.py index 3f45f33d57..e8a4e77c13 100644 --- a/geotrek/core/tests/test_filters.py +++ b/geotrek/core/tests/test_filters.py @@ -49,28 +49,25 @@ def test_trail_filters(self): self.assertEqual(qs.count(), 1) +@skipIf(not settings.TREKKING_TOPOLOGY_ENABLED, 'Test with dynamic segmentation only') class ValidTopologyFilterTest(TestCase): @classmethod def setUpTestData(cls): - if settings.TREKKING_TOPOLOGY_ENABLED: - cls.path = PathFactory() - cls.trek = TrekFactory.create(name="Crossed", paths=[(cls.path, 0, 1)]) - else: - cls.trek = TrekFactory.create(geom=LineString((0, 0), (5, 5))) + cls.path = PathFactory() + cls.trek = TrekFactory.create(name="Crossed", paths=[(cls.path, 0, 1)]) - @skipIf(not settings.TREKKING_TOPOLOGY_ENABLED, 'Test with dynamic segmentation only') def test_trek_filters_not_valid(self): trek = TrekFactory.create(name="Not crossed", paths=[(self.path, 0, 0.5)]) TrekFactory.create(paths=[]) qs = TrekFilterSet().qs self.assertEqual(qs.count(), 3) - data = {'is_valid': True} + data = {'is_valid_topology': True} qs = TrekFilterSet(data=data).qs self.assertIn(self.trek, qs) self.assertEqual(qs.count(), 2) - data = {'is_valid': False} + data = {'is_valid_topology': False} qs = TrekFilterSet(data=data).qs self.assertEqual(qs.count(), 1) @@ -78,29 +75,62 @@ def test_trek_filters_not_valid(self): PathFactory.create(geom=geom) self.trek.reload() trek.reload() - data = {'is_valid': True} + data = {'is_valid_topology': True} qs = TrekFilterSet(data=data).qs self.assertNotIn(self.trek, qs) self.assertIn(trek, qs) self.assertEqual(qs.count(), 1) - data = {'is_valid': False} + data = {'is_valid_topology': False} qs = TrekFilterSet(data=data).qs self.assertIn(self.trek, qs) self.assertNotIn(trek, qs) self.assertEqual(qs.count(), 2) - @skipIf(settings.TREKKING_TOPOLOGY_ENABLED, 'Test without dynamic segmentation only') - def test_trek_filters_not_valid_nds(self): - TrekFactory.create(name="Empty", geom='SRID=2154;LINESTRING EMPTY') + +@skipIf(not settings.TREKKING_TOPOLOGY_ENABLED, 'Test with dynamic segmentation only') +class ValidGeometryFilterTest(TestCase): + @classmethod + def setUpTestData(cls): + cls.path = PathFactory() + + def test_trek_filters_not_valid_geometry(self): + trek_linestring = TrekFactory.create(name="LineString", paths=[(self.path, 0, 1)]) + trek_multilinestring = TrekFactory.create(name="Multilinestring", paths=[(self.path, 0, 0.4, 1), + (self.path, 0.6, 1, 2)]) + trek_point = TrekFactory.create(name="Point", paths=[(self.path, 0, 0)]) + trek_none = TrekFactory.create(name="None", paths=[]) + + qs = TrekFilterSet().qs + self.assertEqual(qs.count(), 4) + + data = {'is_valid_geometry': True} + qs = TrekFilterSet(data=data).qs + self.assertIn(trek_linestring, qs) + self.assertEqual(qs.count(), 1) + + data = {'is_valid_geometry': False} + qs = TrekFilterSet(data=data).qs + self.assertIn(trek_multilinestring, qs) + self.assertIn(trek_point, qs) + self.assertIn(trek_none, qs) + self.assertEqual(qs.count(), 3) + + +@skipIf(settings.TREKKING_TOPOLOGY_ENABLED, 'Test without dynamic segmentation only') +class ValidGeometryFilterNDSTest(TestCase): + def test_trek_filters_not_valid_geometry_nds(self): + trek_empty = TrekFactory.create(name="Empty", geom='SRID=2154;LINESTRING EMPTY') + trek_valid = TrekFactory.create(name="Valid", geom=LineString((0, 0), (5, 5))) qs = TrekFilterSet().qs self.assertEqual(qs.count(), 2) - data = {'is_valid': True} + data = {'is_valid_geometry': True} qs = TrekFilterSet(data=data).qs - self.assertIn(self.trek, qs) + self.assertIn(trek_valid, qs) self.assertEqual(qs.count(), 1) - data = {'is_valid': False} + data = {'is_valid_geometry': False} qs = TrekFilterSet(data=data).qs + self.assertIn(trek_empty, qs) self.assertEqual(qs.count(), 1) diff --git a/geotrek/infrastructure/models.py b/geotrek/infrastructure/models.py index 138b220b10..f5b37b6960 100755 --- a/geotrek/infrastructure/models.py +++ b/geotrek/infrastructure/models.py @@ -167,6 +167,8 @@ class Infrastructure(MapEntityMixin, BaseInfrastructure): related_name='infrastructures_set') accessibility = models.TextField(verbose_name=_("Accessibility"), blank=True) + geometry_types_allowed = ["ST_LineString", "ST_Point"] + class Meta: verbose_name = _("Infrastructure") verbose_name_plural = _("Infrastructures") diff --git a/geotrek/land/models.py b/geotrek/land/models.py index 514a111e6f..e30dd8ee80 100644 --- a/geotrek/land/models.py +++ b/geotrek/land/models.py @@ -43,6 +43,8 @@ class PhysicalEdge(MapEntityMixin, Topology): on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) + geometry_types_allowed = ["ST_LineString"] + class Meta: verbose_name = _("Physical edge") verbose_name_plural = _("Physical edges") @@ -109,6 +111,8 @@ class LandEdge(MapEntityMixin, Topology): agreement = models.BooleanField(verbose_name=_("Agreement"), default=False) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) + geometry_types_allowed = ["ST_LineString"] + class Meta: verbose_name = _("Land edge") verbose_name_plural = _("Land edges") @@ -158,6 +162,8 @@ class CompetenceEdge(MapEntityMixin, Topology): organization = models.ForeignKey(Organism, verbose_name=_("Organism"), on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) + geometry_types_allowed = ["ST_LineString"] + class Meta: verbose_name = _("Competence edge") verbose_name_plural = _("Competence edges") @@ -207,6 +213,8 @@ class WorkManagementEdge(MapEntityMixin, Topology): organization = models.ForeignKey(Organism, verbose_name=_("Organism"), on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) + geometry_types_allowed = ["ST_LineString"] + class Meta: verbose_name = _("Work management edge") verbose_name_plural = _("Work management edges") @@ -256,6 +264,8 @@ class SignageManagementEdge(MapEntityMixin, Topology): organization = models.ForeignKey(Organism, verbose_name=_("Organism"), on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) + geometry_types_allowed = ["ST_LineString"] + class Meta: verbose_name = _("Signage management edge") verbose_name_plural = _("Signage management edges") diff --git a/geotrek/maintenance/models.py b/geotrek/maintenance/models.py index 627f7b4d62..2954238071 100755 --- a/geotrek/maintenance/models.py +++ b/geotrek/maintenance/models.py @@ -75,6 +75,8 @@ class Intervention(ZoningPropertiesMixin, AddPropertyMixin, MapEntityMixin, Alti objects = InterventionManager() + geometry_types_allowed = ["ST_LineString", "ST_Point"] + class Meta: verbose_name = _("Intervention") verbose_name_plural = _("Interventions") diff --git a/geotrek/sensitivity/views.py b/geotrek/sensitivity/views.py index 4d033341f3..aade5968a1 100644 --- a/geotrek/sensitivity/views.py +++ b/geotrek/sensitivity/views.py @@ -11,8 +11,9 @@ MapEntityDelete, MapEntityFormat, LastModifiedMixin) from rest_framework import permissions as rest_permissions, viewsets -from geotrek.api.v2.functions import Buffer, GeometryType, Area +from geotrek.api.v2.functions import Buffer, Area from geotrek.authent.decorators import same_structure_required +from geotrek.common.functions import GeometryType from geotrek.common.mixins.views import CustomColumnsMixin from geotrek.common.permissions import PublicOrReadPermMixin from .filters import SensitiveAreaFilterSet diff --git a/geotrek/signage/models.py b/geotrek/signage/models.py index 94deacab5b..0b56e8b85f 100755 --- a/geotrek/signage/models.py +++ b/geotrek/signage/models.py @@ -74,6 +74,8 @@ class Signage(MapEntityMixin, BaseInfrastructure): type = models.ForeignKey(SignageType, related_name='signages', verbose_name=_("Type"), on_delete=models.CASCADE) coordinates_verbose_name = _("Coordinates") + geometry_types_allowed = ["ST_Point"] + class Meta: verbose_name = _("Signage") verbose_name_plural = _("Signages") diff --git a/geotrek/trekking/models.py b/geotrek/trekking/models.py index 4ef733b08d..4f1f913666 100755 --- a/geotrek/trekking/models.py +++ b/geotrek/trekking/models.py @@ -213,6 +213,8 @@ class Trek(Topology, StructureRelated, PicturesMixin, PublishableMixin, MapEntit capture_map_image_waitfor = '.poi_enum_loaded.services_loaded.info_desks_loaded.ref_points_loaded' + geometry_types_allowed = ["ST_LineString"] + class Meta: verbose_name = _("Trek") verbose_name_plural = _("Treks") @@ -727,6 +729,8 @@ class POI(StructureRelated, PicturesMixin, PublishableMixin, MapEntityMixin, Top type = models.ForeignKey('POIType', related_name='pois', verbose_name=_("Type"), on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) + geometry_types_allowed = ["ST_Point"] + class Meta: verbose_name = _("POI") verbose_name_plural = _("POI") From 19d5f3d0154a572f263bebf88fee68869a824244 Mon Sep 17 00:00:00 2001 From: LePetitTim Date: Wed, 1 Jun 2022 17:45:20 +0200 Subject: [PATCH 2/7] Add traduction --- geotrek/core/locale/de/LC_MESSAGES/django.po | 3 +++ geotrek/core/locale/en/LC_MESSAGES/django.po | 3 +++ geotrek/core/locale/es/LC_MESSAGES/django.po | 3 +++ geotrek/core/locale/fr/LC_MESSAGES/django.po | 3 +++ geotrek/core/locale/it/LC_MESSAGES/django.po | 3 +++ geotrek/core/locale/nl/LC_MESSAGES/django.po | 3 +++ 6 files changed, 18 insertions(+) diff --git a/geotrek/core/locale/de/LC_MESSAGES/django.po b/geotrek/core/locale/de/LC_MESSAGES/django.po index 6e898b3889..cf45a4190f 100644 --- a/geotrek/core/locale/de/LC_MESSAGES/django.po +++ b/geotrek/core/locale/de/LC_MESSAGES/django.po @@ -37,6 +37,9 @@ msgstr "" msgid "Valid topology" msgstr "" +msgid "Valid geometry" +msgstr "" + msgid "length" msgstr "" diff --git a/geotrek/core/locale/en/LC_MESSAGES/django.po b/geotrek/core/locale/en/LC_MESSAGES/django.po index 6e898b3889..cf45a4190f 100644 --- a/geotrek/core/locale/en/LC_MESSAGES/django.po +++ b/geotrek/core/locale/en/LC_MESSAGES/django.po @@ -37,6 +37,9 @@ msgstr "" msgid "Valid topology" msgstr "" +msgid "Valid geometry" +msgstr "" + msgid "length" msgstr "" diff --git a/geotrek/core/locale/es/LC_MESSAGES/django.po b/geotrek/core/locale/es/LC_MESSAGES/django.po index 6e898b3889..cf45a4190f 100644 --- a/geotrek/core/locale/es/LC_MESSAGES/django.po +++ b/geotrek/core/locale/es/LC_MESSAGES/django.po @@ -37,6 +37,9 @@ msgstr "" msgid "Valid topology" msgstr "" +msgid "Valid geometry" +msgstr "" + msgid "length" msgstr "" diff --git a/geotrek/core/locale/fr/LC_MESSAGES/django.po b/geotrek/core/locale/fr/LC_MESSAGES/django.po index c51f74be5d..8eb2af530e 100644 --- a/geotrek/core/locale/fr/LC_MESSAGES/django.po +++ b/geotrek/core/locale/fr/LC_MESSAGES/django.po @@ -38,6 +38,9 @@ msgstr "La ligne a un snapping invalide" msgid "Valid topology" msgstr "Topologie valide" +msgid "Valid geometry" +msgstr "GĂ©ometrie valide" + msgid "length" msgstr "Longueur" diff --git a/geotrek/core/locale/it/LC_MESSAGES/django.po b/geotrek/core/locale/it/LC_MESSAGES/django.po index 6e898b3889..cf45a4190f 100644 --- a/geotrek/core/locale/it/LC_MESSAGES/django.po +++ b/geotrek/core/locale/it/LC_MESSAGES/django.po @@ -37,6 +37,9 @@ msgstr "" msgid "Valid topology" msgstr "" +msgid "Valid geometry" +msgstr "" + msgid "length" msgstr "" diff --git a/geotrek/core/locale/nl/LC_MESSAGES/django.po b/geotrek/core/locale/nl/LC_MESSAGES/django.po index 6e898b3889..cf45a4190f 100644 --- a/geotrek/core/locale/nl/LC_MESSAGES/django.po +++ b/geotrek/core/locale/nl/LC_MESSAGES/django.po @@ -37,6 +37,9 @@ msgstr "" msgid "Valid topology" msgstr "" +msgid "Valid geometry" +msgstr "" + msgid "length" msgstr "" From e8c413bac966caefa8e349459beaac994f23abd8 Mon Sep 17 00:00:00 2001 From: LePetitTim Date: Wed, 1 Jun 2022 17:59:14 +0200 Subject: [PATCH 3/7] Add changelog --- docs/changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.rst b/docs/changelog.rst index ffa4325733..67fc0a4c3f 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,6 +7,7 @@ CHANGELOG **New features** +- Add filter valid geometries on topologies 2.83.0 (2022-05-01) From 2ae405abdf2562493779cb5884939a2cb6a68805 Mon Sep 17 00:00:00 2001 From: LePetitTim Date: Thu, 2 Jun 2022 10:05:28 +0200 Subject: [PATCH 4/7] Change geometry types allowed --- geotrek/api/v2/functions.py | 2 +- geotrek/common/functions.py | 10 ++++++---- geotrek/core/filters.py | 2 +- geotrek/core/models.py | 4 ++-- geotrek/infrastructure/models.py | 2 +- geotrek/land/models.py | 10 +++++----- geotrek/maintenance/models.py | 2 +- geotrek/signage/models.py | 2 +- geotrek/trekking/models.py | 4 ++-- 9 files changed, 20 insertions(+), 18 deletions(-) diff --git a/geotrek/api/v2/functions.py b/geotrek/api/v2/functions.py index 1e0c5fa39c..88ce637b69 100644 --- a/geotrek/api/v2/functions.py +++ b/geotrek/api/v2/functions.py @@ -1,6 +1,6 @@ from django.contrib.gis.db.models.functions import GeoFunc from django.db.models import Func -from django.db.models.fields import FloatField, CharField +from django.db.models.fields import FloatField from django.contrib.gis.db.models import GeometryField, PointField diff --git a/geotrek/common/functions.py b/geotrek/common/functions.py index 4a040e0f67..017401d458 100644 --- a/geotrek/common/functions.py +++ b/geotrek/common/functions.py @@ -1,5 +1,5 @@ from django.contrib.gis.db.models.functions import GeoFunc -from django.db.models import CharField, FloatField +from django.db.models import CharField, FloatField, Func class Length(GeoFunc): @@ -7,6 +7,8 @@ class Length(GeoFunc): output_field = FloatField() -class GeometryType(GeoFunc): - """ ST_GeometryType postgis function """ - output_field = CharField() +def GeometryType(geom): + """ + GeometryType postgis function + """ + return Func(geom, function='GeometryType', output_field=CharField()) diff --git a/geotrek/core/filters.py b/geotrek/core/filters.py index 22fd418d05..249ccde4c8 100644 --- a/geotrek/core/filters.py +++ b/geotrek/core/filters.py @@ -16,7 +16,7 @@ class ValidTopologyFilterSet(FilterSet): # Do not forget to add geometry_types_allowed on models if you add this filterset - # geometry_types_allowed = ["ST_LineString"] for example + # geometry_types_allowed = ["LINESTRING"] for example # Types possible with topologies are linestring and points only if settings.TREKKING_TOPOLOGY_ENABLED: diff --git a/geotrek/core/models.py b/geotrek/core/models.py index cd14b0d498..4cb661e02e 100644 --- a/geotrek/core/models.py +++ b/geotrek/core/models.py @@ -387,7 +387,7 @@ class Topology(ZoningPropertiesMixin, AddPropertyMixin, AltimetryMixin, """ Fake srid attribute, that prevents transform() calls when using Django map widgets. """ srid = settings.API_SRID - geometry_types_allowed = ["ST_LineString", "ST_Point"] + geometry_types_allowed = ["LINESTRING", "POINT"] class Meta: verbose_name = _("Topology") @@ -948,7 +948,7 @@ class Trail(MapEntityMixin, Topology, StructureRelated): comments = models.TextField(default="", blank=True, verbose_name=_("Comments")) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) - geometry_types_allowed = ["ST_LineString"] + geometry_types_allowed = ["LINESTRING"] class Meta: verbose_name = _("Trail") diff --git a/geotrek/infrastructure/models.py b/geotrek/infrastructure/models.py index f5b37b6960..98a0ffe438 100755 --- a/geotrek/infrastructure/models.py +++ b/geotrek/infrastructure/models.py @@ -167,7 +167,7 @@ class Infrastructure(MapEntityMixin, BaseInfrastructure): related_name='infrastructures_set') accessibility = models.TextField(verbose_name=_("Accessibility"), blank=True) - geometry_types_allowed = ["ST_LineString", "ST_Point"] + geometry_types_allowed = ["LINESTRING", "POINT"] class Meta: verbose_name = _("Infrastructure") diff --git a/geotrek/land/models.py b/geotrek/land/models.py index e30dd8ee80..1a0d614ef5 100644 --- a/geotrek/land/models.py +++ b/geotrek/land/models.py @@ -43,7 +43,7 @@ class PhysicalEdge(MapEntityMixin, Topology): on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) - geometry_types_allowed = ["ST_LineString"] + geometry_types_allowed = ["LINESTRING"] class Meta: verbose_name = _("Physical edge") @@ -111,7 +111,7 @@ class LandEdge(MapEntityMixin, Topology): agreement = models.BooleanField(verbose_name=_("Agreement"), default=False) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) - geometry_types_allowed = ["ST_LineString"] + geometry_types_allowed = ["LINESTRING"] class Meta: verbose_name = _("Land edge") @@ -162,7 +162,7 @@ class CompetenceEdge(MapEntityMixin, Topology): organization = models.ForeignKey(Organism, verbose_name=_("Organism"), on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) - geometry_types_allowed = ["ST_LineString"] + geometry_types_allowed = ["LINESTRING"] class Meta: verbose_name = _("Competence edge") @@ -213,7 +213,7 @@ class WorkManagementEdge(MapEntityMixin, Topology): organization = models.ForeignKey(Organism, verbose_name=_("Organism"), on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) - geometry_types_allowed = ["ST_LineString"] + geometry_types_allowed = ["LINESTRING"] class Meta: verbose_name = _("Work management edge") @@ -264,7 +264,7 @@ class SignageManagementEdge(MapEntityMixin, Topology): organization = models.ForeignKey(Organism, verbose_name=_("Organism"), on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) - geometry_types_allowed = ["ST_LineString"] + geometry_types_allowed = ["LINESTRING"] class Meta: verbose_name = _("Signage management edge") diff --git a/geotrek/maintenance/models.py b/geotrek/maintenance/models.py index 2954238071..e43d1131d4 100755 --- a/geotrek/maintenance/models.py +++ b/geotrek/maintenance/models.py @@ -75,7 +75,7 @@ class Intervention(ZoningPropertiesMixin, AddPropertyMixin, MapEntityMixin, Alti objects = InterventionManager() - geometry_types_allowed = ["ST_LineString", "ST_Point"] + geometry_types_allowed = ["LINESTRING", "POINT"] class Meta: verbose_name = _("Intervention") diff --git a/geotrek/signage/models.py b/geotrek/signage/models.py index 0b56e8b85f..fcea619b60 100755 --- a/geotrek/signage/models.py +++ b/geotrek/signage/models.py @@ -74,7 +74,7 @@ class Signage(MapEntityMixin, BaseInfrastructure): type = models.ForeignKey(SignageType, related_name='signages', verbose_name=_("Type"), on_delete=models.CASCADE) coordinates_verbose_name = _("Coordinates") - geometry_types_allowed = ["ST_Point"] + geometry_types_allowed = ["POINT"] class Meta: verbose_name = _("Signage") diff --git a/geotrek/trekking/models.py b/geotrek/trekking/models.py index 4f1f913666..c4f69359d3 100755 --- a/geotrek/trekking/models.py +++ b/geotrek/trekking/models.py @@ -213,7 +213,7 @@ class Trek(Topology, StructureRelated, PicturesMixin, PublishableMixin, MapEntit capture_map_image_waitfor = '.poi_enum_loaded.services_loaded.info_desks_loaded.ref_points_loaded' - geometry_types_allowed = ["ST_LineString"] + geometry_types_allowed = ["LINESTRING"] class Meta: verbose_name = _("Trek") @@ -729,7 +729,7 @@ class POI(StructureRelated, PicturesMixin, PublishableMixin, MapEntityMixin, Top type = models.ForeignKey('POIType', related_name='pois', verbose_name=_("Type"), on_delete=models.CASCADE) eid = models.CharField(verbose_name=_("External id"), max_length=1024, blank=True, null=True) - geometry_types_allowed = ["ST_Point"] + geometry_types_allowed = ["POINT"] class Meta: verbose_name = _("POI") From 95d0ee1b9d765a88b3f086ad0ac1277734997e7e Mon Sep 17 00:00:00 2001 From: LePetitTim Date: Thu, 2 Jun 2022 10:38:51 +0200 Subject: [PATCH 5/7] Update changelog --- docs/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 67fc0a4c3f..cfee2c0cd5 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,7 +7,7 @@ CHANGELOG **New features** -- Add filter valid geometries on topologies +- Add filter valid geometries on topologies (#2515)[3.1] 2.83.0 (2022-05-01) From 1fd8f9af4b7236c848385ba67e4b8f3153404023 Mon Sep 17 00:00:00 2001 From: LePetitTim Date: Thu, 2 Jun 2022 11:34:49 +0200 Subject: [PATCH 6/7] Change function to class Geometry type, remove useless annotate --- geotrek/common/functions.py | 5 +++-- geotrek/core/filters.py | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/geotrek/common/functions.py b/geotrek/common/functions.py index 017401d458..8cad0edfd7 100644 --- a/geotrek/common/functions.py +++ b/geotrek/common/functions.py @@ -7,8 +7,9 @@ class Length(GeoFunc): output_field = FloatField() -def GeometryType(geom): +class GeometryType(Func): """ GeometryType postgis function """ - return Func(geom, function='GeometryType', output_field=CharField()) + output_field = CharField() + function = 'GeometryType' diff --git a/geotrek/core/filters.py b/geotrek/core/filters.py index 249ccde4c8..6ea257f44f 100644 --- a/geotrek/core/filters.py +++ b/geotrek/core/filters.py @@ -25,13 +25,12 @@ class ValidTopologyFilterSet(FilterSet): def filter_valid_topology(self, qs, name, value): if value is not None: - qs = qs.annotate(number_aggregations=Count('aggregations'), - distinct_same_order=Count('aggregations__order', distinct=True), + qs = qs.annotate(distinct_same_order=Count('aggregations__order', distinct=True), same_order=Count('aggregations__order')) if value is True: - qs = qs.filter(number_aggregations__gt=0, same_order=F('distinct_same_order')) + qs = qs.filter(same_order__gt=0, same_order=F('distinct_same_order')) elif value is False: - qs = qs.filter(Q(number_aggregations=0) | Q(distinct_same_order__lt=F('same_order'))) + qs = qs.filter(Q(same_order=0) | Q(distinct_same_order__lt=F('same_order'))) return qs def filter_valid_geometry(self, qs, name, value): From b9cfca09557d100d2795c89a9905e9d0af7781f5 Mon Sep 17 00:00:00 2001 From: LePetitTim Date: Thu, 2 Jun 2022 17:51:29 +0200 Subject: [PATCH 7/7] Change func for geofunc --- geotrek/common/functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geotrek/common/functions.py b/geotrek/common/functions.py index 8cad0edfd7..18515902ea 100644 --- a/geotrek/common/functions.py +++ b/geotrek/common/functions.py @@ -1,5 +1,5 @@ from django.contrib.gis.db.models.functions import GeoFunc -from django.db.models import CharField, FloatField, Func +from django.db.models import CharField, FloatField class Length(GeoFunc): @@ -7,7 +7,7 @@ class Length(GeoFunc): output_field = FloatField() -class GeometryType(Func): +class GeometryType(GeoFunc): """ GeometryType postgis function """