diff --git a/docs/changelog.rst b/docs/changelog.rst index cb84bbae41..6b3b61969d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,9 @@ CHANGELOG 2.108.0+dev (XXXX-XX-XX) ---------------------------- +**Improvements** + +- Change infrastructure condition field to ManyToMany field (#3970) 2.108.0 (2024-07-12) ------------------------ @@ -78,6 +81,7 @@ https://geotrek.readthedocs.io/en/latest/install/upgrade.html#postgresql - Bump mapentity to 8.9.0 + 2.106.0 (2024-05-15) -------------------- @@ -129,7 +133,6 @@ https://geotrek.readthedocs.io/en/latest/install/upgrade.html#postgresql - Add structures to Aggregator (#3569) - Allow to filter flatpages by portal on admin list page - 2.104.2 (2024-04-04) -------------------- diff --git a/geotrek/api/tests/test_v2.py b/geotrek/api/tests/test_v2.py index 7cc9801135..6f94d4dcfb 100644 --- a/geotrek/api/tests/test_v2.py +++ b/geotrek/api/tests/test_v2.py @@ -214,7 +214,7 @@ ]) INFRASTRUCTURE_DETAIL_JSON_STRUCTURE = sorted([ - 'id', 'accessibility', 'attachments', 'condition', 'description', 'eid', 'geometry', + 'id', 'accessibility', 'attachments', 'conditions', 'description', 'eid', 'geometry', 'implantation_year', 'maintenance_difficulty', 'name', 'provider', 'structure', 'type', 'usage_difficulty', 'uuid' ]) @@ -453,9 +453,9 @@ def setUpTestData(cls): type=cls.infrastructure_type, usage_difficulty=cls.infrastructure_usagedifficulty, maintenance_difficulty=cls.infrastructure_maintenancedifficulty, - condition=cls.infrastructure_condition, published=True ) + cls.infrastructure.conditions.add(cls.infrastructure_condition) cls.bladetype = signage_factory.BladeTypeFactory( ) cls.color = signage_factory.BladeColorFactory() diff --git a/geotrek/api/v2/serializers.py b/geotrek/api/v2/serializers.py index 85134816d9..2f818eac91 100644 --- a/geotrek/api/v2/serializers.py +++ b/geotrek/api/v2/serializers.py @@ -1558,7 +1558,7 @@ def get_accessibility(self, obj): class Meta: model = infrastructure_models.Infrastructure - fields = ('id', 'accessibility', 'attachments', 'condition', 'description', 'eid', 'geometry', 'name', + fields = ('id', 'accessibility', 'attachments', 'conditions', 'description', 'eid', 'geometry', 'name', 'implantation_year', 'maintenance_difficulty', 'provider', 'structure', 'type', 'usage_difficulty', 'uuid') class InfrastructureConditionSerializer(DynamicFieldsMixin, serializers.ModelSerializer): diff --git a/geotrek/api/v2/views/infrastructure.py b/geotrek/api/v2/views/infrastructure.py index c29eac9763..8abfae5f63 100644 --- a/geotrek/api/v2/views/infrastructure.py +++ b/geotrek/api/v2/views/infrastructure.py @@ -19,8 +19,8 @@ class InfrastructureViewSet(api_viewsets.GeotrekGeometricViewset): .annotate(geom3d_transformed=Transform(F('geom_3d'), settings.API_SRID)) \ .prefetch_related('topo_object__aggregations', Prefetch('attachments', - queryset=Attachment.objects.select_related('license', 'filetype', 'filetype__structure'))) \ - .order_by('pk') + queryset=Attachment.objects.select_related('license', 'filetype', 'filetype__structure')), + 'conditions').order_by('pk') class InfrastructureTypeViewSet(api_viewsets.GeotrekViewSet): diff --git a/geotrek/infrastructure/filters.py b/geotrek/infrastructure/filters.py index 16fa25b66a..1500885e89 100644 --- a/geotrek/infrastructure/filters.py +++ b/geotrek/infrastructure/filters.py @@ -31,7 +31,7 @@ class InfrastructureFilterSet(AltimetryAllGeometriesFilterSet, ValidTopologyFilt class Meta(StructureRelatedFilterSet.Meta): model = Infrastructure fields = StructureRelatedFilterSet.Meta.fields + [ - 'category', 'type', 'condition', 'implantation_year', + 'category', 'type', 'conditions', 'implantation_year', 'intervention_year', 'published', 'provider', 'access' ] diff --git a/geotrek/infrastructure/forms.py b/geotrek/infrastructure/forms.py index 4784101365..389f0a317e 100644 --- a/geotrek/infrastructure/forms.py +++ b/geotrek/infrastructure/forms.py @@ -43,7 +43,7 @@ class InfrastructureForm(BaseInfrastructureForm): 'description', 'accessibility', 'type', - 'condition', + 'conditions', 'access', 'implantation_year', 'usage_difficulty', @@ -54,4 +54,4 @@ class InfrastructureForm(BaseInfrastructureForm): class Meta(BaseInfrastructureForm.Meta): model = Infrastructure - fields = BaseInfrastructureForm.Meta.fields + ['accessibility', 'maintenance_difficulty', 'usage_difficulty', 'condition'] + fields = BaseInfrastructureForm.Meta.fields + ['accessibility', 'maintenance_difficulty', 'usage_difficulty', 'conditions'] diff --git a/geotrek/infrastructure/locale/de/LC_MESSAGES/django.po b/geotrek/infrastructure/locale/de/LC_MESSAGES/django.po index 59e19533bd..2e6a05549a 100644 --- a/geotrek/infrastructure/locale/de/LC_MESSAGES/django.po +++ b/geotrek/infrastructure/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-03 15:39+0000\n" +"POT-Creation-Date: 2024-07-18 14:36+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -108,7 +108,7 @@ msgstr "" msgid "Accessibility" msgstr "" -msgid "Condition" +msgid "Conditions" msgstr "" msgid "Infrastructures" diff --git a/geotrek/infrastructure/locale/en/LC_MESSAGES/django.po b/geotrek/infrastructure/locale/en/LC_MESSAGES/django.po index 60da80e1e5..33d2bb4fbd 100644 --- a/geotrek/infrastructure/locale/en/LC_MESSAGES/django.po +++ b/geotrek/infrastructure/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-03 15:39+0000\n" +"POT-Creation-Date: 2024-07-18 14:36+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -108,7 +108,7 @@ msgstr "" msgid "Accessibility" msgstr "" -msgid "Condition" +msgid "Conditions" msgstr "" msgid "Infrastructures" diff --git a/geotrek/infrastructure/locale/es/LC_MESSAGES/django.po b/geotrek/infrastructure/locale/es/LC_MESSAGES/django.po index 60da80e1e5..33d2bb4fbd 100644 --- a/geotrek/infrastructure/locale/es/LC_MESSAGES/django.po +++ b/geotrek/infrastructure/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-03 15:39+0000\n" +"POT-Creation-Date: 2024-07-18 14:36+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -108,7 +108,7 @@ msgstr "" msgid "Accessibility" msgstr "" -msgid "Condition" +msgid "Conditions" msgstr "" msgid "Infrastructures" diff --git a/geotrek/infrastructure/locale/fr/LC_MESSAGES/django.po b/geotrek/infrastructure/locale/fr/LC_MESSAGES/django.po index 59ed0d5ec5..eb31275f34 100644 --- a/geotrek/infrastructure/locale/fr/LC_MESSAGES/django.po +++ b/geotrek/infrastructure/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-03 15:39+0000\n" +"POT-Creation-Date: 2024-07-18 14:36+0000\n" "PO-Revision-Date: 2020-04-22 07:48+0000\n" "Last-Translator: Emmanuelle Helly \n" "Language-Team: French \n" "Language-Team: LANGUAGE \n" @@ -108,7 +108,7 @@ msgstr "" msgid "Accessibility" msgstr "" -msgid "Condition" +msgid "Conditions" msgstr "" msgid "Infrastructures" diff --git a/geotrek/infrastructure/locale/nl/LC_MESSAGES/django.po b/geotrek/infrastructure/locale/nl/LC_MESSAGES/django.po index 60da80e1e5..33d2bb4fbd 100644 --- a/geotrek/infrastructure/locale/nl/LC_MESSAGES/django.po +++ b/geotrek/infrastructure/locale/nl/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-04-03 15:39+0000\n" +"POT-Creation-Date: 2024-07-18 14:36+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -108,7 +108,7 @@ msgstr "" msgid "Accessibility" msgstr "" -msgid "Condition" +msgid "Conditions" msgstr "" msgid "Infrastructures" diff --git a/geotrek/infrastructure/management/commands/loadinfrastructure.py b/geotrek/infrastructure/management/commands/loadinfrastructure.py index ebaad1567e..5ddde1a4d2 100644 --- a/geotrek/infrastructure/management/commands/loadinfrastructure.py +++ b/geotrek/infrastructure/management/commands/loadinfrastructure.py @@ -217,7 +217,6 @@ def create_infrastructure(self, geometry, name, type, category, use_structure, fields_without_eid = { 'type': infra_type, 'name': name, - 'condition': condition_type, 'structure': structure, 'description': description, 'implantation_year': year @@ -227,6 +226,8 @@ def create_infrastructure(self, geometry, name, type, category, use_structure, eid=eid, defaults=fields_without_eid ) + if condition_type: + infra.conditions.add(condition_type) if verbosity > 0 and not created: self.stdout.write("Update : %s with eid %s" % (name, eid)) else: diff --git a/geotrek/infrastructure/migrations/0039_infrastructure_conditions.py b/geotrek/infrastructure/migrations/0039_infrastructure_conditions.py new file mode 100644 index 0000000000..554c4e80dc --- /dev/null +++ b/geotrek/infrastructure/migrations/0039_infrastructure_conditions.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.25 on 2024-04-25 12:25 + +from django.db import migrations, models + + +def copy_condition_to_conditions(apps, schema_editor): + Infrastructure = apps.get_model('infrastructure', 'Infrastructure') + + # Copy InfrastructureCondition ForeignKey to ManyToMany field + for infrastructure in Infrastructure.objects.all(): + if infrastructure.condition: + infrastructure.conditions.add(infrastructure.condition) + + +class Migration(migrations.Migration): + + dependencies = [ + ('infrastructure', '0038_rename_access_tmp_infrastructure_access'), + ] + + operations = [ + migrations.AddField( + model_name='infrastructure', + name='conditions', + field=models.ManyToManyField(blank=True, related_name='infrastructures', to='infrastructure.InfrastructureCondition', verbose_name='Condition'), + ), + migrations.RunPython(copy_condition_to_conditions, reverse_code=migrations.RunPython.noop), + ] diff --git a/geotrek/infrastructure/migrations/0040_remove_infrastructure_condition.py b/geotrek/infrastructure/migrations/0040_remove_infrastructure_condition.py new file mode 100644 index 0000000000..0483a2e495 --- /dev/null +++ b/geotrek/infrastructure/migrations/0040_remove_infrastructure_condition.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.25 on 2024-04-25 13:27 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('infrastructure', '0039_infrastructure_conditions'), + ] + + operations = [ + migrations.RemoveField( + model_name='infrastructure', + name='condition', + ), + ] diff --git a/geotrek/infrastructure/models.py b/geotrek/infrastructure/models.py index 1521e4cb42..abc83a47d1 100755 --- a/geotrek/infrastructure/models.py +++ b/geotrek/infrastructure/models.py @@ -174,9 +174,12 @@ class Infrastructure(BaseInfrastructure, GeotrekMapEntityMixin): on_delete=models.PROTECT, related_name='infrastructures_set') accessibility = models.TextField(verbose_name=_("Accessibility"), blank=True) - condition = models.ForeignKey(InfrastructureCondition, - verbose_name=_("Condition"), blank=True, null=True, - on_delete=models.PROTECT) + conditions = models.ManyToManyField( + InfrastructureCondition, + related_name='infrastructures', + verbose_name=_("Conditions"), + blank=True) + geometry_types_allowed = ["LINESTRING", "POINT"] class Meta: @@ -213,6 +216,15 @@ def tourism_infrastructures(cls, tourism_obj, queryset=None): def outdoor_infrastructures(cls, outdoor_obj, queryset=None): return intersecting(qs=queryset_or_model(queryset, cls), obj=outdoor_obj) + @property + def conditions_display(self): + if hasattr(self, "conditions_list"): + # Use conditions prefetched + conditions_list = self.conditions_list + else: + conditions_list = self.conditions.select_related('structure').all() + return ", ".join([str(c) for c in conditions_list]) + def save(self, *args, **kwargs): super().save(*args, **kwargs) for trek in self.treks.all(): diff --git a/geotrek/infrastructure/serializers.py b/geotrek/infrastructure/serializers.py index 42809436ee..71a716957d 100644 --- a/geotrek/infrastructure/serializers.py +++ b/geotrek/infrastructure/serializers.py @@ -18,7 +18,7 @@ class Meta: class InfrastructureSerializer(DynamicFieldsMixin, serializers.ModelSerializer): name = serializers.CharField(source='name_display') type = serializers.CharField(source='type_display') - condition = serializers.SlugRelatedField('label', read_only=True) + conditions = serializers.CharField(source='conditions_display') cities = serializers.CharField(source='cities_display') structure = serializers.SlugRelatedField('name', read_only=True) usage_difficulty = serializers.SlugRelatedField('label', read_only=True) diff --git a/geotrek/infrastructure/templates/infrastructure/infrastructure_detail_attributes.html b/geotrek/infrastructure/templates/infrastructure/infrastructure_detail_attributes.html index 1c107fedaa..7fd4c13287 100644 --- a/geotrek/infrastructure/templates/infrastructure/infrastructure_detail_attributes.html +++ b/geotrek/infrastructure/templates/infrastructure/infrastructure_detail_attributes.html @@ -17,9 +17,11 @@

{% trans "Attributes" %}

{{ object|verbose:"type" }} {{ object.type }} - - {{ object|verbose:"condition" }} - {{ object.condition }} + + {{ object|verbose:"conditions" }} + + {{ object.conditions_display }} + {{ object|verbose:"description" }} diff --git a/geotrek/infrastructure/templates/infrastructure/sql/post_10_views.sql b/geotrek/infrastructure/templates/infrastructure/sql/post_10_views.sql index 96bf63c32a..cfd99cbd05 100644 --- a/geotrek/infrastructure/templates/infrastructure/sql/post_10_views.sql +++ b/geotrek/infrastructure/templates/infrastructure/sql/post_10_views.sql @@ -21,7 +21,6 @@ CREATE VIEW {{ schema_geotrek }}.v_infrastructures AS WITH v_infra AS {% endfor %} CONCAT (e.min_elevation, 'm') AS altitude, t.implantation_year, - t.condition_id, t.access_id, t.structure_id, t.type_id, @@ -44,7 +43,7 @@ SELECT a.id, a.name_{{ lang }} AS "Name {{ lang }}", {% endfor %} b.label AS "Type", - c.label AS "Condition", + c.labels AS "Conditions", {% for lang in MODELTRANSLATION_LANGUAGES %} a.description_{{ lang }} AS "Description {{ lang }}", {% endfor %} @@ -71,7 +70,19 @@ SELECT a.id, a.geom FROM v_infra a LEFT JOIN infrastructure_infrastructuretype b ON a.type_id = b.id -LEFT JOIN infrastructure_infrastructurecondition c ON a.condition_id = c.id + + LEFT JOIN ( WITH infrastructure_condition AS ( + SELECT a_1.infrastructurecondition_id, + b_2.label AS labels, + a_1.infrastructure_id + FROM infrastructure_infrastructurecondition b_2 + JOIN infrastructure_infrastructure_conditions a_1 ON a_1.infrastructurecondition_id = b_2.id + ) + SELECT array_to_string(array_agg(infrastructure_condition.labels), ', '::text, '_'::text)::character varying AS labels, + infrastructure_condition.infrastructure_id + FROM infrastructure_condition + GROUP BY infrastructure_condition.infrastructure_id) c ON a.topo_object_id = c.infrastructure_id + LEFT JOIN infrastructure_infrastructureusagedifficultylevel d ON a.usage_difficulty_id = d.id LEFT JOIN infrastructure_infrastructuremaintenancedifficultylevel e ON a.maintenance_difficulty_id = e.id LEFT JOIN common_accessmean j ON a.access_id = j.id diff --git a/geotrek/infrastructure/tests/data/infrastructure.dbf b/geotrek/infrastructure/tests/data/infrastructure.dbf index d886a6ca32..6264fab5b6 100644 Binary files a/geotrek/infrastructure/tests/data/infrastructure.dbf and b/geotrek/infrastructure/tests/data/infrastructure.dbf differ diff --git a/geotrek/infrastructure/tests/data/infrastructure.qix b/geotrek/infrastructure/tests/data/infrastructure.qix new file mode 100644 index 0000000000..74943b46ad Binary files /dev/null and b/geotrek/infrastructure/tests/data/infrastructure.qix differ diff --git a/geotrek/infrastructure/tests/factories.py b/geotrek/infrastructure/tests/factories.py index 5662a4abf4..6456372455 100644 --- a/geotrek/infrastructure/tests/factories.py +++ b/geotrek/infrastructure/tests/factories.py @@ -44,30 +44,37 @@ class Meta: label = factory.Sequence(lambda n: "Maintenance level %s" % n) -class InfrastructureFactory(TopologyFactory): +class InfrastructureFactoryMixin(): + @factory.post_generation + def conditions(obj, create, extracted=None, **kwargs): + if create: + if extracted: + obj.conditions.set(extracted) + else: + obj.conditions.add(InfrastructureConditionFactory.create()) + + +class InfrastructureFactory(TopologyFactory, InfrastructureFactoryMixin): class Meta: model = models.Infrastructure name = factory.Sequence(lambda n: "Infrastructure %s" % n) type = factory.SubFactory(InfrastructureTypeFactory) - condition = factory.SubFactory(InfrastructureConditionFactory) published = True usage_difficulty = factory.SubFactory(InfrastructureUsageDifficultyLevelFactory) maintenance_difficulty = factory.SubFactory(InfrastructureMaintenanceDifficultyLevelFactory) -class PointInfrastructureFactory(PointTopologyFactory): +class PointInfrastructureFactory(PointTopologyFactory, InfrastructureFactoryMixin): class Meta: model = models.Infrastructure name = factory.Sequence(lambda n: "Infrastructure %s" % n) type = factory.SubFactory(InfrastructureTypeFactory) - condition = factory.SubFactory(InfrastructureConditionFactory) published = True -class InfrastructureNoPictogramFactory(TopologyFactory): +class InfrastructureNoPictogramFactory(TopologyFactory, InfrastructureFactoryMixin): class Meta: model = models.Infrastructure name = factory.Sequence(lambda n: "Infrastructure %s" % n) type = factory.SubFactory(InfrastructureTypeNoPictogramFactory) - condition = factory.SubFactory(InfrastructureConditionFactory) published = True diff --git a/geotrek/infrastructure/tests/test_command_loadinfrastructure.py b/geotrek/infrastructure/tests/test_command_loadinfrastructure.py index 3ff90ed742..9ceaadee92 100644 --- a/geotrek/infrastructure/tests/test_command_loadinfrastructure.py +++ b/geotrek/infrastructure/tests/test_command_loadinfrastructure.py @@ -25,7 +25,7 @@ def test_load_infrastructure(self): structure = StructureFactory.create(name='structure') filename = os.path.join(os.path.dirname(__file__), 'data', 'infrastructure.shp') call_command('loadinfrastructure', filename, type_default='label', name_default='name', - condition_default='condition', structure_default='structure', + condition_default='conditions', structure_default='structure', description_default='description', year_default=2010, verbosity=2, stdout=output) self.assertIn('Infrastructures will be linked to %s' % structure, output.getvalue()) self.assertIn('2 objects created.', output.getvalue()) @@ -42,7 +42,7 @@ def test_load_infrastructure_multipoints(self): structure = StructureFactory.create(name='structure') filename = os.path.join(os.path.dirname(__file__), 'data', 'infrastructure_good_multipoint.geojson') call_command('loadinfrastructure', filename, type_default='label', name_default='name', - condition_default='condition', structure_default='structure', + condition_default='conditions', structure_default='structure', description_default='description', year_default=2010, verbosity=2, stdout=output) self.assertIn('Infrastructures will be linked to %s' % structure, output.getvalue()) self.assertIn('1 objects created.', output.getvalue()) @@ -57,7 +57,7 @@ def test_load_infrastructure_bad_multipoints_error(self): filename = os.path.join(os.path.dirname(__file__), 'data', 'infrastructure_bad_multipoint.geojson') with self.assertRaisesRegex(CommandError, 'One of your geometry is a MultiPoint object with multiple points'): call_command('loadinfrastructure', filename, type_default='label', name_default='name', - condition_default='condition', structure_default='structure', + condition_default='conditions', structure_default='structure', description_default='description', year_default=2010, verbosity=2, stdout=output) def test_load_infrastructure_with_fields_use_structure(self): @@ -65,7 +65,7 @@ def test_load_infrastructure_with_fields_use_structure(self): structure = StructureFactory.create(name='structure') filename = os.path.join(os.path.dirname(__file__), 'data', 'infrastructure.shp') call_command('loadinfrastructure', filename, type_field='label', name_field='name', - condition_field='condition', structure_default='structure', use_structure=True, + condition_field='conditions', structure_default='structure', use_structure=True, description_field='descriptio', year_field='year', verbosity=1, stdout=output) self.assertIn('Infrastructures will be linked to %s' % structure, output.getvalue()) self.assertIn("InfrastructureType 'type (%s)' created" % structure, output.getvalue()) @@ -83,7 +83,7 @@ def test_load_infrastructure_with_fields(self): structure = StructureFactory.create(name='structure') filename = os.path.join(os.path.dirname(__file__), 'data', 'infrastructure.shp') call_command('loadinfrastructure', filename, type_field='label', name_field='name', - condition_field='condition', structure_default='structure', + condition_field='conditions', structure_default='structure', description_field='descriptio', year_field='year', verbosity=1, stdout=output) self.assertIn('Infrastructures will be linked to %s' % structure, output.getvalue()) self.assertIn("InfrastructureType 'type' created", output.getvalue()) @@ -158,7 +158,7 @@ def test_update_same_eid(self): filename = os.path.join(os.path.dirname(__file__), 'data', 'infrastructure.shp') InfrastructureFactory(name="name", eid="eid_2") call_command('loadinfrastructure', filename, eid_field='eid', type_default='label', - name_default='name', verbosity=2, stdout=output) + condition_field='conditions', name_default='name', verbosity=2, stdout=output) self.assertIn("Update : name with eid eid1", output.getvalue()) self.assertEqual(Infrastructure.objects.count(), 2) @@ -166,7 +166,7 @@ def test_fail_structure_default_do_not_exist(self): output = StringIO() filename = os.path.join(os.path.dirname(__file__), 'data', 'infrastructure.shp') call_command('loadinfrastructure', filename, type_default='label', name_default='name', - condition_default='condition', structure_default='wrong_structure_default', + condition_default='conditions', structure_default='wrong_structure_default', description_default='description', year_default=2010, category_default='E', verbosity=0, stdout=output) self.assertIn("Structure wrong_structure_default set in options doesn't exist", output.getvalue()) diff --git a/geotrek/infrastructure/tests/test_views.py b/geotrek/infrastructure/tests/test_views.py index 426d95086a..42c00466db 100755 --- a/geotrek/infrastructure/tests/test_views.py +++ b/geotrek/infrastructure/tests/test_views.py @@ -34,7 +34,7 @@ def get_expected_geojson_attrs(self): def get_expected_datatables_attrs(self): return { 'cities': '', - 'condition': self.obj.condition.label, + 'conditions': self.obj.conditions_display, 'id': self.obj.pk, 'name': self.obj.name_display, 'type': self.obj.type.label, @@ -46,7 +46,7 @@ def get_good_data(self): 'name_en': 'test_en', 'description': 'oh', 'type': InfrastructureTypeFactory.create(type=INFRASTRUCTURE_TYPES.BUILDING).pk, - 'condition': InfrastructureConditionFactory.create().pk, + 'conditions': [InfrastructureConditionFactory.create().pk], 'accessibility': 'description accessibility' } if settings.TREKKING_TOPOLOGY_ENABLED: @@ -85,7 +85,7 @@ def get_good_data(self): 'name_en': 'test_en', 'description': 'oh', 'type': InfrastructureTypeFactory.create(type=INFRASTRUCTURE_TYPES.BUILDING).pk, - 'condition': InfrastructureConditionFactory.create().pk, + 'conditions': [InfrastructureConditionFactory.create().pk], } if settings.TREKKING_TOPOLOGY_ENABLED: path = PathFactory.create() diff --git a/geotrek/infrastructure/views.py b/geotrek/infrastructure/views.py index c86e71ed69..452834ca0e 100755 --- a/geotrek/infrastructure/views.py +++ b/geotrek/infrastructure/views.py @@ -1,5 +1,6 @@ from django.conf import settings from django.contrib.gis.db.models.functions import Transform +from django.db.models.query import Prefetch from mapentity.views import ( MapEntityCreate, MapEntityDelete, @@ -18,7 +19,7 @@ from .filters import InfrastructureFilterSet from .forms import InfrastructureForm -from .models import Infrastructure +from .models import Infrastructure, InfrastructureCondition from .serializers import InfrastructureGeojsonSerializer, InfrastructureSerializer @@ -26,14 +27,14 @@ class InfrastructureList(CustomColumnsMixin, MapEntityList): queryset = Infrastructure.objects.existing() filterform = InfrastructureFilterSet mandatory_columns = ['id', 'name'] - default_extra_columns = ['type', 'condition', 'cities'] + default_extra_columns = ['type', 'conditions', 'cities'] searchable_columns = ['id', 'name'] class InfrastructureFormatList(MapEntityFormat, InfrastructureList): mandatory_columns = ['id'] default_extra_columns = [ - 'id', 'name', 'type', 'condition', 'description', 'accessibility', + 'id', 'name', 'type', 'conditions', 'description', 'accessibility', 'implantation_year', 'published', 'publication_date', 'structure', 'date_insert', 'date_update', 'cities', 'districts', 'areas', 'usage_difficulty', 'maintenance_difficulty', 'access', 'uuid', @@ -88,5 +89,7 @@ def get_queryset(self): qs = qs.annotate(api_geom=Transform('geom', settings.API_SRID)) qs = qs.only('id', 'name', 'published') else: - qs = qs.select_related('type', 'condition', 'maintenance_difficulty', 'access', 'usage_difficulty') + qs = qs.select_related('type', 'maintenance_difficulty', 'access', 'usage_difficulty').prefetch_related( + Prefetch('conditions', + queryset=InfrastructureCondition.objects.select_related('structure'), to_attr="conditions_list"),) return qs diff --git a/geotrek/maintenance/tests/test_views.py b/geotrek/maintenance/tests/test_views.py index 5f9c095c81..b665a0555e 100644 --- a/geotrek/maintenance/tests/test_views.py +++ b/geotrek/maintenance/tests/test_views.py @@ -387,6 +387,7 @@ def test_update_infrastructure(self): data['implantation_year'] = target_year data['accessibility'] = '' data['access'] = '' + data['conditions'] = list(form.instance.conditions.values_list('pk', flat=True)) if settings.TREKKING_TOPOLOGY_ENABLED: data['topology'] = '{"paths": [%s]}' % PathFactory.create().pk else: