This commit is contained in:
Karl Determe 2026-10-09 13:17:59 +02:00
commit 4823d55f08
5 changed files with 506 additions and 10 deletions

View file

@ -0,0 +1,108 @@
# Generated by Django 6.0.7 on 2026-10-07 15:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('assets', '0030_managementzone_managementzonedocument_and_more'),
]
operations = [
migrations.AddField(
model_name='naturetree',
name='amenity_value',
field=models.FloatField(blank=True, null=True, verbose_name="Valeur d'aménité (€)"),
),
migrations.AddField(
model_name='naturetree',
name='biodiversity_index',
field=models.FloatField(blank=True, null=True, verbose_name='Indice de biodiversité'),
),
migrations.AddField(
model_name='naturetree',
name='carbon_stock',
field=models.FloatField(blank=True, null=True, verbose_name='Stock de carbone (t CO2)'),
),
migrations.AddField(
model_name='naturetree',
name='cooling_energy_indicator',
field=models.FloatField(blank=True, null=True, verbose_name='Énergie de refroidissement (kWh)'),
),
migrations.AddField(
model_name='naturetree',
name='cooling_indicator',
field=models.FloatField(blank=True, null=True, verbose_name='Indice de rafraîchissement'),
),
migrations.AddField(
model_name='naturetree',
name='cultivar',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Cultivar / Variété'),
),
migrations.AddField(
model_name='naturetree',
name='death_date',
field=models.DateField(blank=True, null=True, verbose_name='Date de dépérissement / mort'),
),
migrations.AddField(
model_name='naturetree',
name='genus',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Genre botanique'),
),
migrations.AddField(
model_name='naturetree',
name='is_chronoxyle',
field=models.BooleanField(default=False, verbose_name='Arbre sénescent / Chronoxyle (bois mort sur pied)'),
),
migrations.AddField(
model_name='naturetree',
name='is_dead',
field=models.BooleanField(default=False, verbose_name='Arbre mort'),
),
migrations.AddField(
model_name='naturetree',
name='is_stump',
field=models.BooleanField(default=False, verbose_name='Souche'),
),
migrations.AddField(
model_name='naturetree',
name='management_type',
field=models.CharField(blank=True, choices=[('municipal', 'Communal (Régie communale)'), ('regional', 'Régional (Bruxelles Mobilité / Région)'), ('community', 'Intercommunal / Autre pouvoir public'), ('private', 'Privé / Tiers')], default='municipal', max_length=50, null=True, verbose_name='Type de gestionnaire'),
),
migrations.AddField(
model_name='naturetree',
name='managing_authority',
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Autorité gestionnaire'),
),
migrations.AddField(
model_name='naturetree',
name='number_of_trunks',
field=models.IntegerField(blank=True, default=1, null=True, verbose_name='Nombre de troncs / Cépée'),
),
migrations.AddField(
model_name='naturetree',
name='plantation_coefficient',
field=models.FloatField(blank=True, null=True, verbose_name='Coefficient de plantation'),
),
migrations.AddField(
model_name='naturetree',
name='planting_date',
field=models.DateField(blank=True, null=True, verbose_name='Date de plantation réelle'),
),
migrations.AddField(
model_name='naturetree',
name='scientific_name',
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Nom scientifique / latin'),
),
migrations.AddField(
model_name='naturetree',
name='situation_coefficient',
field=models.FloatField(blank=True, null=True, verbose_name='Coefficient de situation'),
),
migrations.AddField(
model_name='naturetree',
name='vernacular_name',
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='Nom vernaculaire / Essence'),
),
]

View file

