diff --git a/geotrek/api/v2/serializers.py b/geotrek/api/v2/serializers.py
index 656b1fc79e..4917b3f285 100644
--- a/geotrek/api/v2/serializers.py
+++ b/geotrek/api/v2/serializers.py
@@ -2095,7 +2095,9 @@ class SignageSerializer(DynamicFieldsMixin, serializers.ModelSerializer):
read_only=True, source="geom3d_transformed", precision=7
)
attachments = AttachmentSerializer(many=True)
- blades = BladeSerializer(source="blades_set", many=True)
+ # TODO: why did it use to refer to the related name `blades_set` for
+ # the `topology` field of Blade?
+ blades = BladeSerializer(source="blade_set", many=True)
provider = serializers.SlugRelatedField(read_only=True, slug_field="name")
condition = serializers.SerializerMethodField(
help_text=_(
diff --git a/geotrek/maintenance/templates/maintenance/sql/post_10_interventions.sql b/geotrek/maintenance/templates/maintenance/sql/post_10_interventions.sql
index 91f1a61309..76ee17615e 100644
--- a/geotrek/maintenance/templates/maintenance/sql/post_10_interventions.sql
+++ b/geotrek/maintenance/templates/maintenance/sql/post_10_interventions.sql
@@ -32,6 +32,8 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
+-- TODO: this function is never called
+-- Its trigger was removed in this PR: https://github.com/GeotrekCE/Geotrek-admin/pull/2218
CREATE FUNCTION {{ schema_geotrek }}.delete_related_intervention_blade() RETURNS trigger SECURITY DEFINER AS $$
BEGIN
UPDATE maintenance_intervention SET deleted = NEW.deleted WHERE target_id = NEW.id AND target_type_id IN (SELECT id FROM django_content_type AS ct WHERE ct.model = 'blade');
diff --git a/geotrek/signage/filters.py b/geotrek/signage/filters.py
index 32e12326fa..495d93c927 100644
--- a/geotrek/signage/filters.py
+++ b/geotrek/signage/filters.py
@@ -84,7 +84,7 @@ def filter_intervention_year(self, qs, name, value):
class BladeFilterSet(MapEntityFilterSet):
- bbox = PolygonTopologyFilter(field_name="topology", lookup_expr="intersects")
+ bbox = PolygonTopologyFilter(field_name="signage__topo_object", lookup_expr="intersects")
structure = ModelMultipleChoiceFilter(
field_name="signage__structure",
queryset=Structure.objects.all(),
diff --git a/geotrek/signage/forms.py b/geotrek/signage/forms.py
index 6766e97f45..7aaad991b6 100644
--- a/geotrek/signage/forms.py
+++ b/geotrek/signage/forms.py
@@ -54,7 +54,6 @@ class Meta:
class BaseBladeForm(CommonForm):
- geomfields = ["topology"]
fieldslayout = (
[
@@ -96,7 +95,6 @@ def __init__(self, *args, **kwargs):
del self.fields["direction"]
def save(self, *args, **kwargs):
- self.instance.set_topology(self.signage)
self.instance.signage = self.signage
return super(CommonForm, self).save(*args, **kwargs)
@@ -132,38 +130,9 @@ class Meta:
fields = ["id", "number", "direction", "type", "conditions", "color"]
-if settings.TREKKING_TOPOLOGY_ENABLED:
-
- class BladeForm(BaseBladeForm):
- topology = TopologyField(label="")
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.fields["topology"].initial = self.signage
- self.fields["topology"].widget.modifiable = True
- self.fields["topology"].label = "{}{} {}".format(
- self.instance.signage_display,
- _("On %s") % _(self.signage.kind.lower()),
- f'{self.signage!s}',
- )
-
-else:
-
- class BladeForm(BaseBladeForm):
- topology = GeometryField(label="")
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.fields["topology"].initial = self.signage.geom
- self.fields["topology"].widget = MapWidget(attrs={"geom_type": "POINT"})
- self.fields["topology"].widget.modifiable = False
- self.fields["topology"].label = "{}{} {}".format(
- self.instance.signage_display,
- _("On %s") % _(self.signage.kind.lower()),
- f'{self.signage!s}',
- )
+class BladeForm(BaseBladeForm):
+ # TODO: display uneditable map
+ ...
if settings.TREKKING_TOPOLOGY_ENABLED:
diff --git a/geotrek/signage/migrations/0045_remove_blade_topology.py b/geotrek/signage/migrations/0045_remove_blade_topology.py
new file mode 100644
index 0000000000..df5ae6aa7d
--- /dev/null
+++ b/geotrek/signage/migrations/0045_remove_blade_topology.py
@@ -0,0 +1,17 @@
+# Generated by Django 4.2.23 on 2025-08-19 10:39
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('signage', '0044_auto_20250611_1417'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='blade',
+ name='topology',
+ ),
+ ]
diff --git a/geotrek/signage/models.py b/geotrek/signage/models.py
index 5fe4d93ef6..023b165f3a 100755
--- a/geotrek/signage/models.py
+++ b/geotrek/signage/models.py
@@ -315,12 +315,6 @@ class Blade(
conditions = models.ManyToManyField(
BladeCondition, related_name="blades", verbose_name=_("Condition"), blank=True
)
- topology = models.ForeignKey(
- Topology,
- related_name="blades_set",
- verbose_name=_("Blades"),
- on_delete=models.CASCADE,
- )
colorblade_verbose_name = _("Color")
printedelevation_verbose_name = _("Printed elevation")
direction_verbose_name = _("Direction")
@@ -339,6 +333,7 @@ def zoning_property(self):
@classproperty
def geomfield(cls):
+ # TODO: ensure this keeps working
return Topology._meta.get_field("geom")
def __str__(self):
@@ -346,12 +341,6 @@ def __str__(self):
signagecode=self.signage.code, bladenumber=self.number
)
- def set_topology(self, topology):
- self.topology = topology
- if not self.is_signage:
- msg = "Expecting a signage"
- raise ValueError(msg)
-
@property
def conditions_display(self):
return ", ".join(
@@ -362,20 +351,26 @@ def conditions_display(self):
def paths(self):
return self.signage.paths.all()
- @property
- def is_signage(self):
- if self.topology:
- return self.topology.kind == Signage.KIND
- return False
+ # TODO: deprecate this method instead of removing it?
+ # @property
+ # def is_signage(self):
+ # if self.topology:
+ # return self.topology.kind == Signage.KIND
+ # return False
@property
def geom(self):
return self.signage.geom
+ # TODO
@geom.setter
def geom(self, value):
self._geom = value
+ @property
+ def topology(self):
+ return self.signage.topo_object
+
@property
def signage_display(self):
return f'
'
@@ -434,12 +429,6 @@ def distance(self, to_cls):
return settings.TREK_SIGNAGE_INTERSECTION_MARGIN
-@receiver(pre_delete, sender=Topology)
-def log_cascade_deletion_from_blade_topology(sender, instance, using, **kwargs):
- # Blade are deleted when Topology are deleted
- log_cascade_deletion(sender, instance, Blade, "topology")
-
-
@receiver(pre_delete, sender=Signage)
def log_cascade_deletion_from_blade_signage(sender, instance, using, **kwargs):
# Blade are deleted when Signage are deleted
diff --git a/geotrek/signage/templates/signage/sql/post_90_defaults.sql b/geotrek/signage/templates/signage/sql/post_90_defaults.sql
index 53bc179b97..69b2dad328 100644
--- a/geotrek/signage/templates/signage/sql/post_90_defaults.sql
+++ b/geotrek/signage/templates/signage/sql/post_90_defaults.sql
@@ -58,7 +58,6 @@ ALTER TABLE signage_bladetype ALTER COLUMN date_update SET DEFAULT now();
-- type
-- color
-- condition
--- topology
ALTER TABLE signage_blade ALTER COLUMN date_insert SET DEFAULT now();
ALTER TABLE signage_blade ALTER COLUMN date_update SET DEFAULT now();
diff --git a/geotrek/signage/tests/test_models.py b/geotrek/signage/tests/test_models.py
index 3ccb5da618..671736b253 100644
--- a/geotrek/signage/tests/test_models.py
+++ b/geotrek/signage/tests/test_models.py
@@ -37,12 +37,6 @@ def setUpTestData(cls):
if not user:
UserFactory(username="__internal__")
- def test_set_topology_other_error(self):
- blade = BladeFactory.create()
- infra = InfrastructureFactory.create()
- with self.assertRaisesRegex(ValueError, "Expecting a signage"):
- blade.set_topology(infra)
-
def test_cascading_deletions(self):
blade = BladeFactory.create()
topo_pk = blade.topology.pk