territories-dashboard-lib 0.1.33b1__py3-none-any.whl → 1.1.1.dev7__py3-none-any.whl
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.
- territories_dashboard_lib/geo_lib/admin.py +3 -1
- territories_dashboard_lib/geo_lib/migrations/0002_geoelement_linked_to_indicator.py +18 -0
- territories_dashboard_lib/geo_lib/migrations/0003_geofeature_color_column_geofeature_size_column.py +23 -0
- territories_dashboard_lib/geo_lib/models.py +17 -0
- territories_dashboard_lib/geo_lib/payloads.py +7 -21
- territories_dashboard_lib/geo_lib/views.py +58 -53
- territories_dashboard_lib/indicators_lib/enums.py +61 -37
- territories_dashboard_lib/indicators_lib/methodo_pdf.py +6 -1
- territories_dashboard_lib/indicators_lib/migrations/0004_alter_indicator_min_mesh.py +18 -0
- territories_dashboard_lib/indicators_lib/migrations/0005_auto_20251203_1621.py +124 -0
- territories_dashboard_lib/indicators_lib/models.py +7 -4
- territories_dashboard_lib/indicators_lib/payloads.py +14 -1
- territories_dashboard_lib/indicators_lib/query/commons.py +90 -104
- territories_dashboard_lib/indicators_lib/query/comparison.py +8 -3
- territories_dashboard_lib/indicators_lib/query/details.py +8 -13
- territories_dashboard_lib/indicators_lib/query/histogram.py +6 -1
- territories_dashboard_lib/indicators_lib/query/indicator_card.py +12 -7
- territories_dashboard_lib/indicators_lib/query/top_10.py +13 -12
- territories_dashboard_lib/indicators_lib/query/utils.py +9 -0
- territories_dashboard_lib/indicators_lib/table.py +15 -12
- territories_dashboard_lib/indicators_lib/views.py +49 -59
- territories_dashboard_lib/superset_lib/logic.py +24 -25
- territories_dashboard_lib/superset_lib/migrations/0002_alter_filter_mesh.py +18 -0
- territories_dashboard_lib/tracking_lib/enums.py +1 -0
- territories_dashboard_lib/tracking_lib/migrations/0005_alter_page_cmp_territory_mesh_alter_page_submesh_and_more.py +28 -0
- territories_dashboard_lib/tracking_lib/migrations/0006_alter_event_name.py +18 -0
- territories_dashboard_lib/tracking_lib/payloads.py +4 -2
- territories_dashboard_lib/tracking_lib/views.py +7 -6
- territories_dashboard_lib/website_lib/conf.py +28 -0
- territories_dashboard_lib/website_lib/context_processors.py +5 -6
- territories_dashboard_lib/website_lib/migrations/0005_mainconf_meshes.py +20 -0
- territories_dashboard_lib/website_lib/models.py +12 -0
- territories_dashboard_lib/website_lib/params.py +34 -22
- territories_dashboard_lib/website_lib/serializers.py +1 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/anchor.mjs +45 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/page.mjs +5 -9
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/histogram.mjs +4 -1
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/page.mjs +2 -7
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/proportions.mjs +3 -2
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/top10.mjs +4 -2
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/utils.mjs +14 -5
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/dom.mjs +0 -15
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/enums.mjs +13 -10
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/side_panel.mjs +1 -15
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/page.mjs +5 -9
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/indicatorMap.bundle.js +1 -1
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/sankeyGraph.bundle.js +1 -1
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/vendors.bundle.js +1 -1
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/base.css +12 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/header.html +1 -1
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/comparaison/[theme]/page.html +4 -3
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/anchor.html +14 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/geo_params.html +3 -3
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/indicator-card.html +14 -8
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/select_territory.html +32 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_geo.html +8 -35
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/histogram.html +1 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/no-data.html +1 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/proportions.html +1 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/top10.html +1 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/map.css +3 -2
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/page.css +8 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/page.html +9 -8
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/methodo/methodo.js +28 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/methodo/page.html +40 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/page.html +4 -3
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/sitemap/page.html +9 -0
- territories_dashboard_lib/website_lib/templatetags/other_filters.py +6 -3
- territories_dashboard_lib/website_lib/views.py +100 -0
- {territories_dashboard_lib-0.1.33b1.dist-info → territories_dashboard_lib-1.1.1.dev7.dist-info}/METADATA +3 -3
- {territories_dashboard_lib-0.1.33b1.dist-info → territories_dashboard_lib-1.1.1.dev7.dist-info}/RECORD +74 -62
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_methodo.css +0 -29
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_methodo.html +0 -45
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_methodo.js +0 -19
- {territories_dashboard_lib-0.1.33b1.dist-info → territories_dashboard_lib-1.1.1.dev7.dist-info}/WHEEL +0 -0
- {territories_dashboard_lib-0.1.33b1.dist-info → territories_dashboard_lib-1.1.1.dev7.dist-info}/licenses/licence.md +0 -0
- {territories_dashboard_lib-0.1.33b1.dist-info → territories_dashboard_lib-1.1.1.dev7.dist-info}/top_level.txt +0 -0
|
@@ -9,7 +9,7 @@ from territories_dashboard_lib.commons.decorators import use_payload
|
|
|
9
9
|
from territories_dashboard_lib.tracking_lib.enums import EventType, GraphType
|
|
10
10
|
from territories_dashboard_lib.tracking_lib.logic import track_event
|
|
11
11
|
|
|
12
|
-
from .enums import
|
|
12
|
+
from .enums import MESHES_SHORT_TITLES
|
|
13
13
|
from .export import export_to_csv
|
|
14
14
|
from .format import format_data, format_indicator_value
|
|
15
15
|
from .models import Indicator
|
|
@@ -19,9 +19,11 @@ from .payloads import (
|
|
|
19
19
|
FlowsPayload,
|
|
20
20
|
IndicatorTablePayload,
|
|
21
21
|
OptionalComparisonQueryPayload,
|
|
22
|
+
SubMeshOnlyPayload,
|
|
22
23
|
SubMeshPayload,
|
|
23
24
|
)
|
|
24
25
|
from .query.commons import (
|
|
26
|
+
get_mesh_column_name,
|
|
25
27
|
get_sub_territories,
|
|
26
28
|
get_territory_name,
|
|
27
29
|
get_values_for_territory,
|
|
@@ -62,6 +64,11 @@ def download_indicator_methodo_view(request, name):
|
|
|
62
64
|
@cache_control(max_age=3600)
|
|
63
65
|
@use_payload(SubMeshPayload)
|
|
64
66
|
def indicator_statistics_view(request, name, payload):
|
|
67
|
+
if payload.submesh == payload.territory.mesh:
|
|
68
|
+
return HttpResponse(
|
|
69
|
+
"les statiques ne sont pas disponibles si la maille est du même niveau que le territoire.",
|
|
70
|
+
status=400,
|
|
71
|
+
)
|
|
65
72
|
indicator = get_object_or_404(Indicator, name=name)
|
|
66
73
|
filters = get_filters(request, indicator)
|
|
67
74
|
query = get_geography_statistics_values_for_indicator(
|
|
@@ -193,7 +200,7 @@ def indicator_proportions_export_view(request, name, payload):
|
|
|
193
200
|
|
|
194
201
|
|
|
195
202
|
@cache_control(max_age=3600)
|
|
196
|
-
@use_payload(
|
|
203
|
+
@use_payload(SubMeshOnlyPayload)
|
|
197
204
|
def indicator_histogram_view(request, name, payload):
|
|
198
205
|
indicator = get_object_or_404(Indicator, name=name)
|
|
199
206
|
filters = get_filters(request, indicator)
|
|
@@ -207,7 +214,7 @@ def indicator_histogram_view(request, name, payload):
|
|
|
207
214
|
|
|
208
215
|
|
|
209
216
|
@cache_control(max_age=3600)
|
|
210
|
-
@use_payload(
|
|
217
|
+
@use_payload(SubMeshOnlyPayload)
|
|
211
218
|
def indicator_histogram_export_view(request, name, payload):
|
|
212
219
|
indicator = get_object_or_404(Indicator, name=name)
|
|
213
220
|
filters = get_filters(request, indicator)
|
|
@@ -237,7 +244,7 @@ def indicator_histogram_export_view(request, name, payload):
|
|
|
237
244
|
|
|
238
245
|
|
|
239
246
|
@cache_control(max_age=3600)
|
|
240
|
-
@use_payload(
|
|
247
|
+
@use_payload(SubMeshOnlyPayload)
|
|
241
248
|
def indicator_top_10_view(request, name, payload):
|
|
242
249
|
indicator = get_object_or_404(Indicator, name=name)
|
|
243
250
|
filters = get_filters(request, indicator)
|
|
@@ -251,7 +258,7 @@ def indicator_top_10_view(request, name, payload):
|
|
|
251
258
|
|
|
252
259
|
|
|
253
260
|
@require_GET
|
|
254
|
-
@use_payload(
|
|
261
|
+
@use_payload(SubMeshOnlyPayload)
|
|
255
262
|
def indicator_top_10_export_view(request, name, payload):
|
|
256
263
|
indicator = get_object_or_404(Indicator, name=name)
|
|
257
264
|
filters = get_filters(request, indicator)
|
|
@@ -274,28 +281,10 @@ def flows_view(request, payload):
|
|
|
274
281
|
last_year_query = f"SELECT DISTINCT annee FROM {flows_table} ORDER BY annee DESC"
|
|
275
282
|
last_year = run_custom_query(last_year_query)[0]["annee"]
|
|
276
283
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
)
|
|
280
|
-
mapped_mesh_level = (
|
|
281
|
-
"DEPCOM" if payload.submesh == "com" else payload.submesh.upper()
|
|
284
|
+
territories = get_sub_territories(
|
|
285
|
+
submesh=payload.submesh, territory=payload.territory, with_center=True
|
|
282
286
|
)
|
|
283
|
-
|
|
284
|
-
codes = ", ".join(f"'{code.strip()}'" for code in payload.territory.id.split(","))
|
|
285
|
-
|
|
286
|
-
# Geo query
|
|
287
|
-
geo_query = f"""
|
|
288
|
-
SELECT DISTINCT
|
|
289
|
-
arbo."{mapped_mesh_level}" as territory_id,
|
|
290
|
-
arbo."NOM_{mapped_mesh_level}" as territory_name,
|
|
291
|
-
ST_ASGEOJSON(ST_CENTROID(contours.geometry)) as center
|
|
292
|
-
FROM arborescence_geo AS arbo
|
|
293
|
-
JOIN contours_simplified_{payload.submesh} as contours
|
|
294
|
-
ON arbo."{mapped_mesh_level}" = contours.code
|
|
295
|
-
WHERE arbo."{mapped_geo_level}" IN ({codes})
|
|
296
|
-
"""
|
|
297
|
-
territories = run_custom_query(geo_query)
|
|
298
|
-
territories_ids = ", ".join(f"'{t['territory_id'].strip()}'" for t in territories)
|
|
287
|
+
territories_ids = ", ".join(f"'{t['code'].strip()}'" for t in territories)
|
|
299
288
|
|
|
300
289
|
dimension_value = (
|
|
301
290
|
f"{payload.dimension} as dimension"
|
|
@@ -303,25 +292,28 @@ def flows_view(request, payload):
|
|
|
303
292
|
else "'all' as dimension"
|
|
304
293
|
)
|
|
305
294
|
|
|
295
|
+
mesh_col = get_mesh_column_name(payload.submesh)
|
|
306
296
|
# Values query
|
|
307
297
|
values_query = f"""
|
|
308
298
|
SELECT
|
|
309
|
-
|
|
310
|
-
|
|
299
|
+
{mesh_col}_1 as territory_1_id,
|
|
300
|
+
{mesh_col}_2 as territory_2_id,
|
|
311
301
|
CAST(valeur AS int) as value,
|
|
312
302
|
{dimension_value}
|
|
313
303
|
FROM {flows_table} flows
|
|
314
304
|
WHERE annee = {last_year}
|
|
315
305
|
AND (
|
|
316
|
-
|
|
317
|
-
OR
|
|
306
|
+
{mesh_col}_1 IN ({territories_ids})
|
|
307
|
+
OR {mesh_col}_2 IN ({territories_ids})
|
|
318
308
|
)
|
|
309
|
+
AND {mesh_col}_1 IS NOT NULL
|
|
310
|
+
AND {mesh_col}_2 IS NOT NULL
|
|
319
311
|
"""
|
|
320
312
|
row_values = run_custom_query(values_query)
|
|
321
313
|
territories_dict = {
|
|
322
|
-
t["
|
|
323
|
-
"name": t["
|
|
324
|
-
"code": t["
|
|
314
|
+
t["code"]: {
|
|
315
|
+
"name": t["name"],
|
|
316
|
+
"code": t["code"],
|
|
325
317
|
"center": json.loads(t["center"]),
|
|
326
318
|
}
|
|
327
319
|
for t in territories
|
|
@@ -333,26 +325,16 @@ def flows_view(request, payload):
|
|
|
333
325
|
external_territories_ids.add(row["territory_1_id"])
|
|
334
326
|
if row["territory_2_id"] not in territories_dict:
|
|
335
327
|
external_territories_ids.add(row["territory_2_id"])
|
|
336
|
-
external_territories_ids
|
|
337
328
|
|
|
338
329
|
external_territories = []
|
|
339
330
|
if external_territories_ids:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
arbo."{mapped_mesh_level}" as territory_id,
|
|
344
|
-
arbo."NOM_{mapped_mesh_level}" as territory_name,
|
|
345
|
-
ST_ASGEOJSON(ST_CENTROID(contours.geometry)) as center
|
|
346
|
-
FROM arborescence_geo AS arbo
|
|
347
|
-
JOIN contours_simplified_{payload.submesh} as contours
|
|
348
|
-
ON arbo."{mapped_mesh_level}" = contours.code
|
|
349
|
-
WHERE arbo."{mapped_mesh_level}" IN ({codes})
|
|
350
|
-
"""
|
|
351
|
-
external_territories = run_custom_query(geo_query)
|
|
331
|
+
external_territories = get_sub_territories(
|
|
332
|
+
submesh=payload.submesh, codes=external_territories_ids, with_center=True
|
|
333
|
+
)
|
|
352
334
|
for t in external_territories:
|
|
353
|
-
territories_dict[t["
|
|
354
|
-
"name": f"{t['
|
|
355
|
-
"code": t["
|
|
335
|
+
territories_dict[t["code"]] = {
|
|
336
|
+
"name": f"{t['name']} (externe)",
|
|
337
|
+
"code": t["code"],
|
|
356
338
|
"center": json.loads(t["center"]),
|
|
357
339
|
}
|
|
358
340
|
|
|
@@ -367,8 +349,12 @@ def flows_view(request, payload):
|
|
|
367
349
|
def comparison_histogram_view(request, name, payload):
|
|
368
350
|
indicator = get_object_or_404(Indicator, name=name)
|
|
369
351
|
filters = get_filters(request, indicator)
|
|
370
|
-
territories = get_sub_territories(
|
|
371
|
-
|
|
352
|
+
territories = get_sub_territories(
|
|
353
|
+
submesh=payload.submesh, territory=payload.territory
|
|
354
|
+
)
|
|
355
|
+
cmp_territories = get_sub_territories(
|
|
356
|
+
submesh=payload.submesh, territory=payload.cmp_territory
|
|
357
|
+
)
|
|
372
358
|
values, cmp_values, buckets = get_comparison_values_and_buckets(
|
|
373
359
|
indicator, payload.submesh, territories, cmp_territories, filters
|
|
374
360
|
)
|
|
@@ -386,8 +372,12 @@ def comparison_histogram_view(request, name, payload):
|
|
|
386
372
|
def comparison_histogram_export_view(request, name, payload):
|
|
387
373
|
indicator = get_object_or_404(Indicator, name=name)
|
|
388
374
|
filters = get_filters(request, indicator)
|
|
389
|
-
territories = get_sub_territories(
|
|
390
|
-
|
|
375
|
+
territories = get_sub_territories(
|
|
376
|
+
submesh=payload.submesh, territory=payload.territory
|
|
377
|
+
)
|
|
378
|
+
cmp_territories = get_sub_territories(
|
|
379
|
+
submesh=payload.submesh, territory=payload.cmp_territory
|
|
380
|
+
)
|
|
391
381
|
values, cmp_values, buckets = get_comparison_values_and_buckets(
|
|
392
382
|
indicator, payload.submesh, territories, cmp_territories, filters
|
|
393
383
|
)
|
|
@@ -399,12 +389,12 @@ def comparison_histogram_export_view(request, name, payload):
|
|
|
399
389
|
row["Décile"] = (
|
|
400
390
|
f"{format_indicator_value(bucket[0])} - {format_indicator_value(bucket[1])}"
|
|
401
391
|
)
|
|
402
|
-
row[f"{territory_name} - Nombre de {
|
|
403
|
-
values[index + 1]
|
|
404
|
-
)
|
|
405
|
-
row[f"{cmp_territory_name} - Nombre de {MESH_TITLES[payload.submesh]}s"] = len(
|
|
406
|
-
cmp_values[index + 1]
|
|
392
|
+
row[f"{territory_name} - Nombre de {MESHES_SHORT_TITLES[payload.submesh]}s"] = (
|
|
393
|
+
len(values[index + 1])
|
|
407
394
|
)
|
|
395
|
+
row[
|
|
396
|
+
f"{cmp_territory_name} - Nombre de {MESHES_SHORT_TITLES[payload.submesh]}s"
|
|
397
|
+
] = len(cmp_values[index + 1])
|
|
408
398
|
row[f"{territory_name} - échantillon de dix territoires"] = " | ".join(
|
|
409
399
|
values[index + 1][:10]
|
|
410
400
|
)
|
|
@@ -418,7 +408,7 @@ def comparison_histogram_export_view(request, name, payload):
|
|
|
418
408
|
def get_label(props, indicator, key):
|
|
419
409
|
labels = {
|
|
420
410
|
"annee": "Année",
|
|
421
|
-
"
|
|
411
|
+
"name": "Lieu",
|
|
422
412
|
"territory_1": "Origine",
|
|
423
413
|
"territory_2": "Destination",
|
|
424
414
|
"valeur": "flux" if props.flows else indicator.unite,
|
|
@@ -9,46 +9,45 @@ def get_territory_meshes(territory_id: str, territory_mesh: MeshLevel):
|
|
|
9
9
|
current_dep = None
|
|
10
10
|
current_epci = None
|
|
11
11
|
current_com = None
|
|
12
|
-
if territory_mesh != MeshLevel.
|
|
13
|
-
mapped_mesh = "DEPCOM" if territory_mesh == "com" else territory_mesh.upper()
|
|
12
|
+
if territory_mesh != MeshLevel.fr:
|
|
14
13
|
query = f"""
|
|
15
14
|
SELECT
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
name_reg,
|
|
16
|
+
name_dep,
|
|
17
|
+
name_epci,
|
|
18
|
+
name_com
|
|
20
19
|
FROM arborescence_geo
|
|
21
|
-
WHERE
|
|
20
|
+
WHERE code_{territory_mesh} = '{territory_id}'
|
|
22
21
|
LIMIT 1
|
|
23
22
|
"""
|
|
24
23
|
row = run_custom_query(query)[0]
|
|
25
24
|
if territory_mesh in [
|
|
26
|
-
MeshLevel.
|
|
27
|
-
MeshLevel.
|
|
28
|
-
MeshLevel.
|
|
29
|
-
MeshLevel.
|
|
25
|
+
MeshLevel.reg,
|
|
26
|
+
MeshLevel.dep,
|
|
27
|
+
MeshLevel.epci,
|
|
28
|
+
MeshLevel.com,
|
|
30
29
|
]:
|
|
31
|
-
current_reg = row["
|
|
30
|
+
current_reg = row["name_reg"]
|
|
32
31
|
if territory_mesh in [
|
|
33
|
-
MeshLevel.
|
|
34
|
-
MeshLevel.
|
|
35
|
-
MeshLevel.
|
|
32
|
+
MeshLevel.dep,
|
|
33
|
+
MeshLevel.epci,
|
|
34
|
+
MeshLevel.com,
|
|
36
35
|
]:
|
|
37
|
-
current_dep = row["
|
|
36
|
+
current_dep = row["name_dep"]
|
|
38
37
|
if territory_mesh in [
|
|
39
|
-
MeshLevel.
|
|
40
|
-
MeshLevel.
|
|
38
|
+
MeshLevel.epci,
|
|
39
|
+
MeshLevel.com,
|
|
41
40
|
]:
|
|
42
|
-
current_epci = row["
|
|
41
|
+
current_epci = row["name_epci"]
|
|
43
42
|
if territory_mesh in [
|
|
44
|
-
MeshLevel.
|
|
43
|
+
MeshLevel.com,
|
|
45
44
|
]:
|
|
46
|
-
current_com = row["
|
|
45
|
+
current_com = row["name_com"]
|
|
47
46
|
territory_meshes = {
|
|
48
|
-
MeshLevel.
|
|
49
|
-
MeshLevel.
|
|
50
|
-
MeshLevel.
|
|
51
|
-
MeshLevel.
|
|
47
|
+
MeshLevel.reg: current_reg,
|
|
48
|
+
MeshLevel.dep: current_dep,
|
|
49
|
+
MeshLevel.epci: current_epci,
|
|
50
|
+
MeshLevel.com: current_com,
|
|
52
51
|
}
|
|
53
52
|
return territory_meshes
|
|
54
53
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 5.2.8 on 2025-12-03 13:30
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('superset_lib', '0001_initial'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='filter',
|
|
15
|
+
name='mesh',
|
|
16
|
+
field=models.TextField(blank=True, choices=[('fr', 'Fr'), ('reg', 'Reg'), ('dep', 'Dep'), ('epci', 'Epci'), ('com', 'Com'), ('aom', 'Aom')], help_text="Maille du territoire sur lequel s'effectue le filtre.", null=True),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Generated by Django 5.2.8 on 2025-12-03 13:30
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('tracking_lib', '0004_cookieinfo_ip_address'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='page',
|
|
15
|
+
name='cmp_territory_mesh',
|
|
16
|
+
field=models.TextField(blank=True, choices=[('fr', 'Fr'), ('reg', 'Reg'), ('dep', 'Dep'), ('epci', 'Epci'), ('com', 'Com'), ('aom', 'Aom')], help_text="Maille du territoire de comparaison, null s'il ne s'agit pas de la page comparaison.", null=True),
|
|
17
|
+
),
|
|
18
|
+
migrations.AlterField(
|
|
19
|
+
model_name='page',
|
|
20
|
+
name='submesh',
|
|
21
|
+
field=models.TextField(blank=True, choices=[('fr', 'Fr'), ('reg', 'Reg'), ('dep', 'Dep'), ('epci', 'Epci'), ('com', 'Com'), ('aom', 'Aom')], help_text="Maille d'analyse sélectionnée.", null=True),
|
|
22
|
+
),
|
|
23
|
+
migrations.AlterField(
|
|
24
|
+
model_name='page',
|
|
25
|
+
name='territory_mesh',
|
|
26
|
+
field=models.TextField(blank=True, choices=[('fr', 'Fr'), ('reg', 'Reg'), ('dep', 'Dep'), ('epci', 'Epci'), ('com', 'Com'), ('aom', 'Aom')], help_text='Maille du territoire principal sélectionné.', null=True),
|
|
27
|
+
),
|
|
28
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 5.2.9 on 2026-01-06 16:48
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('tracking_lib', '0005_alter_page_cmp_territory_mesh_alter_page_submesh_and_more'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterField(
|
|
14
|
+
model_name='event',
|
|
15
|
+
name='name',
|
|
16
|
+
field=models.TextField(choices=[('download', 'Download'), ('vue-resume-indicateur', 'View Indicator Card')]),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
1
3
|
from pydantic import BaseModel
|
|
2
4
|
|
|
3
5
|
from territories_dashboard_lib.tracking_lib.enums import EventType
|
|
@@ -6,5 +8,5 @@ from territories_dashboard_lib.tracking_lib.enums import EventType
|
|
|
6
8
|
class EventPayload(BaseModel):
|
|
7
9
|
indicator: str
|
|
8
10
|
event: EventType
|
|
9
|
-
objet: str
|
|
10
|
-
type: str
|
|
11
|
+
objet: Optional[str] = None
|
|
12
|
+
type: Optional[str] = None
|
|
@@ -26,18 +26,19 @@ def track_event_view(request):
|
|
|
26
26
|
return JsonResponse({"error": e.errors()}, status=422)
|
|
27
27
|
if (
|
|
28
28
|
Event.objects.filter(created_at__gte=timezone.now() - timedelta(days=1)).count()
|
|
29
|
-
>
|
|
29
|
+
> 100_000
|
|
30
30
|
):
|
|
31
31
|
return HttpResponse(status=429)
|
|
32
32
|
response = HttpResponse()
|
|
33
|
+
data = {"indicator": payload.indicator}
|
|
34
|
+
if payload.objet:
|
|
35
|
+
data["objet"] = payload.objet
|
|
36
|
+
if payload.type:
|
|
37
|
+
data["type"] = payload.type
|
|
33
38
|
track_event(
|
|
34
39
|
request=request,
|
|
35
40
|
response=response,
|
|
36
41
|
event_name=payload.event,
|
|
37
|
-
data=
|
|
38
|
-
"indicator": payload.indicator,
|
|
39
|
-
"objet": payload.objet,
|
|
40
|
-
"type": payload.type,
|
|
41
|
-
},
|
|
42
|
+
data=data,
|
|
42
43
|
)
|
|
43
44
|
return HttpResponse()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from territories_dashboard_lib.indicators_lib.enums import (
|
|
2
|
+
ALL_MESHES_ABSOLUTE,
|
|
3
|
+
MESHES_ORDERED_FOR_PRESENTATION,
|
|
4
|
+
)
|
|
5
|
+
from territories_dashboard_lib.website_lib.models import MainConf
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MissingMainConf(Exception):
|
|
9
|
+
def __init__(self):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.message = "Configuration principale du site (MainConf) manquante, veuillez la créer via le backoffice ou le shell."
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_meshes_for_current_project():
|
|
15
|
+
main_conf = get_main_conf()
|
|
16
|
+
return [m for m in ALL_MESHES_ABSOLUTE if m in main_conf.meshes]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_ordered_meshes_for_current_project():
|
|
20
|
+
main_conf = get_main_conf()
|
|
21
|
+
return [m for m in MESHES_ORDERED_FOR_PRESENTATION if m in main_conf.meshes]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_main_conf():
|
|
25
|
+
main_conf = MainConf.objects.first()
|
|
26
|
+
if main_conf is None:
|
|
27
|
+
raise MissingMainConf
|
|
28
|
+
return main_conf
|
|
@@ -2,20 +2,19 @@ from django.conf import settings
|
|
|
2
2
|
|
|
3
3
|
from territories_dashboard_lib.superset_lib.models import Dashboard
|
|
4
4
|
from territories_dashboard_lib.superset_lib.serializers import serialize_dashboard
|
|
5
|
-
from territories_dashboard_lib.website_lib.
|
|
6
|
-
|
|
7
|
-
NoticeBanner,
|
|
8
|
-
)
|
|
5
|
+
from territories_dashboard_lib.website_lib.conf import get_main_conf
|
|
6
|
+
from territories_dashboard_lib.website_lib.models import NoticeBanner
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
def default(request):
|
|
12
|
-
main_conf =
|
|
10
|
+
main_conf = get_main_conf()
|
|
13
11
|
notice = NoticeBanner.objects.first()
|
|
12
|
+
view_name = request.resolver_match.view_name if request.resolver_match else None
|
|
14
13
|
context = {
|
|
15
14
|
"ENABLE_SUPERSET": settings.ENABLE_SUPERSET,
|
|
16
15
|
"ANALYTICS_ID": settings.ANALYTICS_ID,
|
|
17
16
|
"ENVIRONMENT": settings.ENVIRONMENT,
|
|
18
|
-
"view_name":
|
|
17
|
+
"view_name": view_name,
|
|
19
18
|
"absolute_uri": request.build_absolute_uri(),
|
|
20
19
|
"main_conf": main_conf,
|
|
21
20
|
"notice": notice,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Generated by Django 5.2.8 on 2025-12-03 13:42
|
|
2
|
+
|
|
3
|
+
import django.contrib.postgres.fields
|
|
4
|
+
import territories_dashboard_lib.website_lib.models
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
('website_lib', '0004_mainconf_description_mainconf_social_image_url'),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
operations = [
|
|
15
|
+
migrations.AddField(
|
|
16
|
+
model_name='mainconf',
|
|
17
|
+
name='meshes',
|
|
18
|
+
field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(choices=[('fr', 'Fr'), ('reg', 'Reg'), ('dep', 'Dep'), ('epci', 'Epci'), ('com', 'Com'), ('aom', 'Aom')]), default=territories_dashboard_lib.website_lib.models.get_default_meshes, help_text="Liste des mailles territoriales activées sur la plateforme, la liste des mailles disponible est : ['fr', 'reg', 'dep', 'epci', 'com', 'aom'].<br/>L'ajout de nouvelles mailles demande une modification de la base de données des indicateurs ainsi que du code.", size=None, verbose_name='Mailles'),
|
|
19
|
+
),
|
|
20
|
+
]
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
from django.contrib.postgres.fields import ArrayField
|
|
1
2
|
from django.db import models
|
|
2
3
|
from martor.models import MartorField
|
|
3
4
|
|
|
4
5
|
from territories_dashboard_lib.commons.models import CommonModel
|
|
6
|
+
from territories_dashboard_lib.indicators_lib.enums import STANDARD_MESHES, MeshLevel
|
|
5
7
|
from territories_dashboard_lib.website_lib.navigation import (
|
|
6
8
|
parse_footer_navigation,
|
|
7
9
|
parse_header_navigation,
|
|
@@ -12,6 +14,10 @@ from territories_dashboard_lib.website_lib.static_content import (
|
|
|
12
14
|
)
|
|
13
15
|
|
|
14
16
|
|
|
17
|
+
def get_default_meshes():
|
|
18
|
+
return STANDARD_MESHES
|
|
19
|
+
|
|
20
|
+
|
|
15
21
|
class MainConf(CommonModel):
|
|
16
22
|
title = models.TextField(
|
|
17
23
|
verbose_name="Titre principal du site", default="Tableau de bord"
|
|
@@ -74,6 +80,12 @@ class MainConf(CommonModel):
|
|
|
74
80
|
verbose_name="Image de description",
|
|
75
81
|
help_text="Lien d'une image (idéalement 1200x630px). Elle sera utilisée lors du partage sur les réseaux sociaux.",
|
|
76
82
|
)
|
|
83
|
+
meshes = ArrayField(
|
|
84
|
+
models.TextField(choices=MeshLevel),
|
|
85
|
+
default=get_default_meshes,
|
|
86
|
+
verbose_name="Mailles",
|
|
87
|
+
help_text=f"Liste des mailles territoriales activées sur la plateforme, la liste des mailles disponible est : {[m.value for m in MeshLevel]}.<br/>L'ajout de nouvelles mailles demande une modification de la base de données des indicateurs ainsi que du code.",
|
|
88
|
+
)
|
|
77
89
|
|
|
78
90
|
@property
|
|
79
91
|
def entity_breaklines(self):
|
|
@@ -2,23 +2,29 @@ from functools import wraps
|
|
|
2
2
|
|
|
3
3
|
from territories_dashboard_lib.indicators_lib.enums import (
|
|
4
4
|
FRANCE_GEOLEVEL_TITLES,
|
|
5
|
-
|
|
5
|
+
MESHES_LONG_TITLES,
|
|
6
|
+
MESHES_SHORT_TITLES,
|
|
7
|
+
STANDARD_MESHES,
|
|
6
8
|
FranceGeoLevel,
|
|
7
9
|
MeshLevel,
|
|
8
|
-
get_all_meshes,
|
|
9
10
|
get_allow_same_mesh,
|
|
11
|
+
order_meshes_for_presentation,
|
|
10
12
|
)
|
|
11
13
|
from territories_dashboard_lib.indicators_lib.query.utils import run_custom_query
|
|
14
|
+
from territories_dashboard_lib.website_lib.conf import (
|
|
15
|
+
get_meshes_for_current_project,
|
|
16
|
+
get_ordered_meshes_for_current_project,
|
|
17
|
+
)
|
|
12
18
|
|
|
13
19
|
TERRITORY_DEFAULT = {
|
|
14
20
|
"id": FranceGeoLevel.METRO,
|
|
15
|
-
"mesh": MeshLevel.
|
|
21
|
+
"mesh": MeshLevel.fr,
|
|
16
22
|
"name": FRANCE_GEOLEVEL_TITLES[FranceGeoLevel.METRO],
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
CMP_TERRITORY_DEFAULT = {
|
|
20
26
|
"id": FranceGeoLevel.All,
|
|
21
|
-
"mesh": MeshLevel.
|
|
27
|
+
"mesh": MeshLevel.fr,
|
|
22
28
|
"name": FRANCE_GEOLEVEL_TITLES[FranceGeoLevel.All],
|
|
23
29
|
}
|
|
24
30
|
|
|
@@ -32,9 +38,6 @@ class BadParam(Exception):
|
|
|
32
38
|
pass
|
|
33
39
|
|
|
34
40
|
|
|
35
|
-
# TODO coverage
|
|
36
|
-
# appeler la page détail d'un indicateur (page html, pas api) avec plus de combinaisons de paramètres GET
|
|
37
|
-
# tester les valeurs du context du template
|
|
38
41
|
class ParamsHandler:
|
|
39
42
|
def __init__(self, request):
|
|
40
43
|
self.request = request
|
|
@@ -47,6 +50,7 @@ class ParamsHandler:
|
|
|
47
50
|
self.mesh = None
|
|
48
51
|
self.meshes = []
|
|
49
52
|
self.comparison = request.resolver_match.view_name == "website:comparison"
|
|
53
|
+
self.all_meshes = get_meshes_for_current_project()
|
|
50
54
|
|
|
51
55
|
######################## Territory
|
|
52
56
|
|
|
@@ -66,12 +70,12 @@ class ParamsHandler:
|
|
|
66
70
|
return parts[0], parts[1]
|
|
67
71
|
|
|
68
72
|
def get_territory_name(self, territory_id, territory_mesh):
|
|
69
|
-
|
|
73
|
+
# TODO use common -> get_territory_name, need Territory
|
|
74
|
+
if territory_mesh == MeshLevel.fr:
|
|
70
75
|
return FRANCE_GEOLEVEL_TITLES[territory_id]
|
|
71
|
-
mesh = "DEPCOM" if territory_mesh == "com" else territory_mesh.upper()
|
|
72
76
|
query = f"""
|
|
73
|
-
SELECT DISTINCT
|
|
74
|
-
WHERE
|
|
77
|
+
SELECT DISTINCT name FROM arbo_{territory_mesh}
|
|
78
|
+
WHERE code = '{territory_id}'
|
|
75
79
|
"""
|
|
76
80
|
try:
|
|
77
81
|
results = run_custom_query(query)
|
|
@@ -144,29 +148,34 @@ class ParamsHandler:
|
|
|
144
148
|
######################## Mesh
|
|
145
149
|
|
|
146
150
|
def get_max_territory_mesh(self):
|
|
147
|
-
meshes = get_all_meshes()
|
|
148
151
|
if self.comparison is False:
|
|
149
152
|
return self.territory_mesh
|
|
150
|
-
if
|
|
153
|
+
if self.all_meshes.index(self.cmp_territory_mesh) > self.all_meshes.index(
|
|
154
|
+
self.territory_mesh
|
|
155
|
+
):
|
|
151
156
|
return self.cmp_territory_mesh
|
|
152
157
|
return self.territory_mesh
|
|
153
158
|
|
|
154
159
|
def is_not_valid_mesh(self, mesh):
|
|
155
160
|
if mesh is None:
|
|
156
161
|
return True
|
|
157
|
-
meshes = get_all_meshes()
|
|
158
162
|
max_territory_mesh = self.get_max_territory_mesh()
|
|
159
163
|
allow_same_mesh = get_allow_same_mesh()
|
|
160
164
|
is_not_valid = (
|
|
161
|
-
|
|
165
|
+
self.all_meshes.index(max_territory_mesh) > self.all_meshes.index(mesh)
|
|
162
166
|
if allow_same_mesh
|
|
163
|
-
else
|
|
167
|
+
else self.all_meshes.index(max_territory_mesh)
|
|
168
|
+
>= self.all_meshes.index(mesh)
|
|
164
169
|
)
|
|
165
170
|
return is_not_valid
|
|
166
171
|
|
|
167
172
|
def get_default_mesh(self):
|
|
168
173
|
max_territory_mesh = self.get_max_territory_mesh()
|
|
169
|
-
meshes =
|
|
174
|
+
meshes = (
|
|
175
|
+
STANDARD_MESHES
|
|
176
|
+
if max_territory_mesh in STANDARD_MESHES
|
|
177
|
+
else self.all_meshes
|
|
178
|
+
)
|
|
170
179
|
if meshes.index(max_territory_mesh) == len(meshes) - 1:
|
|
171
180
|
default_mesh = meshes[-1]
|
|
172
181
|
else:
|
|
@@ -201,13 +210,15 @@ class ParamsHandler:
|
|
|
201
210
|
max_territory_mesh = self.get_max_territory_mesh()
|
|
202
211
|
meshes = [
|
|
203
212
|
m
|
|
204
|
-
for m in
|
|
205
|
-
if not (m == MeshLevel.
|
|
213
|
+
for m in self.all_meshes
|
|
214
|
+
if not (m == MeshLevel.com and max_territory_mesh == MeshLevel.fr)
|
|
206
215
|
]
|
|
207
216
|
min_mesh_index = meshes.index(max_territory_mesh)
|
|
208
217
|
if get_allow_same_mesh() is False:
|
|
209
218
|
min_mesh_index += 1
|
|
210
|
-
self.meshes =
|
|
219
|
+
self.meshes = order_meshes_for_presentation(
|
|
220
|
+
meshes[min(min_mesh_index, len(meshes) - 1) :]
|
|
221
|
+
)
|
|
211
222
|
|
|
212
223
|
######################## Commons
|
|
213
224
|
|
|
@@ -258,8 +269,9 @@ class ParamsHandler:
|
|
|
258
269
|
"cmp_territory_name": self.cmp_territory_name,
|
|
259
270
|
"mesh": self.mesh,
|
|
260
271
|
"meshes": self.meshes,
|
|
261
|
-
"
|
|
262
|
-
"
|
|
272
|
+
"meshes_short_titles": MESHES_SHORT_TITLES,
|
|
273
|
+
"meshes_long_titles": MESHES_LONG_TITLES,
|
|
274
|
+
"ordered_meshes": get_ordered_meshes_for_current_project(),
|
|
263
275
|
"url_params": "&".join(url_params),
|
|
264
276
|
}
|
|
265
277
|
|