diff --git a/geotrek/api/v2/serializers.py b/geotrek/api/v2/serializers.py index 51fea8ec00..13906b159f 100644 --- a/geotrek/api/v2/serializers.py +++ b/geotrek/api/v2/serializers.py @@ -1261,7 +1261,7 @@ class Meta: class SensitiveAreaSerializer(DynamicFieldsMixin, TimeStampedSerializer): url = HyperlinkedIdentityField(view_name="apiv2:sensitivearea-detail") - name = serializers.SerializerMethodField() + name = serializers.CharField(source="area_name") elevation = serializers.SerializerMethodField() description = serializers.SerializerMethodField() period = serializers.SerializerMethodField() @@ -1281,7 +1281,7 @@ class SensitiveAreaSerializer(DynamicFieldsMixin, TimeStampedSerializer): provider = serializers.SlugRelatedField(read_only=True, slug_field="name") def get_name(self, obj): - return get_translation_or_dict("name", self, obj.species) + return get_translation_or_dict("name", self, obj) def get_description(self, obj): return get_translation_or_dict("description", self, obj) diff --git a/geotrek/diving/templates/diving/dive_public_pdf_base.html b/geotrek/diving/templates/diving/dive_public_pdf_base.html index 519a8e1627..72a713f55d 100644 --- a/geotrek/diving/templates/diving/dive_public_pdf_base.html +++ b/geotrek/diving/templates/diving/dive_public_pdf_base.html @@ -157,7 +157,7 @@

{% trans "Environmental sensitive areas" %}

{% for area in object.published_sensitive_areas %}
{% if area.species.pictogram %}{% endif %} -

{{ area.species.name }}

+

{{ area.name }}

{% trans "Sensitivity period:" %} {{ area.pretty_period }}

{% if area.contact %}

{% trans "Contact:" %} {{ area.contact|safe }}

{% endif %}

{{ area.description|safe }}

