territories-dashboard-lib 0.1.0__tar.gz → 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of territories-dashboard-lib might be problematic. Click here for more details.
- territories_dashboard_lib-0.1.2/MANIFEST.in +5 -0
- {territories_dashboard_lib-0.1.0 → territories_dashboard_lib-0.1.2}/PKG-INFO +1 -1
- {territories_dashboard_lib-0.1.0 → territories_dashboard_lib-0.1.2}/pyproject.toml +1 -2
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/commons/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/commons/decorators.py +36 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/commons/models.py +9 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/geo_lib/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/geo_lib/admin.py +64 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/geo_lib/enums.py +7 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/geo_lib/migrations/0001_initial.py +51 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/geo_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/geo_lib/models.py +58 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/geo_lib/urls.py +27 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/geo_lib/views.py +239 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/admin.py +140 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/enums.py +59 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/export.py +29 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/format.py +34 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/methodo_pdf.py +99 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/migrations/0001_initial.py +138 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/models.py +230 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/payloads.py +54 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/query/commons.py +223 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/query/comparison.py +70 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/query/details.py +64 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/query/histogram.py +82 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/query/indicator_card.py +102 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/query/top_10.py +100 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/query/utils.py +20 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/refresh_filters.py +17 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/table.py +154 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/urls.py +97 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/indicators_lib/views.py +490 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/admin.py +22 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/guest_token.py +64 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/logic.py +67 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/migrations/0001_initial.py +45 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/models.py +52 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/serializers.py +10 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/urls.py +10 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/superset_lib/views.py +19 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/tracking_lib/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/tracking_lib/enums.py +7 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/tracking_lib/logic.py +78 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/tracking_lib/migrations/0001_initial.py +45 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/tracking_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/tracking_lib/models.py +79 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/admin.py +40 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/context_processors.py +27 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/forms.py +47 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/migrations/0001_initial.py +91 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/models.py +148 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/navigation.py +124 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/params.py +268 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/serializers.py +105 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/css/website.css +956 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/chart.js +13 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/chartjs-plugin-datalabels.js +1 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/html2canvas.js +20 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/data.mjs +62 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/history.mjs +98 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/main-values.mjs +30 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/page.mjs +105 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/territory-chart.mjs +141 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/data.mjs +59 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/histogram.mjs +130 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/map.mjs +25 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/page.mjs +96 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/proportions.mjs +77 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/sankey.mjs +27 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/table.mjs +229 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/top10.mjs +76 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/utils.mjs +8 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/dom.mjs +92 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/enums.mjs +104 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/export-graph.mjs +15 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/export.mjs +20 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/filters.mjs +159 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/format.mjs +54 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/side_panel.mjs +103 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/history.mjs +89 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/main-value.mjs +22 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/page.mjs +162 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/statistics.mjs +42 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/utils.mjs +93 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/static/page.mjs +35 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/patternomaly.js +1452 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/react18.js +31 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/reactdom18.js +267 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/supersetEmbed.js +355 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/indicatorMap.bundle.js +2 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/sankeyGraph.bundle.js +2 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/vendors-node_modules_mapbox-gl_dist_mapbox-gl_js.bundle.js +2 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/static_content.py +20 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/admin/indicators_lib/indicator/change_form.html +8 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/404.html +10 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/500.html +10 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/base.html +42 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/base.js +47 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/footer.html +96 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/header.html +101 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/header.js +102 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/comparaison/[theme]/components/indicateur-card.html +48 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/comparaison/[theme]/page.html +52 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/chart-buttons.html +29 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/geo_params.html +71 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/indicator-card.html +52 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/loader.html +28 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel.html +27 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_geo.html +80 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_geo.js +85 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_methodo.html +45 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_methodo.js +19 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/themes-list.html +9 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/themes-nav.html +33 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/title.html +28 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/filters-reminder.html +19 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/table.html +123 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/page.html +166 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/components/extremum.html +15 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/components/indicateur-card.html +76 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/page.html +66 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/lexique/page.html +17 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/page.html +14 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/sitemap/page.html +71 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/static/page.html +16 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/superset/page.html +55 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templatetags/htmlparams.py +75 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/templatetags/other_filters.py +30 -0
- territories_dashboard_lib-0.1.2/territories_dashboard_lib/website_lib/views.py +212 -0
- {territories_dashboard_lib-0.1.0 → territories_dashboard_lib-0.1.2}/territories_dashboard_lib.egg-info/PKG-INFO +1 -1
- territories_dashboard_lib-0.1.2/territories_dashboard_lib.egg-info/SOURCES.txt +142 -0
- territories_dashboard_lib-0.1.0/territories_dashboard_lib.egg-info/SOURCES.txt +0 -8
- {territories_dashboard_lib-0.1.0 → territories_dashboard_lib-0.1.2}/README.md +0 -0
- {territories_dashboard_lib-0.1.0 → territories_dashboard_lib-0.1.2}/licence.md +0 -0
- {territories_dashboard_lib-0.1.0 → territories_dashboard_lib-0.1.2}/setup.cfg +0 -0
- {territories_dashboard_lib-0.1.0 → territories_dashboard_lib-0.1.2}/territories_dashboard_lib/__init__.py +0 -0
- {territories_dashboard_lib-0.1.0 → territories_dashboard_lib-0.1.2}/territories_dashboard_lib.egg-info/dependency_links.txt +0 -0
- {territories_dashboard_lib-0.1.0 → territories_dashboard_lib-0.1.2}/territories_dashboard_lib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "territories-dashboard-lib"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.2"
|
|
4
4
|
description = "Librairie pour la visualisation d'indicateurs territoriaux."
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Bastien", email = "bastien@prune.sh" }
|
|
@@ -19,7 +19,6 @@ classifiers = [
|
|
|
19
19
|
]
|
|
20
20
|
|
|
21
21
|
[tool.setuptools]
|
|
22
|
-
packages = ["territories_dashboard_lib"]
|
|
23
22
|
include-package-data = true
|
|
24
23
|
|
|
25
24
|
[build-system]
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
from typing import get_origin
|
|
3
|
+
|
|
4
|
+
from django.http import HttpResponse
|
|
5
|
+
from pydantic import ValidationError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def use_payload(payload_class):
|
|
9
|
+
def decorator(func):
|
|
10
|
+
@functools.wraps(func)
|
|
11
|
+
def wrapper(request, *args, **kwargs):
|
|
12
|
+
if request.method != "GET":
|
|
13
|
+
raise NotImplementedError
|
|
14
|
+
data = {}
|
|
15
|
+
for field_name, field in payload_class.model_fields.items():
|
|
16
|
+
url_name = field.alias if field.alias else field_name
|
|
17
|
+
is_list_field = get_origin(field.annotation) is list
|
|
18
|
+
url_value = (
|
|
19
|
+
request.GET.getlist(url_name)
|
|
20
|
+
if is_list_field
|
|
21
|
+
else request.GET.get(url_name)
|
|
22
|
+
)
|
|
23
|
+
if url_value is not None:
|
|
24
|
+
data[url_name] = url_value
|
|
25
|
+
try:
|
|
26
|
+
payload = payload_class.model_validate(data)
|
|
27
|
+
except ValidationError as e:
|
|
28
|
+
return HttpResponse(
|
|
29
|
+
e.json(), headers={"content_type": "application/json"}, status=400
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
return func(request, *args, payload=payload, **kwargs)
|
|
33
|
+
|
|
34
|
+
return wrapper
|
|
35
|
+
|
|
36
|
+
return decorator
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from django import forms
|
|
2
|
+
from django.contrib import admin
|
|
3
|
+
from django.db import models
|
|
4
|
+
from django.utils.safestring import mark_safe
|
|
5
|
+
|
|
6
|
+
from territories_dashboard_lib.geo_lib.models import GeoElement, GeoFeature
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GeoColumnInLine(admin.TabularInline):
|
|
10
|
+
model = GeoElement
|
|
11
|
+
fields = ["name", "label", "filterable"]
|
|
12
|
+
extra = 0
|
|
13
|
+
formfield_overrides = {
|
|
14
|
+
models.TextField: {"widget": forms.TextInput()},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class GeoFeatureForm(forms.ModelForm):
|
|
19
|
+
svg_file = forms.FileField(required=False, label="Charger un fichier SVG")
|
|
20
|
+
|
|
21
|
+
class Meta:
|
|
22
|
+
model = GeoFeature
|
|
23
|
+
fields = [
|
|
24
|
+
"indicator",
|
|
25
|
+
"name",
|
|
26
|
+
"title",
|
|
27
|
+
"unite",
|
|
28
|
+
"geo_type",
|
|
29
|
+
"color",
|
|
30
|
+
"show_on_fr_level",
|
|
31
|
+
"point_icon_svg",
|
|
32
|
+
"svg_file",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
def clean(self):
|
|
36
|
+
cleaned_data = super().clean()
|
|
37
|
+
svg_file = cleaned_data.get("svg_file")
|
|
38
|
+
|
|
39
|
+
if svg_file:
|
|
40
|
+
svg_content = svg_file.read().decode("utf-8")
|
|
41
|
+
cleaned_data["point_icon_svg"] = svg_content
|
|
42
|
+
|
|
43
|
+
return cleaned_data
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class GeoTableAdmin(admin.ModelAdmin):
|
|
47
|
+
form = GeoFeatureForm
|
|
48
|
+
inlines = [GeoColumnInLine]
|
|
49
|
+
formfield_overrides = {
|
|
50
|
+
models.TextField: {"widget": forms.TextInput()},
|
|
51
|
+
}
|
|
52
|
+
list_display = ["__str__", "indicator"]
|
|
53
|
+
list_filter = ["indicator"]
|
|
54
|
+
readonly_fields = ["svg_preview"]
|
|
55
|
+
|
|
56
|
+
def svg_preview(self, obj):
|
|
57
|
+
if obj.point_icon_svg:
|
|
58
|
+
return mark_safe(obj.point_icon_svg)
|
|
59
|
+
return "-"
|
|
60
|
+
|
|
61
|
+
svg_preview.short_description = "Prévisualisation du SVG"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
admin.site.register(GeoFeature, GeoTableAdmin)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Generated by Django 5.2.3 on 2025-06-19 07:13
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
initial = True
|
|
10
|
+
|
|
11
|
+
dependencies = [
|
|
12
|
+
('indicators_lib', '0001_initial'),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
operations = [
|
|
16
|
+
migrations.CreateModel(
|
|
17
|
+
name='GeoFeature',
|
|
18
|
+
fields=[
|
|
19
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
20
|
+
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
21
|
+
('updated_at', models.DateTimeField(auto_now=True)),
|
|
22
|
+
('name', models.TextField(help_text='attention le nom doit être exactement le même que celui en base.', verbose_name='Nom de la table en base')),
|
|
23
|
+
('title', models.TextField(default='à compléter', verbose_name='Titre à afficher')),
|
|
24
|
+
('unite', models.TextField(verbose_name='Unité au pluriel')),
|
|
25
|
+
('geo_type', models.TextField(choices=[('point', 'Point'), ('line', 'Line'), ('polygon', 'Polygon')], default='point', verbose_name='Type de géométrie')),
|
|
26
|
+
('point_icon_svg', models.TextField(blank=True, help_text="Icone SVG a utilisé pour les points.<br/>Laisser vide pour les autres types de géométrie.<br/>Veuillez charger un fichier provenant des <a href='/'>Material Icons</a> de Google.", null=True, verbose_name='Icone des points')),
|
|
27
|
+
('color', models.TextField(default='#000000', help_text="Couleur des données sur la date, à renseigner au format hexadécimal, par exemple: '#05B2F9'", verbose_name='Couleur')),
|
|
28
|
+
('show_on_fr_level', models.BooleanField(default=True, help_text='Décochez si la quantité de données est trop importante pour le niveau France entière.', verbose_name='Afficher au niveau France entière')),
|
|
29
|
+
('indicator', models.ForeignKey(help_text="Cette donnée géographique sera ajoutée à la carte de l'indicateur.", on_delete=django.db.models.deletion.CASCADE, related_name='geo_features', to='indicators_lib.indicator')),
|
|
30
|
+
],
|
|
31
|
+
options={
|
|
32
|
+
'verbose_name': 'Données de la carte',
|
|
33
|
+
'ordering': ('indicator', 'name'),
|
|
34
|
+
},
|
|
35
|
+
),
|
|
36
|
+
migrations.CreateModel(
|
|
37
|
+
name='GeoElement',
|
|
38
|
+
fields=[
|
|
39
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
40
|
+
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
41
|
+
('updated_at', models.DateTimeField(auto_now=True)),
|
|
42
|
+
('name', models.TextField(verbose_name='Nom de la colonne en DB')),
|
|
43
|
+
('label', models.TextField()),
|
|
44
|
+
('filterable', models.BooleanField(default=True, verbose_name='Filtrable')),
|
|
45
|
+
('geo_feature', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='geo_lib.geofeature')),
|
|
46
|
+
],
|
|
47
|
+
options={
|
|
48
|
+
'abstract': False,
|
|
49
|
+
},
|
|
50
|
+
),
|
|
51
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from django.db import models
|
|
2
|
+
|
|
3
|
+
from territories_dashboard_lib.commons.models import CommonModel
|
|
4
|
+
from territories_dashboard_lib.indicators_lib.models import Indicator
|
|
5
|
+
|
|
6
|
+
from .enums import GeoFeatureType
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GeoFeature(CommonModel):
|
|
10
|
+
name = models.TextField(
|
|
11
|
+
verbose_name="Nom de la table en base",
|
|
12
|
+
help_text="attention le nom doit être exactement le même que celui en base.",
|
|
13
|
+
)
|
|
14
|
+
title = models.TextField(verbose_name="Titre à afficher", default="à compléter")
|
|
15
|
+
unite = models.TextField(verbose_name="Unité au pluriel")
|
|
16
|
+
indicator = models.ForeignKey(
|
|
17
|
+
Indicator,
|
|
18
|
+
related_name="geo_features",
|
|
19
|
+
on_delete=models.CASCADE,
|
|
20
|
+
help_text="Cette donnée géographique sera ajoutée à la carte de l'indicateur.",
|
|
21
|
+
)
|
|
22
|
+
geo_type = models.TextField(
|
|
23
|
+
choices=GeoFeatureType.choices,
|
|
24
|
+
default=GeoFeatureType.point,
|
|
25
|
+
verbose_name="Type de géométrie",
|
|
26
|
+
)
|
|
27
|
+
point_icon_svg = models.TextField(
|
|
28
|
+
blank=True,
|
|
29
|
+
null=True,
|
|
30
|
+
verbose_name="Icone des points",
|
|
31
|
+
help_text="Icone SVG a utilisé pour les points.<br/>Laisser vide pour les autres types de géométrie.<br/>Veuillez charger un fichier provenant des <a href='/'>Material Icons</a> de Google.",
|
|
32
|
+
)
|
|
33
|
+
color = models.TextField(
|
|
34
|
+
default="#000000",
|
|
35
|
+
verbose_name="Couleur",
|
|
36
|
+
help_text="Couleur des données sur la date, à renseigner au format hexadécimal, par exemple: '#05B2F9'",
|
|
37
|
+
)
|
|
38
|
+
show_on_fr_level = models.BooleanField(
|
|
39
|
+
default=True,
|
|
40
|
+
verbose_name="Afficher au niveau France entière",
|
|
41
|
+
help_text="Décochez si la quantité de données est trop importante pour le niveau France entière.",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def __str__(self):
|
|
45
|
+
return self.name
|
|
46
|
+
|
|
47
|
+
class Meta:
|
|
48
|
+
ordering = ("indicator", "name")
|
|
49
|
+
verbose_name = "Données de la carte"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class GeoElement(CommonModel):
|
|
53
|
+
geo_feature = models.ForeignKey(
|
|
54
|
+
GeoFeature, related_name="items", on_delete=models.CASCADE
|
|
55
|
+
)
|
|
56
|
+
name = models.TextField(verbose_name="Nom de la colonne en DB")
|
|
57
|
+
label = models.TextField()
|
|
58
|
+
filterable = models.BooleanField(default=True, verbose_name="Filtrable")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from django.urls import path
|
|
2
|
+
|
|
3
|
+
from .views import (
|
|
4
|
+
geo_features_view,
|
|
5
|
+
main_territory_view,
|
|
6
|
+
precise_view,
|
|
7
|
+
search_territories_view,
|
|
8
|
+
territories_view,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
app_name = "geo-api"
|
|
12
|
+
|
|
13
|
+
urlpatterns = [
|
|
14
|
+
path(
|
|
15
|
+
"geo-features/",
|
|
16
|
+
geo_features_view,
|
|
17
|
+
name="geo-features",
|
|
18
|
+
),
|
|
19
|
+
path(
|
|
20
|
+
"main-territory/",
|
|
21
|
+
main_territory_view,
|
|
22
|
+
name="main-territory",
|
|
23
|
+
),
|
|
24
|
+
path("precise/", precise_view, name="precise"),
|
|
25
|
+
path("territories/", territories_view, name="territories"),
|
|
26
|
+
path("search-territories/", search_territories_view, name="search"),
|
|
27
|
+
]
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import gzip
|
|
3
|
+
import json
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from django.http import HttpResponse, JsonResponse
|
|
7
|
+
from django.shortcuts import get_object_or_404
|
|
8
|
+
from django.views.decorators.cache import cache_control
|
|
9
|
+
from django.views.decorators.http import require_GET
|
|
10
|
+
from psycopg2.sql import SQL, Identifier, Literal
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
|
|
13
|
+
from territories_dashboard_lib.indicators_lib.enums import (
|
|
14
|
+
FRANCE_GEOLEVEL_TITLES,
|
|
15
|
+
MESH_DB,
|
|
16
|
+
GeoLevel,
|
|
17
|
+
MeshLevel,
|
|
18
|
+
)
|
|
19
|
+
from territories_dashboard_lib.indicators_lib.query.commons import get_territories_ids
|
|
20
|
+
from territories_dashboard_lib.indicators_lib.query.utils import run_custom_query
|
|
21
|
+
|
|
22
|
+
from .enums import GeoFeatureType
|
|
23
|
+
from .models import GeoFeature
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class GeoFeaturesParams(BaseModel):
|
|
27
|
+
mesh: MeshLevel
|
|
28
|
+
geo_level: GeoLevel
|
|
29
|
+
main_territories: str
|
|
30
|
+
last: Optional[str] = None
|
|
31
|
+
limit: Optional[str] = "1000"
|
|
32
|
+
feature: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@require_GET
|
|
36
|
+
@cache_control(max_age=3600)
|
|
37
|
+
def geo_features_view(request):
|
|
38
|
+
params = GeoFeaturesParams(**request.GET.dict())
|
|
39
|
+
|
|
40
|
+
geo_feature = get_object_or_404(GeoFeature, id=params.feature)
|
|
41
|
+
geo_level = params.geo_level
|
|
42
|
+
mesh = params.mesh
|
|
43
|
+
main_territory_codes = params.main_territories.split(",")
|
|
44
|
+
last = params.last
|
|
45
|
+
limit = params.limit
|
|
46
|
+
|
|
47
|
+
last_year_query = (
|
|
48
|
+
f"SELECT DISTINCT annee FROM {geo_feature.name} ORDER BY annee DESC"
|
|
49
|
+
)
|
|
50
|
+
years = run_custom_query(last_year_query)
|
|
51
|
+
last_year = years[0].get("annee")
|
|
52
|
+
|
|
53
|
+
territories_ids = get_territories_ids(main_territory_codes, geo_level, mesh)
|
|
54
|
+
|
|
55
|
+
col_id_name = f"code_{mesh}"
|
|
56
|
+
columns = [el.name for el in geo_feature.items.all()]
|
|
57
|
+
|
|
58
|
+
coma = ", " if columns else ""
|
|
59
|
+
select_geo_code = (
|
|
60
|
+
f", geo.{col_id_name} AS geo_code"
|
|
61
|
+
if geo_feature.geo_type == GeoFeatureType.point
|
|
62
|
+
else ""
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
if geo_feature.geo_type == GeoFeatureType.point:
|
|
66
|
+
where_clause = f"WHERE geo.{col_id_name} IN ('{"', '".join(territories_ids)}')"
|
|
67
|
+
else:
|
|
68
|
+
where_clause = (
|
|
69
|
+
f"JOIN contours_simplified_{geo_level} contours ON ST_intersects(geo.geometry, contours.geometry)\n"
|
|
70
|
+
f"WHERE contours.code IN ('{"', '".join(main_territory_codes)}')"
|
|
71
|
+
)
|
|
72
|
+
where_clause += f" AND annee = {last_year}"
|
|
73
|
+
|
|
74
|
+
pagination = f"AND order_id > {last or 0} ORDER BY order_id ASC LIMIT {limit}"
|
|
75
|
+
|
|
76
|
+
query = (
|
|
77
|
+
f"SELECT ST_asgeojson(geo.geometry) AS geojson, order_id{coma + ', '.join(columns)}\n"
|
|
78
|
+
f"{select_geo_code}\n"
|
|
79
|
+
f"FROM {geo_feature.name} AS geo\n"
|
|
80
|
+
f"{where_clause} {pagination}"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Execute the query
|
|
84
|
+
results = run_custom_query(query)
|
|
85
|
+
items = geo_feature.items.all()
|
|
86
|
+
# Transform results
|
|
87
|
+
data = [
|
|
88
|
+
{
|
|
89
|
+
"type": "Feature",
|
|
90
|
+
"id": r.get("geo_code"),
|
|
91
|
+
"properties": {el.label: r.get(el.name) for el in items},
|
|
92
|
+
"geometry": json.loads(r.get("geojson")),
|
|
93
|
+
}
|
|
94
|
+
for r in results
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
last_queried_order_id = results[-1]["order_id"] if results else None
|
|
98
|
+
|
|
99
|
+
compressed_data = gzip.compress(json.dumps(data).encode())
|
|
100
|
+
compressed_base64 = base64.b64encode(compressed_data).decode()
|
|
101
|
+
|
|
102
|
+
return JsonResponse({"data": compressed_base64, "last": last_queried_order_id})
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class MainTerritoryParams(BaseModel):
|
|
106
|
+
geo_level: GeoLevel
|
|
107
|
+
geo_id: str
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@require_GET
|
|
111
|
+
@cache_control(max_age=3600)
|
|
112
|
+
def main_territory_view(request):
|
|
113
|
+
params = MainTerritoryParams(**request.GET.dict())
|
|
114
|
+
|
|
115
|
+
codes = ", ".join(f"'{code.strip()}'" for code in params.geo_id.split(","))
|
|
116
|
+
|
|
117
|
+
query = f"""
|
|
118
|
+
SELECT code as id, ST_asgeojson(ST_simplify(geometry, 0.01)) AS polygon
|
|
119
|
+
FROM contours_simplified_{params.geo_level}
|
|
120
|
+
WHERE code IN ({codes})
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
results = run_custom_query(query)
|
|
124
|
+
|
|
125
|
+
data = [
|
|
126
|
+
{
|
|
127
|
+
"id": r.get("id"),
|
|
128
|
+
"polygon": json.loads(r.get("polygon")),
|
|
129
|
+
}
|
|
130
|
+
for r in results
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
return JsonResponse(data, safe=False)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@require_GET
|
|
137
|
+
@cache_control(max_age=3600)
|
|
138
|
+
def precise_view(request):
|
|
139
|
+
territories_ids = request.GET.get("territories", "").split(",")
|
|
140
|
+
mesh_level = request.GET.get("mesh")
|
|
141
|
+
|
|
142
|
+
if not mesh_level:
|
|
143
|
+
return JsonResponse({"error": "Missing 'mesh' parameter"}, status=400)
|
|
144
|
+
|
|
145
|
+
mapped_mesh_level = "DEPCOM" if mesh_level == "com" else mesh_level.upper()
|
|
146
|
+
|
|
147
|
+
query = f"""
|
|
148
|
+
SELECT "{mapped_mesh_level}" AS id, ST_asgeojson(geometry) AS polygon
|
|
149
|
+
FROM contours_geo_ign_{mesh_level}
|
|
150
|
+
WHERE "{mapped_mesh_level}" IN ('{"', '".join(territories_ids)}')
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
results = run_custom_query(query)
|
|
154
|
+
|
|
155
|
+
territories = {r.get("id"): json.loads(r.get("polygon")) for r in results}
|
|
156
|
+
|
|
157
|
+
return JsonResponse(territories)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class TerritoryFeatureParams(BaseModel):
|
|
161
|
+
mesh: MeshLevel
|
|
162
|
+
geo_level: GeoLevel | None = None
|
|
163
|
+
main_territories: str | None = None
|
|
164
|
+
codes: str | None = None
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@require_GET
|
|
168
|
+
@cache_control(max_age=3600)
|
|
169
|
+
def territories_view(request):
|
|
170
|
+
params = TerritoryFeatureParams(**request.GET.dict())
|
|
171
|
+
geo_level = params.geo_level
|
|
172
|
+
mesh = params.mesh
|
|
173
|
+
|
|
174
|
+
if params.codes:
|
|
175
|
+
territories_ids = params.codes.split(",")
|
|
176
|
+
else:
|
|
177
|
+
main_territory_codes = params.main_territories.split(",")
|
|
178
|
+
territories_ids = get_territories_ids(main_territory_codes, geo_level, mesh)
|
|
179
|
+
|
|
180
|
+
query = f"""
|
|
181
|
+
SELECT code AS id, ST_asgeojson(geometry) AS polygon
|
|
182
|
+
FROM contours_simplified_{params.mesh}
|
|
183
|
+
WHERE code IN ('{"', '".join(territories_ids)}')
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
results = run_custom_query(query)
|
|
187
|
+
|
|
188
|
+
data = [
|
|
189
|
+
{"type": "Feature", "id": r.get("id"), "geometry": json.loads(r.get("polygon"))}
|
|
190
|
+
for r in results
|
|
191
|
+
]
|
|
192
|
+
return JsonResponse(data, safe=False)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _fill_territory_li(code, name, mesh):
|
|
196
|
+
label = name if mesh == MeshLevel.National else f"{name} - {code}"
|
|
197
|
+
return f"""<li data-code="{code}" data-name="{name}" onclick="chooseTerritory(this)"><button aria-label="Choisir {label}">{label}</button></li>"""
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@require_GET
|
|
201
|
+
@cache_control(max_age=3600)
|
|
202
|
+
def search_territories_view(request):
|
|
203
|
+
request_mesh = request.GET.get("mesh")
|
|
204
|
+
if request_mesh in MeshLevel:
|
|
205
|
+
mesh = request_mesh
|
|
206
|
+
else:
|
|
207
|
+
raise ValueError("mesh")
|
|
208
|
+
if mesh == MeshLevel.National:
|
|
209
|
+
lis = []
|
|
210
|
+
for code, name in FRANCE_GEOLEVEL_TITLES.items():
|
|
211
|
+
li = _fill_territory_li(code, name, mesh)
|
|
212
|
+
lis.append(li)
|
|
213
|
+
return HttpResponse("\n".join(lis))
|
|
214
|
+
mesh_db = MESH_DB[mesh]
|
|
215
|
+
pagination = 20
|
|
216
|
+
search = request.GET.get("search", "")
|
|
217
|
+
offset = int(request.GET.get("offset", 0))
|
|
218
|
+
query = SQL("""
|
|
219
|
+
SELECT DISTINCT {code} as code, {name} as name FROM arborescence_geo
|
|
220
|
+
WHERE unaccent({name}) || {code} ILIKE unaccent(%s)
|
|
221
|
+
AND "FR" <> 'ETR'
|
|
222
|
+
ORDER BY {name}, {code}
|
|
223
|
+
LIMIT {limit} OFFSET {offset};
|
|
224
|
+
;
|
|
225
|
+
""").format(
|
|
226
|
+
code=Identifier(mesh_db),
|
|
227
|
+
name=Identifier(f"NOM_{mesh_db}"),
|
|
228
|
+
offset=Literal(offset * pagination),
|
|
229
|
+
limit=Literal(pagination),
|
|
230
|
+
)
|
|
231
|
+
territories = run_custom_query(query, [f"%{search}%"])
|
|
232
|
+
lis = []
|
|
233
|
+
for territory in territories:
|
|
234
|
+
li = _fill_territory_li(territory["code"], territory["name"], mesh)
|
|
235
|
+
lis.append(li)
|
|
236
|
+
if len(territories) == pagination:
|
|
237
|
+
li = f"""<li data-type="load"><button onclick="loadMoreTerritories(this)" data-mesh="{mesh}" data-offset="{offset + 1}" class="fr-btn fr-btn--secondary fr-btn--sm">Charger plus de résultats</button></li>"""
|
|
238
|
+
lis.append(li)
|
|
239
|
+
return HttpResponse("\n".join(lis))
|
|
File without changes
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import nested_admin
|
|
2
|
+
from django.contrib import admin
|
|
3
|
+
from django.db.models import TextField
|
|
4
|
+
from django.forms import TextInput
|
|
5
|
+
from django.shortcuts import redirect
|
|
6
|
+
from django.urls import path, reverse
|
|
7
|
+
from django.utils.html import format_html
|
|
8
|
+
|
|
9
|
+
from territories_dashboard_lib.indicators_lib.methodo_pdf import reset_methodo_file
|
|
10
|
+
from territories_dashboard_lib.indicators_lib.models import (
|
|
11
|
+
Dimension,
|
|
12
|
+
Filter,
|
|
13
|
+
Indicator,
|
|
14
|
+
SubTheme,
|
|
15
|
+
Theme,
|
|
16
|
+
)
|
|
17
|
+
from territories_dashboard_lib.indicators_lib.refresh_filters import refresh_filters
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FilterInline(nested_admin.NestedTabularInline): # type: ignore
|
|
21
|
+
model = Filter
|
|
22
|
+
extra = 0
|
|
23
|
+
formfield_overrides = {TextField: {"widget": TextInput(attrs={"size": "32"})}}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class DimensionInline(nested_admin.NestedTabularInline): # type: ignore
|
|
27
|
+
model = Dimension
|
|
28
|
+
extra = 0
|
|
29
|
+
inlines = [FilterInline]
|
|
30
|
+
formfield_overrides = {TextField: {"widget": TextInput(attrs={"size": "32"})}}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class IndicatorAdmin(nested_admin.NestedModelAdmin):
|
|
34
|
+
model = Indicator
|
|
35
|
+
inlines = [DimensionInline]
|
|
36
|
+
list_display = [
|
|
37
|
+
"name",
|
|
38
|
+
"title",
|
|
39
|
+
"sub_theme",
|
|
40
|
+
"index_in_theme",
|
|
41
|
+
"is_active",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
def save_model(self, request, indicator, form, change):
|
|
45
|
+
super().save_model(request, indicator, form, change)
|
|
46
|
+
if "methodo" in form.changed_data:
|
|
47
|
+
reset_methodo_file(indicator)
|
|
48
|
+
|
|
49
|
+
def change_view(self, request, object_id, form_url="", extra_context=None):
|
|
50
|
+
extra_context = extra_context or {}
|
|
51
|
+
extra_context["refresh_url"] = f"../../{object_id}/refresh_filters/"
|
|
52
|
+
return super().change_view(request, object_id, form_url, extra_context)
|
|
53
|
+
|
|
54
|
+
def get_urls(self):
|
|
55
|
+
urls = super().get_urls()
|
|
56
|
+
custom_urls = [
|
|
57
|
+
path(
|
|
58
|
+
"<path:object_id>/refresh_filters/",
|
|
59
|
+
self.admin_site.admin_view(self.refresh_filters_view),
|
|
60
|
+
name="refresh_filters",
|
|
61
|
+
),
|
|
62
|
+
]
|
|
63
|
+
return custom_urls + urls
|
|
64
|
+
|
|
65
|
+
def refresh_filters_view(self, request, object_id):
|
|
66
|
+
indicator = Indicator.objects.get(pk=object_id)
|
|
67
|
+
try:
|
|
68
|
+
for dimension in indicator.dimensions.all():
|
|
69
|
+
refresh_filters(dimension)
|
|
70
|
+
self.message_user(request, "Les filtres ont été actualisés.")
|
|
71
|
+
except Exception as e:
|
|
72
|
+
print(e)
|
|
73
|
+
self.message_user(
|
|
74
|
+
request,
|
|
75
|
+
f"Erreur lors de l'actualisation des filtres: {str(e)}",
|
|
76
|
+
level="error",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return redirect("../")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class IndicatorInline(admin.TabularInline):
|
|
83
|
+
model = Indicator
|
|
84
|
+
extra = 0
|
|
85
|
+
fields = ["name", "index_in_theme", "link"]
|
|
86
|
+
readonly_fields = ["link"]
|
|
87
|
+
ordering = ["index_in_theme"]
|
|
88
|
+
|
|
89
|
+
def link(self, obj):
|
|
90
|
+
url = reverse("admin:indicators_lib_indicator_change", args=[obj.id])
|
|
91
|
+
return format_html(f'<a href="{url}">Edit</a>')
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class SubThemesInline(admin.TabularInline):
|
|
95
|
+
model = SubTheme
|
|
96
|
+
extra = 0
|
|
97
|
+
fields = [
|
|
98
|
+
"name",
|
|
99
|
+
"index_in_theme",
|
|
100
|
+
"indicators_count",
|
|
101
|
+
"is_displayed_on_app",
|
|
102
|
+
"link",
|
|
103
|
+
]
|
|
104
|
+
ordering = ["index_in_theme"]
|
|
105
|
+
readonly_fields = ["indicators_count", "is_displayed_on_app", "link"]
|
|
106
|
+
|
|
107
|
+
def link(self, obj):
|
|
108
|
+
url = reverse("admin:indicators_lib_subtheme_change", args=[obj.id])
|
|
109
|
+
return format_html(f'<a href="{url}">Edit</a>')
|
|
110
|
+
|
|
111
|
+
link.short_description = "Link"
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class ThemeAdmin(admin.ModelAdmin):
|
|
115
|
+
model = Theme
|
|
116
|
+
inlines = [SubThemesInline]
|
|
117
|
+
list_display = [
|
|
118
|
+
"title",
|
|
119
|
+
"ordering",
|
|
120
|
+
"subthemes_count",
|
|
121
|
+
"indicators_count",
|
|
122
|
+
"is_displayed_on_app",
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class SubThemeAdmin(admin.ModelAdmin):
|
|
127
|
+
model = SubTheme
|
|
128
|
+
inlines = [IndicatorInline]
|
|
129
|
+
list_display = [
|
|
130
|
+
"title",
|
|
131
|
+
"theme",
|
|
132
|
+
"index_in_theme",
|
|
133
|
+
"indicators_count",
|
|
134
|
+
"is_displayed_on_app",
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
admin.site.register(Theme, ThemeAdmin)
|
|
139
|
+
admin.site.register(SubTheme, SubThemeAdmin)
|
|
140
|
+
admin.site.register(Indicator, IndicatorAdmin)
|