@ -146,6 +146,13 @@ TREE_PRUNING_CHOICES = [
('none', _("Non taillé / Entretien minimal")),
]
TREE_MANAGEMENT_TYPE_CHOICES = [
('municipal', _("Communal (Régie communale)")),
('regional', _("Régional (Bruxelles Mobilité / Région)")),
('community', _("Intercommunal / Autre pouvoir public")),
('private', _("Privé / Tiers")),
]
BULB_TYPE_CHOICES = [
('tulipes', _('Tulipes')),
@ -224,6 +231,37 @@ class NatureTree(AbstractGeoAsset):
pruning_frequency_years = models.IntegerField(null=True, blank=True, verbose_name=_("Périodicité de taille (années)"))
last_pruning_date = models.DateField(null=True, blank=True, verbose_name=_("Dernière taille / élagage"))
# Gestionnaire & Compétence
managing_authority = models.CharField(max_length=200, null=True, blank=True, verbose_name=_("Autorité gestionnaire"))
management_type = models.CharField(max_length=50, choices=TREE_MANAGEMENT_TYPE_CHOICES, default='municipal', null=True, blank=True, verbose_name=_("Type de gestionnaire"))
# Taxonomie & Botanique
vernacular_name = models.CharField(max_length=200, null=True, blank=True, verbose_name=_("Nom vernaculaire / Essence"))
scientific_name = models.CharField(max_length=200, null=True, blank=True, verbose_name=_("Nom scientifique / latin"))
genus = models.CharField(max_length=100, null=True, blank=True, verbose_name=_("Genre botanique"))
cultivar = models.CharField(max_length=100, null=True, blank=True, verbose_name=_("Cultivar / Variété"))
# Dendrométrie & Morphologie complémentaire
number_of_trunks = models.IntegerField(null=True, blank=True, default=1, verbose_name=_("Nombre de troncs / Cépée"))
# Éco-services & Valeur patrimoniale (Indicateurs écosystémiques)
amenity_value = models.FloatField(null=True, blank=True, verbose_name=_("Valeur d'aménité (€)"))
carbon_stock = models.FloatField(null=True, blank=True, verbose_name=_("Stock de carbone (t CO2)"))
cooling_indicator = models.FloatField(null=True, blank=True, verbose_name=_("Indice de rafraîchissement"))
cooling_energy_indicator = models.FloatField(null=True, blank=True, verbose_name=_("Énergie de refroidissement (kWh)"))
biodiversity_index = models.FloatField(null=True, blank=True, verbose_name=_("Indice de biodiversité"))
# Évaluation patrimoniale & Barème
situation_coefficient = models.FloatField(null=True, blank=True, verbose_name=_("Coefficient de situation"))
plantation_coefficient = models.FloatField(null=True, blank=True, verbose_name=_("Coefficient de plantation"))
# Statut biologique particulier
is_dead = models.BooleanField(default=False, verbose_name=_("Arbre mort"))
is_stump = models.BooleanField(default=False, verbose_name=_("Souche"))
is_chronoxyle = models.BooleanField(default=False, verbose_name=_("Arbre sénescent / Chronoxyle (bois mort sur pied)"))
death_date = models.DateField(null=True, blank=True, verbose_name=_("Date de dépérissement / mort"))
planting_date = models.DateField(null=True, blank=True, verbose_name=_("Date de plantation réelle"))
# Références des choix pour utilisation simple dans les templates
DEVELOPMENT_STAGE_CHOICES = TREE_DEVELOPMENT_STAGE_CHOICES
VITALITY_CHOICES = TREE_VITALITY_CHOICES
@ -233,6 +271,7 @@ class NatureTree(AbstractGeoAsset):
PIT_TYPE_CHOICES = TREE_PIT_TYPE_CHOICES
PROTECTION_CHOICES = TREE_PROTECTION_CHOICES
PRUNING_CHOICES = TREE_PRUNING_CHOICES
MANAGEMENT_TYPE_CHOICES = TREE_MANAGEMENT_TYPE_CHOICES
indexes = [
models.Index(fields=["code"]),

View file

@ -64,6 +64,16 @@
{% endfor %}
</select>
</div>
<div class="col-12">
<label for="management_type" class="form-label">{% translate "Gestionnaire / Compétence" %}</label>
<select name="management_type" id="management_type" class="form-select" multiple>
{% for key, value in management_type_choices %}
<option value="{{ key }}" {% if key in selected_management_types %}selected{% endif %}>
{{ value }}
</option>
{% endfor %}
</select>
</div>
<div class="col-12 d-flex justify-content-between mt-4" style="width: 200px;">
<button type="button" id="apply-assets-filters" class="btn btn-sm btn-primary">{% translate "Filtrer" %}</button>
<button type="button" id="reset-assets-filters" class="btn btn-sm btn-secondary">{% translate "Réinitialiser" %}</button>
@ -86,12 +96,15 @@
{ field: 'highway', title: '{% translate "Ring/Autoroute" %}', align: 'center' }
];
var assets_property_fields = ['category', 'model', 'area'];
var assets_property_fields = ['code', 'name', 'managing_authority', 'model', 'scientific_name', 'area'];
var assets_columns = [
{ field: 'category', title: '{% translate "Catégorie" %}' },
{ field: 'code', title: '{% translate "Code" %}' },
{ field: 'name', title: '{% translate "Nom" %}' },
{ field: 'managing_authority', title: '{% translate "Gestionnaire" %}' },
{ field: 'model', title: '{% translate "Modèle" %}' },
{ field: 'scientific_name', title: '{% translate "Botanique" %}' },
{ field: 'area', title: '{% translate "Superficie" %}' }
]
];
const locations_layer_def = {
@ -161,16 +174,25 @@
16, 5,
20, 8
],
'circle-color': ['coalesce', ['get', 'color'], '#0277BD'],
'circle-color': [
'case',
['==', ['get', 'management_type'], 'regional'], '#1E3A8A',
['boolean', ['get', 'is_remarkable'], false], '#F59E0B',
['coalesce', ['get', 'color'], '#15803D']
],
'circle-stroke-width': [
'case',
['boolean', ['feature-state', 'highlighted'], false], 2,
['boolean', ['feature-state', 'highlighted'], false], 2.5,
['==', ['get', 'management_type'], 'regional'], 1.5,
['boolean', ['get', 'is_remarkable'], false], 2,
1
],
'circle-stroke-color': [
'case',
['boolean', ['feature-state', 'highlighted'], false], '#ff0000',
'#000000'
['boolean', ['feature-state', 'highlighted'], false], '#EF4444',
['==', ['get', 'management_type'], 'regional'], '#93C5FD',
['boolean', ['get', 'is_remarkable'], false], '#FEF08A',
'#064E3B'
],
'circle-opacity': 0.8
},

