territories-dashboard-lib 0.1.0__py3-none-any.whl → 0.1.2__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.
Potentially problematic release.
This version of territories-dashboard-lib might be problematic. Click here for more details.
- territories_dashboard_lib/commons/__init__.py +0 -0
- territories_dashboard_lib/commons/decorators.py +36 -0
- territories_dashboard_lib/commons/models.py +9 -0
- territories_dashboard_lib/geo_lib/__init__.py +0 -0
- territories_dashboard_lib/geo_lib/admin.py +64 -0
- territories_dashboard_lib/geo_lib/enums.py +7 -0
- territories_dashboard_lib/geo_lib/migrations/0001_initial.py +51 -0
- territories_dashboard_lib/geo_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib/geo_lib/models.py +58 -0
- territories_dashboard_lib/geo_lib/urls.py +27 -0
- territories_dashboard_lib/geo_lib/views.py +239 -0
- territories_dashboard_lib/indicators_lib/__init__.py +0 -0
- territories_dashboard_lib/indicators_lib/admin.py +140 -0
- territories_dashboard_lib/indicators_lib/enums.py +59 -0
- territories_dashboard_lib/indicators_lib/export.py +29 -0
- territories_dashboard_lib/indicators_lib/format.py +34 -0
- territories_dashboard_lib/indicators_lib/methodo_pdf.py +99 -0
- territories_dashboard_lib/indicators_lib/migrations/0001_initial.py +138 -0
- territories_dashboard_lib/indicators_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib/indicators_lib/models.py +230 -0
- territories_dashboard_lib/indicators_lib/payloads.py +54 -0
- territories_dashboard_lib/indicators_lib/query/commons.py +223 -0
- territories_dashboard_lib/indicators_lib/query/comparison.py +70 -0
- territories_dashboard_lib/indicators_lib/query/details.py +64 -0
- territories_dashboard_lib/indicators_lib/query/histogram.py +82 -0
- territories_dashboard_lib/indicators_lib/query/indicator_card.py +102 -0
- territories_dashboard_lib/indicators_lib/query/top_10.py +100 -0
- territories_dashboard_lib/indicators_lib/query/utils.py +20 -0
- territories_dashboard_lib/indicators_lib/refresh_filters.py +17 -0
- territories_dashboard_lib/indicators_lib/table.py +154 -0
- territories_dashboard_lib/indicators_lib/urls.py +97 -0
- territories_dashboard_lib/indicators_lib/views.py +490 -0
- territories_dashboard_lib/superset_lib/__init__.py +0 -0
- territories_dashboard_lib/superset_lib/admin.py +22 -0
- territories_dashboard_lib/superset_lib/guest_token.py +64 -0
- territories_dashboard_lib/superset_lib/logic.py +67 -0
- territories_dashboard_lib/superset_lib/migrations/0001_initial.py +45 -0
- territories_dashboard_lib/superset_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib/superset_lib/models.py +52 -0
- territories_dashboard_lib/superset_lib/serializers.py +10 -0
- territories_dashboard_lib/superset_lib/urls.py +10 -0
- territories_dashboard_lib/superset_lib/views.py +19 -0
- territories_dashboard_lib/tracking_lib/__init__.py +0 -0
- territories_dashboard_lib/tracking_lib/enums.py +7 -0
- territories_dashboard_lib/tracking_lib/logic.py +78 -0
- territories_dashboard_lib/tracking_lib/migrations/0001_initial.py +45 -0
- territories_dashboard_lib/tracking_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib/tracking_lib/models.py +79 -0
- territories_dashboard_lib/website_lib/__init__.py +0 -0
- territories_dashboard_lib/website_lib/admin.py +40 -0
- territories_dashboard_lib/website_lib/context_processors.py +27 -0
- territories_dashboard_lib/website_lib/forms.py +47 -0
- territories_dashboard_lib/website_lib/migrations/0001_initial.py +91 -0
- territories_dashboard_lib/website_lib/migrations/__init__.py +0 -0
- territories_dashboard_lib/website_lib/models.py +148 -0
- territories_dashboard_lib/website_lib/navigation.py +124 -0
- territories_dashboard_lib/website_lib/params.py +268 -0
- territories_dashboard_lib/website_lib/serializers.py +105 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/css/website.css +956 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/chart.js +13 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/chartjs-plugin-datalabels.js +1 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/html2canvas.js +20 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/data.mjs +62 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/history.mjs +98 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/main-values.mjs +30 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/page.mjs +105 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/comparaison/territory-chart.mjs +141 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/data.mjs +59 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/histogram.mjs +130 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/map.mjs +25 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/page.mjs +96 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/proportions.mjs +77 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/sankey.mjs +27 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/table.mjs +229 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/top10.mjs +76 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/details/utils.mjs +8 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/dom.mjs +92 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/enums.mjs +104 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/export-graph.mjs +15 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/export.mjs +20 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/filters.mjs +159 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/format.mjs +54 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/side_panel.mjs +103 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/history.mjs +89 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/main-value.mjs +22 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/page.mjs +162 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/theme/statistics.mjs +42 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/indicators/utils.mjs +93 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/pages/static/page.mjs +35 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/patternomaly.js +1452 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/react18.js +31 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/reactdom18.js +267 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/js/supersetEmbed.js +355 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/indicatorMap.bundle.js +2 -0
- territories_dashboard_lib/website_lib/static/territories_dashboard_lib/website/react/sankeyGraph.bundle.js +2 -0
- 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/website_lib/static_content.py +20 -0
- territories_dashboard_lib/website_lib/templates/admin/indicators_lib/indicator/change_form.html +8 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/404.html +10 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/500.html +10 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/base.html +42 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/base.js +47 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/footer.html +96 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/header.html +101 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/layout/header.js +102 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/comparaison/[theme]/components/indicateur-card.html +48 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/comparaison/[theme]/page.html +52 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/chart-buttons.html +29 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/geo_params.html +71 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/indicator-card.html +52 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/loader.html +28 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel.html +27 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_geo.html +80 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_geo.js +85 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_methodo.html +45 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/side_panel_methodo.js +19 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/themes-list.html +9 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/themes-nav.html +33 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/components/title.html +28 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/filters-reminder.html +19 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/components/table.html +123 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/details/page.html +166 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/components/extremum.html +15 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/components/indicateur-card.html +76 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/indicators/themes/page.html +66 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/lexique/page.html +17 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/page.html +14 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/sitemap/page.html +71 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/static/page.html +16 -0
- territories_dashboard_lib/website_lib/templates/territories_dashboard_lib/website/pages/superset/page.html +55 -0
- territories_dashboard_lib/website_lib/templatetags/htmlparams.py +75 -0
- territories_dashboard_lib/website_lib/templatetags/other_filters.py +30 -0
- territories_dashboard_lib/website_lib/views.py +212 -0
- {territories_dashboard_lib-0.1.0.dist-info → territories_dashboard_lib-0.1.2.dist-info}/METADATA +1 -1
- territories_dashboard_lib-0.1.2.dist-info/RECORD +138 -0
- territories_dashboard_lib-0.1.0.dist-info/RECORD +0 -5
- {territories_dashboard_lib-0.1.0.dist-info → territories_dashboard_lib-0.1.2.dist-info}/WHEEL +0 -0
- {territories_dashboard_lib-0.1.0.dist-info → territories_dashboard_lib-0.1.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from django.http import Http404, HttpResponse, JsonResponse
|
|
4
|
+
from django.shortcuts import get_object_or_404, render
|
|
5
|
+
from django.views.decorators.cache import cache_control
|
|
6
|
+
from django.views.decorators.http import require_GET
|
|
7
|
+
|
|
8
|
+
from territories_dashboard_lib.commons.decorators import use_payload
|
|
9
|
+
from territories_dashboard_lib.tracking_lib.enums import EventType
|
|
10
|
+
from territories_dashboard_lib.tracking_lib.logic import track_event
|
|
11
|
+
|
|
12
|
+
from .enums import MESH_TITLES
|
|
13
|
+
from .export import export_to_csv
|
|
14
|
+
from .format import format_data, format_indicator_value
|
|
15
|
+
from .models import Indicator
|
|
16
|
+
from .payloads import (
|
|
17
|
+
BasePayload,
|
|
18
|
+
ComparisonQueryPayload,
|
|
19
|
+
FlowsPayload,
|
|
20
|
+
IndicatorTablePayload,
|
|
21
|
+
OptionalComparisonQueryPayload,
|
|
22
|
+
SubMeshPayload,
|
|
23
|
+
)
|
|
24
|
+
from .query.commons import (
|
|
25
|
+
get_sub_territories,
|
|
26
|
+
get_territory_name,
|
|
27
|
+
get_values_for_territory,
|
|
28
|
+
)
|
|
29
|
+
from .query.comparison import get_comparison_values_and_buckets
|
|
30
|
+
from .query.details import get_proportions_chart, get_values_for_submesh_territories
|
|
31
|
+
from .query.histogram import get_indicator_histogram_data
|
|
32
|
+
from .query.indicator_card import (
|
|
33
|
+
get_geography_statistics_values_for_indicator,
|
|
34
|
+
get_names_from_codes,
|
|
35
|
+
)
|
|
36
|
+
from .query.top_10 import get_indicator_top_10_data
|
|
37
|
+
from .query.utils import run_custom_query
|
|
38
|
+
from .table import (
|
|
39
|
+
get_count_and_data_for_indicator_table,
|
|
40
|
+
get_export_indicator_table_values,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def download_indicator_methodo_view(request, name):
|
|
45
|
+
"""View to download the methodology file for an indicator."""
|
|
46
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
47
|
+
|
|
48
|
+
if not indicator.methodo_file:
|
|
49
|
+
raise Http404("No methodology file available for this indicator.")
|
|
50
|
+
|
|
51
|
+
response = HttpResponse(indicator.methodo_file, content_type="application/pdf")
|
|
52
|
+
response["Content-Disposition"] = "attachment; filename=methodo.pdf"
|
|
53
|
+
response = track_event(
|
|
54
|
+
request=request,
|
|
55
|
+
response=response,
|
|
56
|
+
event_name=EventType.download,
|
|
57
|
+
data={"indicator": indicator.name, "objet": "methodo"},
|
|
58
|
+
)
|
|
59
|
+
return response
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@cache_control(max_age=3600)
|
|
63
|
+
@use_payload(SubMeshPayload)
|
|
64
|
+
def indicator_statistics_view(request, name, payload):
|
|
65
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
66
|
+
filters = get_filters(request, indicator)
|
|
67
|
+
query = get_geography_statistics_values_for_indicator(
|
|
68
|
+
indicator,
|
|
69
|
+
payload.territory,
|
|
70
|
+
payload.submesh,
|
|
71
|
+
filters,
|
|
72
|
+
)
|
|
73
|
+
rows = run_custom_query(query)
|
|
74
|
+
if not rows:
|
|
75
|
+
return HttpResponse("{}")
|
|
76
|
+
data = rows[0]
|
|
77
|
+
data = get_names_from_codes(data, payload.submesh)
|
|
78
|
+
return HttpResponse(json.dumps(data))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def get_values(indicator, payload, filters):
|
|
82
|
+
query = get_values_for_territory(
|
|
83
|
+
indicator,
|
|
84
|
+
payload.territory,
|
|
85
|
+
filters,
|
|
86
|
+
)
|
|
87
|
+
rows = run_custom_query(query)
|
|
88
|
+
results = {"values": rows}
|
|
89
|
+
if payload.cmp_territory:
|
|
90
|
+
query = get_values_for_territory(
|
|
91
|
+
indicator,
|
|
92
|
+
payload.cmp_territory,
|
|
93
|
+
filters,
|
|
94
|
+
)
|
|
95
|
+
cmp_rows = run_custom_query(query)
|
|
96
|
+
results["cmp_values"] = cmp_rows
|
|
97
|
+
return results
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def get_filters(request, indicator):
|
|
101
|
+
filters = {}
|
|
102
|
+
for dimension in indicator.dimensions.all():
|
|
103
|
+
input_filters = request.GET.getlist(dimension.db_name)
|
|
104
|
+
possible_filters = [f.db_name for f in dimension.filters.all()]
|
|
105
|
+
filters[dimension.db_name] = [f for f in input_filters if f in possible_filters]
|
|
106
|
+
return filters
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@require_GET
|
|
110
|
+
@cache_control(max_age=3600)
|
|
111
|
+
@use_payload(OptionalComparisonQueryPayload)
|
|
112
|
+
def indicator_values_view(request, name, payload):
|
|
113
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
114
|
+
filters = get_filters(request, indicator)
|
|
115
|
+
results = get_values(indicator, payload, filters)
|
|
116
|
+
return HttpResponse(json.dumps(results))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@require_GET
|
|
120
|
+
@use_payload(OptionalComparisonQueryPayload)
|
|
121
|
+
def indicator_values_export_view(request, name, payload):
|
|
122
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
123
|
+
filters = get_filters(request, indicator)
|
|
124
|
+
results = get_values(indicator, payload, filters)
|
|
125
|
+
export_values = {}
|
|
126
|
+
territory_name = get_territory_name(payload.territory)
|
|
127
|
+
for value in results["values"]:
|
|
128
|
+
export_values[value["annee"]] = {
|
|
129
|
+
"Année": value["annee"],
|
|
130
|
+
f"Valeur {territory_name} ({indicator.unite})": value["valeur"],
|
|
131
|
+
}
|
|
132
|
+
if results.get("cmp_values") is not None:
|
|
133
|
+
cmp_territory_name = get_territory_name(payload.cmp_territory)
|
|
134
|
+
for value in results["cmp_values"]:
|
|
135
|
+
export_values[value["annee"]][
|
|
136
|
+
f"Valeur {cmp_territory_name} ({indicator.unite})"
|
|
137
|
+
] = value["valeur"]
|
|
138
|
+
return export_to_csv(
|
|
139
|
+
request, indicator, "comparaison-historique", list(export_values.values())
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@require_GET
|
|
144
|
+
@cache_control(max_age=3600)
|
|
145
|
+
@use_payload(SubMeshPayload)
|
|
146
|
+
def indicator_submesh_territories_view(request, name, payload):
|
|
147
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
148
|
+
filters = get_filters(request, indicator)
|
|
149
|
+
data = get_values_for_submesh_territories(
|
|
150
|
+
indicator, payload.submesh, payload.territory, filters
|
|
151
|
+
)
|
|
152
|
+
return HttpResponse(json.dumps(data))
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@cache_control(max_age=3600)
|
|
156
|
+
@use_payload(BasePayload)
|
|
157
|
+
def proportions_chart_view(request, name, payload):
|
|
158
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
159
|
+
if indicator.dimensions.count() == 0:
|
|
160
|
+
return HttpResponse(status=400)
|
|
161
|
+
filters = get_filters(request, indicator)
|
|
162
|
+
rows = get_proportions_chart(
|
|
163
|
+
indicator,
|
|
164
|
+
payload.territory,
|
|
165
|
+
filters,
|
|
166
|
+
)
|
|
167
|
+
return HttpResponse(json.dumps({"values": rows}))
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@require_GET
|
|
171
|
+
@use_payload(BasePayload)
|
|
172
|
+
def indicator_proportions_export_view(request, name, payload):
|
|
173
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
174
|
+
if indicator.dimensions.count() == 0:
|
|
175
|
+
return HttpResponse(status=400)
|
|
176
|
+
filters = get_filters(request, indicator)
|
|
177
|
+
rows = get_proportions_chart(
|
|
178
|
+
indicator,
|
|
179
|
+
payload.territory,
|
|
180
|
+
filters,
|
|
181
|
+
)
|
|
182
|
+
rows = [
|
|
183
|
+
{"Dimension": r["label"], f"Valeur {indicator.unite}": r["data"][0]}
|
|
184
|
+
for r in rows
|
|
185
|
+
]
|
|
186
|
+
return export_to_csv(request, indicator, "repartition-dimension", rows)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@cache_control(max_age=3600)
|
|
190
|
+
@use_payload(SubMeshPayload)
|
|
191
|
+
def indicator_histogram_view(request, name, payload):
|
|
192
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
193
|
+
filters = get_filters(request, indicator)
|
|
194
|
+
data = get_indicator_histogram_data(
|
|
195
|
+
indicator,
|
|
196
|
+
payload.territory,
|
|
197
|
+
payload.submesh,
|
|
198
|
+
filters,
|
|
199
|
+
)
|
|
200
|
+
return HttpResponse(json.dumps(data))
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@cache_control(max_age=3600)
|
|
204
|
+
@use_payload(SubMeshPayload)
|
|
205
|
+
def indicator_histogram_export_view(request, name, payload):
|
|
206
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
207
|
+
filters = get_filters(request, indicator)
|
|
208
|
+
data = get_indicator_histogram_data(
|
|
209
|
+
indicator,
|
|
210
|
+
payload.territory,
|
|
211
|
+
payload.submesh,
|
|
212
|
+
filters,
|
|
213
|
+
)
|
|
214
|
+
rows = []
|
|
215
|
+
for index, decile in enumerate(data["deciles"]):
|
|
216
|
+
row = {}
|
|
217
|
+
next_decile = (
|
|
218
|
+
format_indicator_value(data["deciles"][index + 1])
|
|
219
|
+
if index < len(data["deciles"]) - 1
|
|
220
|
+
else "+"
|
|
221
|
+
)
|
|
222
|
+
row["Décile"] = f"{format_indicator_value(decile)} - {next_decile}"
|
|
223
|
+
row["Nombre de territoires"] = data["datasetsHistogramBarChart"]["data"][index][
|
|
224
|
+
"y"
|
|
225
|
+
]
|
|
226
|
+
row["Commentaire"] = data["datasetsHistogramBarChart"]["comments"][
|
|
227
|
+
index
|
|
228
|
+
].replace("\n", " | ")
|
|
229
|
+
rows.append(row)
|
|
230
|
+
return export_to_csv(request, indicator, "repartition-valeurs", rows)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@cache_control(max_age=3600)
|
|
234
|
+
@use_payload(SubMeshPayload)
|
|
235
|
+
def indicator_top_10_view(request, name, payload):
|
|
236
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
237
|
+
filters = get_filters(request, indicator)
|
|
238
|
+
data, _ = get_indicator_top_10_data(
|
|
239
|
+
indicator,
|
|
240
|
+
payload.territory,
|
|
241
|
+
payload.submesh,
|
|
242
|
+
filters,
|
|
243
|
+
)
|
|
244
|
+
return HttpResponse(json.dumps(data))
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@require_GET
|
|
248
|
+
@use_payload(SubMeshPayload)
|
|
249
|
+
def indicator_top_10_export_view(request, name, payload):
|
|
250
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
251
|
+
filters = get_filters(request, indicator)
|
|
252
|
+
_, csv_data = get_indicator_top_10_data(
|
|
253
|
+
indicator,
|
|
254
|
+
payload.territory,
|
|
255
|
+
payload.submesh,
|
|
256
|
+
filters,
|
|
257
|
+
)
|
|
258
|
+
return export_to_csv(request, indicator, "top_10", csv_data)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
@require_GET
|
|
262
|
+
@cache_control(max_age=3600)
|
|
263
|
+
@use_payload(FlowsPayload)
|
|
264
|
+
def flows_view(request, payload):
|
|
265
|
+
flows_table = f"{payload.prefix}_{payload.submesh}"
|
|
266
|
+
|
|
267
|
+
# Query to get the latest year
|
|
268
|
+
last_year_query = f"SELECT DISTINCT annee FROM {flows_table} ORDER BY annee DESC"
|
|
269
|
+
last_year = run_custom_query(last_year_query)[0]["annee"]
|
|
270
|
+
|
|
271
|
+
mapped_geo_level = (
|
|
272
|
+
"DEPCOM" if payload.territory.mesh == "com" else payload.territory.mesh.upper()
|
|
273
|
+
)
|
|
274
|
+
mapped_mesh_level = (
|
|
275
|
+
"DEPCOM" if payload.submesh == "com" else payload.submesh.upper()
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
codes = ", ".join(f"'{code.strip()}'" for code in payload.territory.id.split(","))
|
|
279
|
+
|
|
280
|
+
# Geo query
|
|
281
|
+
geo_query = f"""
|
|
282
|
+
SELECT DISTINCT
|
|
283
|
+
arbo."{mapped_mesh_level}" as territory_id,
|
|
284
|
+
arbo."NOM_{mapped_mesh_level}" as territory_name,
|
|
285
|
+
ST_ASGEOJSON(ST_CENTROID(contours.geometry)) as center
|
|
286
|
+
FROM arborescence_geo AS arbo
|
|
287
|
+
JOIN contours_simplified_{payload.submesh} as contours
|
|
288
|
+
ON arbo."{mapped_mesh_level}" = contours.code
|
|
289
|
+
WHERE arbo."{mapped_geo_level}" IN ({codes})
|
|
290
|
+
"""
|
|
291
|
+
territories = run_custom_query(geo_query)
|
|
292
|
+
territories_ids = ", ".join(f"'{t['territory_id'].strip()}'" for t in territories)
|
|
293
|
+
|
|
294
|
+
dimension_value = (
|
|
295
|
+
f"{payload.dimension} as dimension"
|
|
296
|
+
if payload.dimension
|
|
297
|
+
else "'all' as dimension"
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
# Values query
|
|
301
|
+
values_query = f"""
|
|
302
|
+
SELECT
|
|
303
|
+
code_{payload.submesh}_1 as territory_1_id,
|
|
304
|
+
code_{payload.submesh}_2 as territory_2_id,
|
|
305
|
+
CAST(valeur AS int) as value,
|
|
306
|
+
{dimension_value}
|
|
307
|
+
FROM {flows_table} flows
|
|
308
|
+
WHERE annee = {last_year}
|
|
309
|
+
AND (
|
|
310
|
+
code_{payload.submesh}_1 IN ({territories_ids})
|
|
311
|
+
OR code_{payload.submesh}_2 IN ({territories_ids})
|
|
312
|
+
)
|
|
313
|
+
"""
|
|
314
|
+
row_values = run_custom_query(values_query)
|
|
315
|
+
territories_dict = {
|
|
316
|
+
t["territory_id"]: {
|
|
317
|
+
"name": t["territory_name"],
|
|
318
|
+
"code": t["territory_id"],
|
|
319
|
+
"center": json.loads(t["center"]),
|
|
320
|
+
}
|
|
321
|
+
for t in territories
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
external_territories_ids = set()
|
|
325
|
+
for row in row_values:
|
|
326
|
+
if row["territory_1_id"] not in territories_dict:
|
|
327
|
+
external_territories_ids.add(row["territory_1_id"])
|
|
328
|
+
if row["territory_2_id"] not in territories_dict:
|
|
329
|
+
external_territories_ids.add(row["territory_2_id"])
|
|
330
|
+
external_territories_ids
|
|
331
|
+
|
|
332
|
+
codes = ", ".join([f"'{tid}'" for tid in external_territories_ids])
|
|
333
|
+
geo_query = f"""
|
|
334
|
+
SELECT DISTINCT
|
|
335
|
+
arbo."{mapped_mesh_level}" as territory_id,
|
|
336
|
+
arbo."NOM_{mapped_mesh_level}" as territory_name,
|
|
337
|
+
ST_ASGEOJSON(ST_CENTROID(contours.geometry)) as center
|
|
338
|
+
FROM arborescence_geo AS arbo
|
|
339
|
+
JOIN contours_simplified_{payload.submesh} as contours
|
|
340
|
+
ON arbo."{mapped_mesh_level}" = contours.code
|
|
341
|
+
WHERE arbo."{mapped_mesh_level}" IN ({codes})
|
|
342
|
+
"""
|
|
343
|
+
external_territories = run_custom_query(geo_query)
|
|
344
|
+
for t in external_territories:
|
|
345
|
+
territories_dict[t["territory_id"]] = {
|
|
346
|
+
"name": f"{t['territory_name']} (externe)",
|
|
347
|
+
"code": t["territory_id"],
|
|
348
|
+
"center": json.loads(t["center"]),
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return JsonResponse(
|
|
352
|
+
{"flows": row_values, "territories": territories_dict}, status=200
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
@require_GET
|
|
357
|
+
@cache_control(max_age=3600)
|
|
358
|
+
@use_payload(ComparisonQueryPayload)
|
|
359
|
+
def comparison_histogram_view(request, name, payload):
|
|
360
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
361
|
+
filters = get_filters(request, indicator)
|
|
362
|
+
territories = get_sub_territories(payload.territory, payload.submesh)
|
|
363
|
+
cmp_territories = get_sub_territories(payload.cmp_territory, payload.submesh)
|
|
364
|
+
values, cmp_values, buckets = get_comparison_values_and_buckets(
|
|
365
|
+
indicator, payload.submesh, territories, cmp_territories, filters
|
|
366
|
+
)
|
|
367
|
+
return JsonResponse(
|
|
368
|
+
{
|
|
369
|
+
"values": values,
|
|
370
|
+
"comparedValues": cmp_values,
|
|
371
|
+
"buckets": buckets,
|
|
372
|
+
}
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
@require_GET
|
|
377
|
+
@use_payload(ComparisonQueryPayload)
|
|
378
|
+
def comparison_histogram_export_view(request, name, payload):
|
|
379
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
380
|
+
filters = get_filters(request, indicator)
|
|
381
|
+
territories = get_sub_territories(payload.territory, payload.submesh)
|
|
382
|
+
cmp_territories = get_sub_territories(payload.cmp_territory, payload.submesh)
|
|
383
|
+
values, cmp_values, buckets = get_comparison_values_and_buckets(
|
|
384
|
+
indicator, payload.submesh, territories, cmp_territories, filters
|
|
385
|
+
)
|
|
386
|
+
rows = []
|
|
387
|
+
territory_name = get_territory_name(payload.territory)
|
|
388
|
+
cmp_territory_name = get_territory_name(payload.cmp_territory)
|
|
389
|
+
for index, bucket in enumerate(buckets):
|
|
390
|
+
row = {}
|
|
391
|
+
row["Décile"] = (
|
|
392
|
+
f"{format_indicator_value(bucket[0])} - {format_indicator_value(bucket[1])}"
|
|
393
|
+
)
|
|
394
|
+
row[f"{territory_name} - Nombre de {MESH_TITLES[payload.submesh]}s"] = len(
|
|
395
|
+
values[index + 1]
|
|
396
|
+
)
|
|
397
|
+
row[f"{cmp_territory_name} - Nombre de {MESH_TITLES[payload.submesh]}s"] = len(
|
|
398
|
+
cmp_values[index + 1]
|
|
399
|
+
)
|
|
400
|
+
row[f"{territory_name} - échantillon de dix territoires"] = " | ".join(
|
|
401
|
+
values[index + 1][:10]
|
|
402
|
+
)
|
|
403
|
+
row[f"{cmp_territory_name} - échantillon de dix territoires"] = " | ".join(
|
|
404
|
+
cmp_values[index + 1][:10]
|
|
405
|
+
)
|
|
406
|
+
rows.append(row)
|
|
407
|
+
return export_to_csv(request, indicator, "comparison-histogram", rows)
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def get_label(props, indicator, key):
|
|
411
|
+
labels = {
|
|
412
|
+
"annee": "Année",
|
|
413
|
+
"lieu": "Lieu",
|
|
414
|
+
"territory_1": "Origine",
|
|
415
|
+
"territory_2": "Destination",
|
|
416
|
+
"valeur": "flux" if props.flows else indicator.unite,
|
|
417
|
+
"valeur_alternative": indicator.unite_alternative,
|
|
418
|
+
"dimension": "Dimension",
|
|
419
|
+
}
|
|
420
|
+
for dimension in indicator.dimensions.all():
|
|
421
|
+
labels[dimension.db_name] = dimension.title
|
|
422
|
+
return labels[key]
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def get_pages(count, limit, current):
|
|
426
|
+
length = count // limit
|
|
427
|
+
if count % limit != 0 or count == 0:
|
|
428
|
+
length += 1
|
|
429
|
+
page_range = list(range(1, length + 1))
|
|
430
|
+
pages = {
|
|
431
|
+
"first": page_range[0] if page_range[0] != current else None,
|
|
432
|
+
"last": page_range[-1] if page_range[-1] != current else None,
|
|
433
|
+
"current": current,
|
|
434
|
+
"before": current - 1 if current - 1 in page_range else None,
|
|
435
|
+
"after": current + 1 if current + 1 in page_range else None,
|
|
436
|
+
"only_one_page": page_range == [1],
|
|
437
|
+
}
|
|
438
|
+
return pages
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def get_line_focus(payload: IndicatorTablePayload):
|
|
442
|
+
if not payload.focus:
|
|
443
|
+
return None
|
|
444
|
+
limit = payload.limit
|
|
445
|
+
previous_limit = payload.previous_limit
|
|
446
|
+
if limit and previous_limit:
|
|
447
|
+
if limit <= previous_limit:
|
|
448
|
+
return 1
|
|
449
|
+
else:
|
|
450
|
+
return previous_limit + 1
|
|
451
|
+
return None
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
@require_GET
|
|
455
|
+
@use_payload(IndicatorTablePayload)
|
|
456
|
+
def indicator_details_table_view(request, name, payload):
|
|
457
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
458
|
+
filters = get_filters(request, indicator)
|
|
459
|
+
count, data = get_count_and_data_for_indicator_table(indicator, payload, filters)
|
|
460
|
+
formated_data = [format_data(element) for element in data]
|
|
461
|
+
keys = [
|
|
462
|
+
{"db": key, "label": get_label(payload, indicator, key)}
|
|
463
|
+
for key in (formated_data[0].keys() if formated_data else [])
|
|
464
|
+
]
|
|
465
|
+
last_year = None
|
|
466
|
+
if data and "annee" in data[0].keys():
|
|
467
|
+
last_year = max([d["annee"] for d in data])
|
|
468
|
+
context = {
|
|
469
|
+
"rows": formated_data,
|
|
470
|
+
"keys": keys,
|
|
471
|
+
"result_count": count,
|
|
472
|
+
"pages": get_pages(count, payload.limit, payload.pagination),
|
|
473
|
+
"props": payload,
|
|
474
|
+
"last_year": last_year,
|
|
475
|
+
"line_focus": get_line_focus(payload),
|
|
476
|
+
}
|
|
477
|
+
return render(
|
|
478
|
+
request,
|
|
479
|
+
"territories_dashboard_lib/website/pages/indicators/details/components/table.html",
|
|
480
|
+
context,
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
@require_GET
|
|
485
|
+
@use_payload(IndicatorTablePayload)
|
|
486
|
+
def indicator_details_table_export_view(request, name, payload):
|
|
487
|
+
indicator = get_object_or_404(Indicator, name=name)
|
|
488
|
+
filters = get_filters(request, indicator)
|
|
489
|
+
table_values = get_export_indicator_table_values(indicator, payload, filters)
|
|
490
|
+
return export_to_csv(request, indicator, "table", table_values)
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from django.contrib import admin
|
|
2
|
+
from django.db import models
|
|
3
|
+
from django.forms import TextInput
|
|
4
|
+
|
|
5
|
+
from .models import Dashboard, Filter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FilterInLine(admin.TabularInline):
|
|
9
|
+
model = Filter
|
|
10
|
+
extra = 0
|
|
11
|
+
formfield_overrides = {
|
|
12
|
+
models.TextField: {"widget": TextInput(attrs={"size": "32"})},
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@admin.register(Dashboard)
|
|
17
|
+
class DashboardAdmin(admin.ModelAdmin):
|
|
18
|
+
formfield_overrides = {
|
|
19
|
+
models.TextField: {"widget": TextInput(attrs={"size": "32"})},
|
|
20
|
+
}
|
|
21
|
+
inlines = [FilterInLine]
|
|
22
|
+
list_display = ["short_name", "order"]
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import http.client
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_guest_token(dashboard_id):
|
|
8
|
+
"""
|
|
9
|
+
Function copied from https://snum.gitlab-pages.din.developpement-durable.gouv.fr/ds/gd3ia/offre-dataviz-documentation/05-Documentation_SUPERSET_INTEGRATION/
|
|
10
|
+
"""
|
|
11
|
+
conn = http.client.HTTPSConnection(settings.SUPERSET_DOMAIN)
|
|
12
|
+
params = json.dumps(
|
|
13
|
+
{
|
|
14
|
+
"provider": "db",
|
|
15
|
+
"refresh": "True",
|
|
16
|
+
"username": settings.SUPERSET_USERNAME,
|
|
17
|
+
"password": settings.SUPERSET_PASSWORD,
|
|
18
|
+
}
|
|
19
|
+
)
|
|
20
|
+
conn.request(
|
|
21
|
+
"POST", "/api/v1/security/login", params, {"Content-Type": "application/json"}
|
|
22
|
+
)
|
|
23
|
+
response = conn.getresponse()
|
|
24
|
+
content = json.loads(response.read())
|
|
25
|
+
access_token = content["access_token"]
|
|
26
|
+
|
|
27
|
+
# Recuperation du token CSRF et cookie de session associe
|
|
28
|
+
headers = {"Authorization": f"Bearer {access_token}"}
|
|
29
|
+
conn.request("GET", "/api/v1/security/csrf_token/", None, headers)
|
|
30
|
+
response = conn.getresponse()
|
|
31
|
+
content = json.loads(response.read())
|
|
32
|
+
csrf_token = content["result"]
|
|
33
|
+
cookie = response.headers["set-cookie"].split("; ")[0]
|
|
34
|
+
|
|
35
|
+
# Recuperation du guest_token pour l'affichage du diagramme
|
|
36
|
+
params = json.dumps(
|
|
37
|
+
{
|
|
38
|
+
"resources": [{"id": dashboard_id, "type": "dashboard"}],
|
|
39
|
+
"rls": [
|
|
40
|
+
{
|
|
41
|
+
# Clause SQL appliquée à la récupération des donnes du dashboard
|
|
42
|
+
# Elle peut être ajustée pour limiter les données affichées
|
|
43
|
+
# dans le dashboard en fonction du profil utilisateur
|
|
44
|
+
# La valeur "1=1" permet de n'appliquer aucun filtre
|
|
45
|
+
"clause": "1=1"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"user": {
|
|
49
|
+
"first_name": "Prenom",
|
|
50
|
+
"last_name": "Nom",
|
|
51
|
+
"username": settings.SUPERSET_USERNAME,
|
|
52
|
+
},
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
headers = {
|
|
56
|
+
"Content-Type": "application/json",
|
|
57
|
+
"Authorization": f"Bearer {access_token}",
|
|
58
|
+
"X-Csrftoken": csrf_token,
|
|
59
|
+
"Cookie": cookie,
|
|
60
|
+
}
|
|
61
|
+
conn.request("POST", "/api/v1/security/guest_token/", params, headers)
|
|
62
|
+
response = conn.getresponse()
|
|
63
|
+
guest_token = json.loads(response.read())["token"]
|
|
64
|
+
return guest_token
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from territories_dashboard_lib.indicators_lib.enums import MeshLevel
|
|
2
|
+
from territories_dashboard_lib.indicators_lib.query.utils import run_custom_query
|
|
3
|
+
|
|
4
|
+
from .models import Dashboard
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_territory_meshes(territory_id: str, territory_mesh: MeshLevel):
|
|
8
|
+
current_reg = None
|
|
9
|
+
current_dep = None
|
|
10
|
+
current_epci = None
|
|
11
|
+
current_com = None
|
|
12
|
+
if territory_mesh != MeshLevel.National:
|
|
13
|
+
mapped_mesh = "DEPCOM" if territory_mesh == "com" else territory_mesh.upper()
|
|
14
|
+
query = f"""
|
|
15
|
+
SELECT
|
|
16
|
+
"NOM_REG" as reg_name,
|
|
17
|
+
"NOM_DEP" as dep_name,
|
|
18
|
+
"NOM_EPCI" as epci_name,
|
|
19
|
+
"NOM_DEPCOM" as com_name
|
|
20
|
+
FROM arborescence_geo
|
|
21
|
+
WHERE "{mapped_mesh}" = '{territory_id}'
|
|
22
|
+
LIMIT 1
|
|
23
|
+
"""
|
|
24
|
+
row = run_custom_query(query)[0]
|
|
25
|
+
if territory_mesh in [
|
|
26
|
+
MeshLevel.Region,
|
|
27
|
+
MeshLevel.Department,
|
|
28
|
+
MeshLevel.Epci,
|
|
29
|
+
MeshLevel.Town,
|
|
30
|
+
]:
|
|
31
|
+
current_reg = row["reg_name"]
|
|
32
|
+
if territory_mesh in [
|
|
33
|
+
MeshLevel.Department,
|
|
34
|
+
MeshLevel.Epci,
|
|
35
|
+
MeshLevel.Town,
|
|
36
|
+
]:
|
|
37
|
+
current_dep = row["dep_name"]
|
|
38
|
+
if territory_mesh in [
|
|
39
|
+
MeshLevel.Epci,
|
|
40
|
+
MeshLevel.Town,
|
|
41
|
+
]:
|
|
42
|
+
current_epci = row["epci_name"]
|
|
43
|
+
if territory_mesh in [
|
|
44
|
+
MeshLevel.Town,
|
|
45
|
+
]:
|
|
46
|
+
current_com = row["com_name"]
|
|
47
|
+
return {
|
|
48
|
+
MeshLevel.Region: current_reg,
|
|
49
|
+
MeshLevel.Department: current_dep,
|
|
50
|
+
MeshLevel.Epci: current_epci,
|
|
51
|
+
MeshLevel.Town: current_com,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def make_filter(dashboard: Dashboard, territory_id: str, territory_mesh: MeshLevel):
|
|
56
|
+
if dashboard.filters.count() == 0:
|
|
57
|
+
return None
|
|
58
|
+
territory_meshes = get_territory_meshes(territory_id, territory_mesh)
|
|
59
|
+
filters = []
|
|
60
|
+
for f in dashboard.filters.all():
|
|
61
|
+
value = territory_meshes.get(f.mesh)
|
|
62
|
+
if value:
|
|
63
|
+
filter_string = f"""NATIVE_FILTER-{f.superset_id}:(__cache:(label:'{value}',validateStatus:!f,value:!('{value}')),extraFormData:(filters:!((col:{f.superset_col},op:IN,val:!('{value}')))),filterState:(label:'{value}',validateStatus:!f,value:!('{value}')),id:NATIVE_FILTER-{f.superset_id},ownState:())"""
|
|
64
|
+
filters.append(filter_string)
|
|
65
|
+
if not filters:
|
|
66
|
+
return None
|
|
67
|
+
return f"""({",".join(filters)})"""
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Generated by Django 5.2.3 on 2025-06-18 13:03
|
|
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
|
+
]
|
|
13
|
+
|
|
14
|
+
operations = [
|
|
15
|
+
migrations.CreateModel(
|
|
16
|
+
name='Dashboard',
|
|
17
|
+
fields=[
|
|
18
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
19
|
+
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
20
|
+
('updated_at', models.DateTimeField(auto_now=True)),
|
|
21
|
+
('superset_id', models.TextField(help_text="Un utilisateur administrateur de l'instance Superset doit accéder aux paramètres du dashboard et cliquer sur 'embed dashboard' pour récupérer cet ID nécessaire à la connexion avec l'instance Superset.", unique=True, verbose_name='Embed ID de Superset')),
|
|
22
|
+
('short_name', models.TextField(help_text="Pour l'URL, ne mettre que des lettres minuscules sans accents et des tirets", unique=True, verbose_name='Nom court')),
|
|
23
|
+
('label', models.TextField(help_text='Nom du dashboard à afficher dans la liste.', unique=True, verbose_name='Label')),
|
|
24
|
+
('order', models.IntegerField(default=1, help_text="Numéro d'ordre dans la dropdown de sélection, les dashboards sont triés du plus petit numéro au plus grand.", verbose_name="Numéro d'ordre")),
|
|
25
|
+
],
|
|
26
|
+
options={
|
|
27
|
+
'abstract': False,
|
|
28
|
+
},
|
|
29
|
+
),
|
|
30
|
+
migrations.CreateModel(
|
|
31
|
+
name='Filter',
|
|
32
|
+
fields=[
|
|
33
|
+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
34
|
+
('created_at', models.DateTimeField(auto_now_add=True)),
|
|
35
|
+
('updated_at', models.DateTimeField(auto_now=True)),
|
|
36
|
+
('superset_id', models.TextField(blank=True, help_text="ID du native filter du territoire, qui permettra d'initialiser les filtres du dasbhoard au territoire sélectionné dans l'application. Pour le récupérer c'est un petit parcours du combattant : aller sur le dashboard dans superset, cliquer sur modifier le dashboard, cliquer sur les trois petits points, puis sur modifier les propriétés. Cliquer sur avancé, copier le json et le coller dans un site comme : https://jsonformatter.curiousconcept.com/ pour mieux le voir. Chercher 'global_chart_configuration' puis 'native_filter_configuration'. Chercher le native filter lié au choix du territoire. Copier l'id qui dans son nom, le nom est de la forme NATIVE_FILTER-ID. Promis, c'est le plus simple que j'ai trouvé !", null=True)),
|
|
37
|
+
('superset_col', models.TextField(blank=True, help_text="Nom de la colonne en base de données liée au filtre sur le territoire. Pour trouver le nom faire les mêmes étapes que pour geo_filter_id et chercher 'column' dans les paramètres json du native filter.", null=True)),
|
|
38
|
+
('mesh', models.TextField(blank=True, choices=[('fr', 'National'), ('reg', 'Region'), ('dep', 'Department'), ('epci', 'Epci'), ('com', 'Town')], help_text="Maille du territoire sur lequel s'effectue le filtre.", null=True)),
|
|
39
|
+
('dashboard', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='filters', to='superset_lib.dashboard')),
|
|
40
|
+
],
|
|
41
|
+
options={
|
|
42
|
+
'abstract': False,
|
|
43
|
+
},
|
|
44
|
+
),
|
|
45
|
+
]
|
|
File without changes
|