diff --git a/geotrek/sensitivity/forms.py b/geotrek/sensitivity/forms.py index bd81ce8999..f1bd333a67 100644 --- a/geotrek/sensitivity/forms.py +++ b/geotrek/sensitivity/forms.py @@ -23,13 +23,22 @@ class PolygonMapWidget(MapWidget): class SensitiveAreaForm(CommonForm): geomfields = ["geom"] + name = forms.CharField(max_length=250, label=_("Name"), required=False) species = forms.ModelChoiceField( queryset=Species.objects.filter(category=Species.SPECIES), label=pgettext("Singular", "Species"), ) class Meta: - fields = ["structure", "species", "published", "description", "contact", "geom"] + fields = [ + "structure", + "species", + "name", + "published", + "description", + "contact", + "geom", + ] model = SensitiveArea widgets = {"geom": BubbleMapWidget()} @@ -82,7 +91,6 @@ def __init__(self, *args, **kwargs): if instance: species = instance.species kwargs["initial"] = { - "name": species.name, "elevation": species.radius, "pictogram": species.pictogram, "practices": species.practices.all(), @@ -101,7 +109,6 @@ def save(self, **kwargs): else: species = self.instance.species species.category = Species.REGULATORY - species.name = self.cleaned_data["name"] species.radius = self.cleaned_data["elevation"] species.pictogram = self.cleaned_data["pictogram"] species.url = self.cleaned_data["url"] diff --git a/geotrek/sensitivity/locale/de/LC_MESSAGES/django.po b/geotrek/sensitivity/locale/de/LC_MESSAGES/django.po index 59dafbe94d..de881fd33e 100644 --- a/geotrek/sensitivity/locale/de/LC_MESSAGES/django.po +++ b/geotrek/sensitivity/locale/de/LC_MESSAGES/django.po @@ -112,6 +112,9 @@ msgstr "" msgid "Species" msgstr "" +msgid "Area name" +msgstr "" + msgid "Species or regulatory area" msgstr "" @@ -133,6 +136,9 @@ msgstr "" msgid "Sensitive areas" msgstr "" +msgid "Published name" +msgstr "" + msgid "Radius" msgstr "" diff --git a/geotrek/sensitivity/locale/en/LC_MESSAGES/django.po b/geotrek/sensitivity/locale/en/LC_MESSAGES/django.po index 19c1ca5ac9..888fc39fc2 100644 --- a/geotrek/sensitivity/locale/en/LC_MESSAGES/django.po +++ b/geotrek/sensitivity/locale/en/LC_MESSAGES/django.po @@ -112,9 +112,12 @@ msgstr "" msgid "Species" msgstr "" -msgid "Species or regulatory area" +msgid "Area name" msgstr "" +msgid "Species or regulatory area" +msgstr "Specie" + msgid "Published" msgstr "" @@ -133,6 +136,9 @@ msgstr "" msgid "Sensitive areas" msgstr "" +msgid "Published name" +msgstr "" + msgid "Radius" msgstr "" diff --git a/geotrek/sensitivity/locale/es/LC_MESSAGES/django.po b/geotrek/sensitivity/locale/es/LC_MESSAGES/django.po index f117c66a89..c2942b3f18 100644 --- a/geotrek/sensitivity/locale/es/LC_MESSAGES/django.po +++ b/geotrek/sensitivity/locale/es/LC_MESSAGES/django.po @@ -112,6 +112,9 @@ msgstr "" msgid "Species" msgstr "" +msgid "Area name" +msgstr "" + msgid "Species or regulatory area" msgstr "" @@ -133,6 +136,9 @@ msgstr "" msgid "Sensitive areas" msgstr "" +msgid "Published name" +msgstr "" + msgid "Radius" msgstr "" diff --git a/geotrek/sensitivity/locale/fr/LC_MESSAGES/django.po b/geotrek/sensitivity/locale/fr/LC_MESSAGES/django.po index 882ae2d36e..22666c1a2d 100644 --- a/geotrek/sensitivity/locale/fr/LC_MESSAGES/django.po +++ b/geotrek/sensitivity/locale/fr/LC_MESSAGES/django.po @@ -112,8 +112,11 @@ msgstr "ID externe" msgid "Species" msgstr "Espèces" +msgid "Area name" +msgstr "Nom de la zone" + msgid "Species or regulatory area" -msgstr "Espèce ou zone réglementaire" +msgstr "Espèce" msgid "Published" msgstr "Publiée" @@ -133,6 +136,11 @@ msgstr "Zone de sensibilité" msgid "Sensitive areas" msgstr "Zones sensibles" +#, fuzzy +#| msgid "Published" +msgid "Published name" +msgstr "Publiée" + msgid "Radius" msgstr "Rayon" diff --git a/geotrek/sensitivity/locale/it/LC_MESSAGES/django.po b/geotrek/sensitivity/locale/it/LC_MESSAGES/django.po index 168844b8f3..8bc874eda7 100644 --- a/geotrek/sensitivity/locale/it/LC_MESSAGES/django.po +++ b/geotrek/sensitivity/locale/it/LC_MESSAGES/django.po @@ -112,6 +112,9 @@ msgstr "" msgid "Species" msgstr "" +msgid "Area name" +msgstr "" + msgid "Species or regulatory area" msgstr "" @@ -133,6 +136,9 @@ msgstr "" msgid "Sensitive areas" msgstr "" +msgid "Published name" +msgstr "" + msgid "Radius" msgstr "" diff --git a/geotrek/sensitivity/locale/nl/LC_MESSAGES/django.po b/geotrek/sensitivity/locale/nl/LC_MESSAGES/django.po index 952af318aa..134c0ea12a 100644 --- a/geotrek/sensitivity/locale/nl/LC_MESSAGES/django.po +++ b/geotrek/sensitivity/locale/nl/LC_MESSAGES/django.po @@ -112,6 +112,9 @@ msgstr "" msgid "Species" msgstr "" +msgid "Area name" +msgstr "" + msgid "Species or regulatory area" msgstr "" @@ -133,6 +136,9 @@ msgstr "" msgid "Sensitive areas" msgstr "" +msgid "Published name" +msgstr "" + msgid "Radius" msgstr "" diff --git a/geotrek/sensitivity/migrations/0031_sensitivearea_name.py b/geotrek/sensitivity/migrations/0031_sensitivearea_name.py new file mode 100644 index 0000000000..39830406d7 --- /dev/null +++ b/geotrek/sensitivity/migrations/0031_sensitivearea_name.py @@ -0,0 +1,98 @@ +import logging +from typing import cast + +from django.conf import settings +from django.core.management.color import no_style +from django.db import connection, migrations, models, utils +from django.db.models import Field, Model +from modeltranslation.translator import TranslationOptions, translator +from modeltranslation.utils import build_localized_fieldname + +from geotrek.sensitivity.models import SensitiveArea + +logger = logging.getLogger(__name__) + + +def get_sync_sql( + field_name: str, missing_langs: list[str], model: type[Model] +) -> list[str]: + """ + Returns SQL needed for sync schema for a new translatable field. + """ + qn = connection.ops.quote_name + style = no_style() + sql_output: list[str] = [] + db_table = model._meta.db_table + for lang in missing_langs: + new_field = build_localized_fieldname(field_name, lang) + f = cast(Field, model._meta.get_field(new_field)) + col_type = f.db_type(connection=connection) + field_sql = [style.SQL_FIELD(qn(f.column)), style.SQL_COLTYPE(col_type)] # type: ignore[arg-type] + # column creation + stmt = "ALTER TABLE {} ADD COLUMN IF NOT EXISTS {}".format(qn(db_table), " ".join(field_sql)) + if not f.null: + stmt += " " + style.SQL_KEYWORD("NOT NULL") + sql_output.append(stmt + ";") + return sql_output + + +def create_translation_fields(apps, schema_editor): + translated_fields = [ + "name", + "description", + ] + + class SensitiveAreaTO(TranslationOptions): + fields = translated_fields + + SensitiveArea = apps.get_model("sensitivity", "SensitiveArea") + translator.register(SensitiveArea, SensitiveAreaTO) + + langs = settings.MODELTRANSLATION_LANGUAGES + + for field in translated_fields: + sql_statements = get_sync_sql(field, langs, SensitiveArea) + with connection.cursor() as cursor: + for sql in sql_statements: + cursor.execute(sql) + +def generate_name(apps, schema_editor): + """Populate SensitiveAreas name from Species""" + + sensitive_area = SensitiveArea + languages = settings.MODELTRANSLATION_LANGUAGES + update_fields = [ + "name", + ] + update_fields += [f"name_{lang}" for lang in languages] + for row in sensitive_area.objects.existing().filter(species__category=2): + for field in update_fields: + try: + setattr(row, field, getattr(row.species, field)) + row.save(update_fields=update_fields) + except utils.ProgrammingError as e: + logger.warning('[Update sensitive areas] An error occured during migration : %s', e) + for field in update_fields: + # print(f"species.manager {row.species._meta.managers}") + # print(f"row {row.species} | field {field}") + try: + setattr(row.species, field, "") + row.species.save(update_fields=update_fields) + except utils.ProgrammingError as e: + logger.warning('[Update sensitive species] An error occured during migration : %s', e) + +class Migration(migrations.Migration): + dependencies = [ + ("sensitivity", "0030_alter_sensitivearea_eid"), + ] + + operations = [ + migrations.AddField( + model_name="sensitivearea", + name="name", + field=models.CharField(default="", max_length=250, verbose_name="Name"), + ), + # migrations.RunPython(update_translation_fields_func, reverse_code=migrations.RunPython.noop), + migrations.RunPython(create_translation_fields, reverse_code=migrations.RunPython.noop), + migrations.RunPython(generate_name, reverse_code=migrations.RunPython.noop), + ] diff --git a/geotrek/sensitivity/models.py b/geotrek/sensitivity/models.py index 13fdea5315..2e4462edf8 100644 --- a/geotrek/sensitivity/models.py +++ b/geotrek/sensitivity/models.py @@ -122,6 +122,7 @@ class SensitiveArea( AddPropertyMixin, ExternalSourceMixin, ): + name = models.CharField(max_length=250, verbose_name=_("Name"), default="") geom = models.GeometryField(srid=settings.SRID) geom_buffered = models.GeometryField(srid=settings.SRID, editable=False) species = models.ForeignKey( @@ -152,7 +153,7 @@ class Meta: permissions = (("import_sensitivearea", "Can import Sensitive area"),) def __str__(self): - return self.species.name + return self.name @property def radius(self): @@ -216,17 +217,28 @@ def published_langs(self): return [] @property - def species_display(self): - s = f'{self.species.name}' - if self.published: - s = ( - ' '.format( - _("Published") - ) - + s + def area_name(self): + if self.species.category == 1: + return ( + self.species.name if (self.name == "" or not self.name) else self.name ) + return self.name + + @classproperty + def area_name_verbose_name(cls): + return _("Published name") + + @property + def name_display(self): + s = f'{self.area_name}' + if self.published: + s = f""" {s}""" return s + @property + def species_display(self): + return self.species.name + @property def extent(self): return ( @@ -251,7 +263,7 @@ def kml(self): geom = GEOSGeometry(Polygon(geometry), srid=settings.SRID) geom = geom.transform(4326, clone=True) # KML uses WGS84 line = kml.newpolygon( - name=self.species.name, + name=self.name, description=plain_text(self.description), altitudemode=simplekml.AltitudeMode.relativetoground, outerboundaryis=simplify_coords(geom.coords[0]), diff --git a/geotrek/sensitivity/serializers.py b/geotrek/sensitivity/serializers.py index b57e571be6..e8de2f0012 100644 --- a/geotrek/sensitivity/serializers.py +++ b/geotrek/sensitivity/serializers.py @@ -8,7 +8,8 @@ class SensitiveAreaSerializer(DynamicFieldsMixin, rest_serializers.ModelSerializer): category = rest_serializers.CharField(source="category_display") structure = rest_serializers.SlugRelatedField("name", read_only=True) - species = rest_serializers.CharField(source="species_display") + species = rest_serializers.CharField(source="species.name") + name = rest_serializers.CharField(source="name_display") class Meta: model = sensitivity_models.SensitiveArea diff --git a/geotrek/sensitivity/templates/sensitivity/sensitivearea_detail_attributes.html b/geotrek/sensitivity/templates/sensitivity/sensitivearea_detail_attributes.html index 9879705a83..3cf9287e09 100644 --- a/geotrek/sensitivity/templates/sensitivity/sensitivearea_detail_attributes.html +++ b/geotrek/sensitivity/templates/sensitivity/sensitivearea_detail_attributes.html @@ -15,17 +15,16 @@ {{ sensitivearea|verbose:"structure" }} {{ sensitivearea.structure }} - {% if sensitivearea.species.category == 2 %} + {% if sensitivearea.species.category == 1 %} - {{ sensitivearea.species|verbose:"name" }} - {{ sensitivearea.species.name }} - - {% else %} - - {{ sensitivearea|verbose:"species" }} - {{ sensitivearea.species }} + {{ sensitivearea|verbose:"area_name" }} + {{ sensitivearea.area_name }} {% endif %} + + {{ sensitivearea|verbose:"name" }} + {{ sensitivearea.name }} + {% trans "Period" %} {{ sensitivearea.species.pretty_period }} diff --git a/geotrek/sensitivity/tests/factories.py b/geotrek/sensitivity/tests/factories.py index 79a662e04a..488d121067 100644 --- a/geotrek/sensitivity/tests/factories.py +++ b/geotrek/sensitivity/tests/factories.py @@ -57,6 +57,7 @@ class SensitiveAreaFactory(StructureRelatedDefaultFactory): class Meta: model = models.SensitiveArea + name = "Sensitive area" species = factory.SubFactory(SpeciesFactory) geom = "POLYGON((700000 6600000, 700000 6600003, 700003 6600003, 700003 6600000, 700000 6600000))" published = True diff --git a/geotrek/sensitivity/tests/test_views.py b/geotrek/sensitivity/tests/test_views.py index a5a16398f6..0189a95823 100644 --- a/geotrek/sensitivity/tests/test_views.py +++ b/geotrek/sensitivity/tests/test_views.py @@ -88,7 +88,7 @@ def setUp(self): def test_species_name_shown_in_detail_page(self): url = reverse("sensitivity:sensitivearea_detail", kwargs={"pk": self.area.pk}) response = self.client.get(url) - self.assertContains(response, self.area.species.name) + self.assertContains(response, self.area.name) class SensitiveAreaOpenAirViewsTest(TestCase): diff --git a/geotrek/sensitivity/translation.py b/geotrek/sensitivity/translation.py index aa910cd1b3..e3eb8fbf34 100644 --- a/geotrek/sensitivity/translation.py +++ b/geotrek/sensitivity/translation.py @@ -23,7 +23,10 @@ class SpeciesTO(TranslationOptions): class SensitiveAreaTO(TranslationOptions): - fields = ("description",) + fields = ( + "name", + "description", + ) translator.register(Rule, RuleTO) diff --git a/geotrek/sensitivity/views.py b/geotrek/sensitivity/views.py index dc5a802766..2d1c2ced49 100644 --- a/geotrek/sensitivity/views.py +++ b/geotrek/sensitivity/views.py @@ -34,8 +34,8 @@ class SensitiveAreaList(CustomColumnsMixin, MapEntityList): queryset = SensitiveArea.objects.existing() - mandatory_columns = ["id", "species"] - default_extra_columns = ["category"] + mandatory_columns = ["id", "name"] + default_extra_columns = ["species", "category"] class SensitiveAreaFilter(MapEntityFilter): diff --git a/geotrek/trekking/templates/trekking/trek_public_pdf_base.html b/geotrek/trekking/templates/trekking/trek_public_pdf_base.html index 4bc3c1e9bc..b806f4ffc1 100644 --- a/geotrek/trekking/templates/trekking/trek_public_pdf_base.html +++ b/geotrek/trekking/templates/trekking/trek_public_pdf_base.html @@ -380,7 +380,7 @@

{% trans "Environmental sensitive areas" %}

{% for area in object.published_sensitive_areas %}
{% if area.species.pictogram %}{% endif %} -

{{ area.species.name }}

+

{{ area.name }}

{% trans "Sensitivity period:" %} {{ area.pretty_period }}

{% if area.contact %}

{% trans "Contact:" %} {{ area.contact|safe }}

{% endif %}

{{ area.description|safe }}