View file

@ -88,6 +88,24 @@
{% if asset.is_remarkable %}
<span class="badge bg-warning text-dark ms-1 shadow-sm"><i class="bi bi-star-fill text-warning me-1"></i>{% translate "Arbre remarquable" %}</span>
{% endif %}
{# Badge Gestionnaire #}
{% if asset.managing_authority %}
<span class="badge {% if asset.management_type == 'regional' %}bg-primary-subtle text-primary border border-primary{% else %}bg-success-subtle text-success border border-success{% endif %} ms-1">
<i class="bi bi-buildings me-1"></i>{{ asset.managing_authority }}
</span>
{% elif asset.management_type %}
<span class="badge bg-secondary-subtle text-secondary border ms-1">{{ asset.get_management_type_display }}</span>
{% endif %}
{# Badges Biologiques Spéciaux #}
{% if asset.is_dead %}
<span class="badge bg-dark text-white ms-1"><i class="bi bi-x-circle me-1"></i>{% translate "Mort" %}</span>
{% elif asset.is_stump %}
<span class="badge bg-secondary text-white ms-1"><i class="bi bi-dash-circle me-1"></i>{% translate "Souche" %}</span>
{% elif asset.is_chronoxyle %}
<span class="badge bg-warning-subtle text-dark border border-warning ms-1"><i class="bi bi-recycle me-1"></i>{% translate "Chronoxyle" %}</span>
{% endif %}
</div>
<div class="d-flex align-items-center gap-2 mt-1" style="font-size: 0.8rem; color: #6c757d;">
@ -159,6 +177,24 @@
{% if asset.is_remarkable %}
<span class="badge bg-warning text-dark ms-1 shadow-sm"><i class="bi bi-star-fill text-warning me-1"></i>{% translate "Arbre remarquable" %}</span>
{% endif %}
{# Badge Gestionnaire #}
{% if asset.managing_authority %}
<span class="badge {% if asset.management_type == 'regional' %}bg-primary-subtle text-primary border border-primary{% else %}bg-success-subtle text-success border border-success{% endif %} ms-1">
<i class="bi bi-buildings me-1"></i>{{ asset.managing_authority }}
</span>
{% elif asset.management_type %}
<span class="badge bg-secondary-subtle text-secondary border ms-1">{{ asset.get_management_type_display }}</span>
{% endif %}
{# Badges Biologiques Spéciaux #}
{% if asset.is_dead %}
<span class="badge bg-dark text-white ms-1"><i class="bi bi-x-circle me-1"></i>{% translate "Mort" %}</span>
{% elif asset.is_stump %}
<span class="badge bg-secondary text-white ms-1"><i class="bi bi-dash-circle me-1"></i>{% translate "Souche" %}</span>
{% elif asset.is_chronoxyle %}
<span class="badge bg-warning-subtle text-dark border border-warning ms-1"><i class="bi bi-recycle me-1"></i>{% translate "Chronoxyle" %}</span>
{% endif %}
</div>
<div class="d-flex align-items-center gap-2 mt-1" style="font-size: 0.85rem; color: #6c757d;">
@ -221,6 +257,89 @@
</td>
</tr>
<!-- Autorité gestionnaire -->
<tr class="asset-editable-field" data-field="managing_authority" data-can-edit="{% if 'managing_authority' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Autorité gestionnaire" %}</th>
<td>
<div class="field-display">
<span class="field-value fw-semibold text-primary">
{% if asset.managing_authority %}
<i class="bi bi-bank me-1"></i>{{ asset.managing_authority }}
{% if asset.management_type %}
<small class="text-muted fw-normal">({{ asset.get_management_type_display }})</small>
{% endif %}
{% else %}
{{ asset.get_management_type_display|default:"-" }}
{% endif %}
</span>
</div>
<div class="field-edit d-none">
<input type="text" class="form-control form-control-sm" value="{{ asset.managing_authority|default:'' }}" placeholder="{% translate 'Ex: Commune de Watermael-Boitsfort' %}">
</div>
</td>
</tr>
<!-- Type de gestionnaire -->
<tr class="asset-editable-field" data-field="management_type" data-can-edit="{% if 'management_type' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Type de gestionnaire" %}</th>
<td>
<div class="field-display"><span class="field-value">{{ asset.get_management_type_display|default:"-" }}</span></div>
<div class="field-edit d-none">
<select class="form-select form-select-sm">
{% for val, lbl in asset.TREE_MANAGEMENT_TYPE_CHOICES %}
<option value="{{ val }}" {% if asset.management_type == val %}selected{% endif %}>{{ lbl }}</option>
{% endfor %}
</select>
</div>
</td>
</tr>
<!-- Nom scientifique / Latin -->
<tr class="asset-editable-field" data-field="scientific_name" data-can-edit="{% if 'scientific_name' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Nom scientifique / Latin" %}</th>
<td>
<div class="field-display">
<span class="field-value fst-italic fw-medium text-success">
{{ asset.scientific_name|default:"-" }}
</span>
</div>
<div class="field-edit d-none">
<input type="text" class="form-control form-control-sm" value="{{ asset.scientific_name|default:'' }}" placeholder="{% translate 'Ex: Prunus serrulata' %}">
</div>
</td>
</tr>
<!-- Nom vernaculaire / Essence -->
<tr class="asset-editable-field" data-field="vernacular_name" data-can-edit="{% if 'vernacular_name' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Nom vernaculaire / Essence" %}</th>
<td>
<div class="field-display"><span class="field-value">{{ asset.vernacular_name|default:"-" }}</span></div>
<div class="field-edit d-none">
<input type="text" class="form-control form-control-sm" value="{{ asset.vernacular_name|default:'' }}" placeholder="{% translate 'Ex: Cerisier du Japon' %}">
</div>
</td>
</tr>
<!-- Genre & Cultivar -->
{% if asset.genus or asset.cultivar or 'genus' in allowed_update_fields %}
<tr class="asset-editable-field" data-field="genus" data-can-edit="{% if 'genus' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Genre & Cultivar" %}</th>
<td>
<div class="field-display">
<span class="field-value">
{{ asset.genus|default:"-" }}{% if asset.cultivar %} '{{ asset.cultivar }}'{% endif %}
</span>
</div>
<div class="field-edit d-none">
<div class="row g-1">
<div class="col-6"><input type="text" class="form-control form-control-sm" placeholder="Genre" value="{{ asset.genus|default:'' }}"></div>
<div class="col-6"><input type="text" class="form-control form-control-sm" placeholder="Cultivar" value="{{ asset.cultivar|default:'' }}"></div>
</div>
</div>
</td>
</tr>
{% endif %}
<!-- Nom commun FR -->
<tr class="asset-editable-field" data-field="name_fr" data-can-edit="{% if 'name_fr' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Nom commun (FR)" %}</th>
@ -419,6 +538,25 @@
<table class="table table-striped mb-0 align-middle">
<tbody>
<!-- Nombre de troncs / Cépée -->
<tr class="asset-editable-field" data-field="number_of_trunks" data-can-edit="{% if 'number_of_trunks' in allowed_update_fields %}true{% else %}false{% endif %}">
<th style="width: 35%;">{% translate "Nombre de troncs (cépée)" %}</th>
<td>
<div class="field-display">
<span class="field-value">
{% if asset.number_of_trunks and asset.number_of_trunks > 1 %}
<span class="badge bg-secondary-subtle text-secondary border"><i class="bi bi-diagram-3 me-1"></i>{{ asset.number_of_trunks }} {% translate "troncs" %}</span>
{% else %}
1 {% translate "(tronc unique)" %}
{% endif %}
</span>
</div>
<div class="field-edit d-none">
<input type="number" step="1" min="1" class="form-control form-control-sm" value="{{ asset.number_of_trunks|default:1 }}">
</div>
</td>
</tr>
<!-- Hauteur totale -->
<tr class="asset-editable-field" data-field="height" data-can-edit="{% if 'height' in allowed_update_fields %}true{% else %}false{% endif %}">
<th style="width: 35%;">{% translate "Hauteur totale (m)" %}</th>
@ -518,6 +656,173 @@
</div>
{# ── CARTE ÉCO-SERVICES & VALEUR PATRIMONIALE (GRALITY / BARÈME DE L'ARBRE) ── #}
<div class="card mb-3 shadow-sm border-success-subtle">
<div class="card-header bg-success-subtle d-flex align-items-center justify-content-between">
<h5 class="mb-0 fs-6 fw-bold text-success-emphasis">
<i class="bi bi-feather me-2"></i>{% translate "Éco-services & Valeur patrimoniale" %}
</h5>
<span class="badge bg-success text-white">
<i class="bi bi-shield-check me-1"></i>{% translate "Indicateurs écologiques" %}
</span>
</div>
<div class="card-body">
{# 4 mini-widgets écologiques #}
<div class="row g-2 mb-3">
<!-- Valeur d'aménité -->
<div class="col-6 col-md-3">
<div class="p-2 border border-success-subtle rounded text-center bg-white shadow-sm tree-metric-widget">
<div class="small text-muted mb-1 metric-title text-truncate" title="{% translate "Valeur d'aménité calculée" %}">
<i class="bi bi-currency-euro text-success me-1"></i>{% translate "Aménité" %}
</div>
<div class="fs-5 fw-bold text-success metric-value">
{% if asset.amenity_value %}
{{ asset.amenity_value|floatformat:0 }} <small class="text-muted fw-normal" style="font-size: 0.75rem;">€</small>
{% else %}
<span class="text-muted fs-6">&mdash;</span>
{% endif %}
</div>
</div>
</div>
<!-- Stock carbone -->
<div class="col-6 col-md-3">
<div class="p-2 border border-primary-subtle rounded text-center bg-white shadow-sm tree-metric-widget">
<div class="small text-muted mb-1 metric-title text-truncate" title="{% translate 'Stock de carbone séquestré' %}">
<i class="bi bi-cloud-check text-primary me-1"></i>{% translate "Carbone" %}
</div>
<div class="fs-5 fw-bold text-primary metric-value">
{% if asset.carbon_stock %}
{{ asset.carbon_stock|floatformat:2 }} <small class="text-muted fw-normal" style="font-size: 0.75rem;">t CO₂</small>
{% else %}
<span class="text-muted fs-6">&mdash;</span>
{% endif %}
</div>
</div>
</div>
<!-- Rafraîchissement urbain -->
<div class="col-6 col-md-3">
<div class="p-2 border border-info-subtle rounded text-center bg-white shadow-sm tree-metric-widget">
<div class="small text-muted mb-1 metric-title text-truncate" title="{% translate 'Potentiel de rafraîchissement urbain' %}">
<i class="bi bi-thermometer-snow text-info me-1"></i>{% translate "Fraîcheur" %}
</div>
<div class="fs-5 fw-bold text-info-emphasis metric-value">
{% if asset.cooling_indicator %}
{{ asset.cooling_indicator|floatformat:1 }} <small class="text-muted fw-normal" style="font-size: 0.75rem;">/ 10</small>
{% else %}
<span class="text-muted fs-6">&mdash;</span>
{% endif %}
</div>
</div>
</div>
<!-- Indice de biodiversité -->
<div class="col-6 col-md-3">
<div class="p-2 border border-warning-subtle rounded text-center bg-white shadow-sm tree-metric-widget">
<div class="small text-muted mb-1 metric-title text-truncate" title="{% translate "Indice d'accueil biodiversité" %}">
<i class="bi bi-bug text-warning me-1"></i>{% translate "Biodiversité" %}
</div>
<div class="fs-5 fw-bold text-warning-emphasis metric-value">
{% if asset.biodiversity_index %}
{{ asset.biodiversity_index|floatformat:2 }}
{% else %}
<span class="text-muted fs-6">&mdash;</span>
{% endif %}
</div>
</div>
</div>
</div>
{# Table détaillée des indicateurs écosystémiques #}
<table class="table table-striped mb-0 align-middle">
<tbody>
<!-- Énergie de refroidissement -->
<tr class="asset-editable-field" data-field="cooling_energy_indicator" data-can-edit="{% if 'cooling_energy_indicator' in allowed_update_fields %}true{% else %}false{% endif %}">
<th style="width: 35%;">{% translate "Énergie de refroidissement (kWh)" %}</th>
<td>
<div class="field-display">
<span class="field-value">
{% if asset.cooling_energy_indicator %}
{{ asset.cooling_energy_indicator|floatformat:1 }} kWh
{% else %}
-
{% endif %}
</span>
</div>
<div class="field-edit d-none">
<input type="number" step="0.1" class="form-control form-control-sm" value="{{ asset.cooling_energy_indicator|default:'' }}">
</div>
</td>
</tr>
<!-- Coefficient de situation -->
<tr class="asset-editable-field" data-field="situation_coefficient" data-can-edit="{% if 'situation_coefficient' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Coefficient de situation (barème)" %}</th>
<td>
<div class="field-display"><span class="field-value">{{ asset.situation_coefficient|default:"-" }}</span></div>
<div class="field-edit d-none">
<input type="number" step="0.1" class="form-control form-control-sm" value="{{ asset.situation_coefficient|default:'' }}">
</div>
</td>
</tr>
<!-- Coefficient de plantation -->
<tr class="asset-editable-field" data-field="plantation_coefficient" data-can-edit="{% if 'plantation_coefficient' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Coefficient de plantation (barème)" %}</th>
<td>
<div class="field-display"><span class="field-value">{{ asset.plantation_coefficient|default:"-" }}</span></div>
<div class="field-edit d-none">
<input type="number" step="0.1" class="form-control form-control-sm" value="{{ asset.plantation_coefficient|default:'' }}">
</div>
</td>
</tr>
<!-- Date de plantation réelle -->
<tr class="asset-editable-field" data-field="planting_date" data-can-edit="{% if 'planting_date' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Date de plantation constatée" %}</th>
<td>
<div class="field-display">
<span class="field-value">
{% if asset.planting_date %}
<i class="bi bi-calendar3 me-1 text-muted"></i>{{ asset.planting_date|date:"d/m/Y" }}
{% else %}
-
{% endif %}
</span>
</div>
<div class="field-edit d-none">
<input type="date" class="form-control form-control-sm" value="{{ asset.planting_date|date:'Y-m-d'|default:'' }}">
</div>
</td>
</tr>
<!-- Date de dépérissement / mort -->
{% if asset.death_date or asset.is_dead or 'death_date' in allowed_update_fields %}
<tr class="asset-editable-field" data-field="death_date" data-can-edit="{% if 'death_date' in allowed_update_fields %}true{% else %}false{% endif %}">
<th>{% translate "Date de mort / dépérissement" %}</th>
<td>
<div class="field-display">
<span class="field-value text-danger">
{% if asset.death_date %}
<i class="bi bi-calendar-x me-1"></i>{{ asset.death_date|date:"d/m/Y" }}
{% else %}
-
{% endif %}
</span>
</div>
<div class="field-edit d-none">
<input type="date" class="form-control form-control-sm" value="{{ asset.death_date|date:'Y-m-d'|default:'' }}">
</div>
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
{# ── CARTE 3 : DIAGNOSTIC SANITAIRE & SÉCURITÉ ── #}
<div class="card mb-3 shadow-sm">
<div class="card-header bg-light d-flex align-items-center justify-content-between">

View file

@ -71,6 +71,14 @@ def nature_index(request):
categories.sort(key=lambda m: m.get_name().lower())
category_choices = [(m.id, m.get_name()) for m in categories]
selected_management_types = request.GET.getlist('management_type')
management_type_choices = [
('municipal', _("Communal (Commune)")),
('regional', _("Régional (Bruxelles Mobilité)")),
('community', _("Intercommunal / Communautaire")),
('private', _("Privé / Conventionné")),
]
models = list(NatureAssetModel.objects.all())
models.sort(key=lambda m: (m.get_name() or "").lower())
model_choices = [(m.id, m.get_name()) for m in models]
@ -92,6 +100,8 @@ def nature_index(request):
'model_choices': model_choices,
'category_model_map': dict(category_model_map),
'selected_thematic': selected_thematic,
'management_type_choices': management_type_choices,
'selected_management_types': selected_management_types,
'selected_statuses': statuses,
'selected_categories': selected_categories,
'selected_models': selected_models,
@ -551,7 +561,7 @@ def ensure_list(value):
return [value]
MAX_ASSET_FEATURES = 5000 # limite imposée
MAX_ASSET_FEATURES = 10000 # limite imposée
@check_thematic_access('nature')
def nature_assets_geojson(request):
@ -570,6 +580,7 @@ def nature_assets_geojson(request):
models = ensure_list(data.get('model'))
highway = data.get('highway') == "1"
location_type = data.get('location_type', '')
management_types = ensure_list(data.get('management_type'))
# Récupération et parsing de la géométrie
filter_geom_raw = data.get("filter_geom")
@ -590,11 +601,12 @@ def nature_assets_geojson(request):
models = request.GET.getlist('model', [])
highway = request.GET.get('highway') == "1"
location_type = request.GET.get('location_type', '')
management_types = request.GET.getlist('management_type', [])
filter_geom = None
_search_q = (data.get('q') or '').strip() if request.method == 'POST' else ''
if not request.GET.get('unified') and not sections_ids and not categories and not models and not filter_geom and not _search_q and not highway and not location_type: # return empty geojson if no param with section_id
if not request.GET.get('unified') and not sections_ids and not categories and not models and not filter_geom and not _search_q and not highway and not location_type and not management_types: # return empty geojson if no param with section_id
geojson_data = {
"type": "FeatureCollection",
"features": [],
@ -664,6 +676,11 @@ def nature_assets_geojson(request):
"thematic": "nature",
"is_location": False,
"structure_type": obj.get('structure_type', ''),
"managing_authority": obj.get('managing_authority') or '',
"management_type": obj.get('management_type') or '',
"is_remarkable": obj.get('is_remarkable', False),
"scientific_name": obj.get('scientific_name') or '',
"vernacular_name": obj.get('vernacular_name') or '',
}
}
@ -715,6 +732,9 @@ def nature_assets_geojson(request):
naturetree_qs = naturetree_qs.filter(model__id__in=models)
natureshrub_qs = natureshrub_qs.filter(model__id__in=models)
naturebench_qs = naturebench_qs.filter(model__id__in=models)
if management_types:
naturetree_qs = naturetree_qs.filter(management_type__in=management_types)
if categories:
naturegreensurface_qs = naturegreensurface_qs.filter(category__id__in=categories)
naturetree_qs = naturetree_qs.filter(category__id__in=categories)
@ -790,7 +810,9 @@ def nature_assets_geojson(request):
.values( # on limite strictement les colonnes
'id', 'code', 'name', 'status', 'validation_status', 'lon', 'lat',
'category_name', 'model_name', 'color', 'geojson',
'category_id', 'model_id', 'location_lon', 'location_lat'
'category_id', 'model_id', 'location_lon', 'location_lat',
'managing_authority', 'management_type', 'is_remarkable',
'scientific_name', 'vernacular_name'
)
.order_by('code')
)[:MAX_ASSET_FEATURES + 1]