From 107c55863c4ff15063d6116e8ebad043f3b94613 Mon Sep 17 00:00:00 2001 From: Jean-Marie Favreau Date: Wed, 16 Oct 2024 23:55:03 +0200 Subject: [PATCH] =?UTF-8?q?Ajout=20d'un=20filtre=20par=20proximit=C3=A9=20?= =?UTF-8?q?g=C3=A9ographique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 4 + README.md | 6 + src/agenda_culturel/admin.py | 4 +- .../locale/fr/LC_MESSAGES/django.po | 473 +-- .../migrations/0087_referencelocation.py | 24 + ...lter_referencelocation_options_and_more.py | 22 + src/agenda_culturel/models.py | 16 + src/agenda_culturel/static/style.scss | 9 +- .../templates/agenda_culturel/filter-inc.html | 34 +- src/agenda_culturel/views.py | 66 +- src/scripts/communes.json | 3259 +++++++++++++++++ src/scripts/create_reference_locations.py | 17 + 12 files changed, 3682 insertions(+), 252 deletions(-) create mode 100644 src/agenda_culturel/migrations/0087_referencelocation.py create mode 100644 src/agenda_culturel/migrations/0088_alter_referencelocation_options_and_more.py create mode 100644 src/scripts/communes.json create mode 100644 src/scripts/create_reference_locations.py diff --git a/Makefile b/Makefile index d7a03fd..471b97d 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,10 @@ create-categories: docker exec -it $(BACKEND_APP_NAME) $(SHELL) "-c" \ "python3 manage.py runscript create_categories" +create-reference-locations: + docker exec -it $(BACKEND_APP_NAME) $(SHELL) "-c" \ + "python3 manage.py runscript create_reference_locations" + build-dev: DOCKER_BUILDKIT=1 COMPOSE_DOCKER_CLI_BUILD=1 docker-compose -f docker-compose.yml up --build -d diff --git a/README.md b/README.md index cb6196e..6be0ca0 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,12 @@ On peut aussi peupler les catégories avec un choix de catégories élémentaire * ```make create-categories``` +On peut aussi peupler les positions de référence qui serviront aux recherches géographiques avec la commande, après avoir éventuellement modifié le fichier [communes.json](./src/scripts/communes.json) qui contient pour l'exemple toutes les communes récupérées depuis [public.opendatasoft.com](https://public.opendatasoft.com/explore/dataset/georef-france-commune/export/?flg=fr-fr&disjunctive.reg_name&disjunctive.dep_name&disjunctive.arrdep_name&disjunctive.ze2020_name&disjunctive.bv2022_name&disjunctive.epci_name&disjunctive.ept_name&disjunctive.com_name&disjunctive.ze2010_name&disjunctive.com_is_mountain_area&sort=year&refine.dep_name=Puy-de-D%C3%B4me&location=9,45.51597,3.05969&basemap=jawg.light): + +* ```make create-reference-locations``` + + + ## Notes aux développeurs ### Ajout d'une nouvelle source *custom* diff --git a/src/agenda_culturel/admin.py b/src/agenda_culturel/admin.py index 977dd20..81d5e4a 100644 --- a/src/agenda_culturel/admin.py +++ b/src/agenda_culturel/admin.py @@ -8,7 +8,8 @@ from .models import ( BatchImportation, RecurrentImport, Place, - ContactMessage + ContactMessage, + ReferenceLocation ) from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget @@ -22,6 +23,7 @@ admin.site.register(BatchImportation) admin.site.register(RecurrentImport) admin.site.register(Place) admin.site.register(ContactMessage) +admin.site.register(ReferenceLocation) class URLWidget(DynamicArrayWidget): diff --git a/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po b/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po index bac901e..5ff8561 100644 --- a/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po +++ b/src/agenda_culturel/locale/fr/LC_MESSAGES/django.po @@ -2,13 +2,13 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Jean-Marie Favreau , 2023. -# +# #, fuzzy msgid "" msgstr "" "Project-Id-Version: agenda_culturel\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-10-10 14:22+0200\n" +"POT-Creation-Date: 2024-10-16 23:42+0200\n" "PO-Revision-Date: 2023-10-29 14:16+0000\n" "Last-Translator: Jean-Marie Favreau \n" "Language-Team: Jean-Marie Favreau \n" @@ -90,161 +90,177 @@ msgstr "Après-midi" msgid "Evening" msgstr "Soir" -#: agenda_culturel/forms.py:44 agenda_culturel/models.py:168 -#: agenda_culturel/models.py:336 agenda_culturel/models.py:1347 -#: agenda_culturel/models.py:1447 +#: agenda_culturel/forms.py:44 agenda_culturel/models.py:170 +#: agenda_culturel/models.py:354 agenda_culturel/models.py:1367 +#: agenda_culturel/models.py:1467 msgid "Category" msgstr "Catégorie" -#: agenda_culturel/forms.py:46 -msgid "Unknown" -msgstr "Inconnue" - -#: agenda_culturel/forms.py:47 +#: agenda_culturel/forms.py:48 msgid "Optional. If you dont specify a category, well find it for you." msgstr "" "Facultatif. Si tu ne donnes pas la catégorie, on s'occupe de la trouver." -#: agenda_culturel/forms.py:119 +#: agenda_culturel/forms.py:123 msgid "The end date must be after the start date." msgstr "La date de fin doit être après la date de début." -#: agenda_culturel/forms.py:135 +#: agenda_culturel/forms.py:139 msgid "The end time cannot be earlier than the start time." msgstr "L'heure de fin ne peut pas être avant l'heure de début." -#: agenda_culturel/forms.py:145 +#: agenda_culturel/forms.py:149 msgid "JSON in the format expected for the import." msgstr "JSON dans le format attendu pour l'import" -#: agenda_culturel/forms.py:403 +#: agenda_culturel/forms.py:407 msgid "Apply category {} to the event {}" msgstr "Appliquer la catégorie {} à l'événement {}" -#: agenda_culturel/forms.py:418 agenda_culturel/models.py:260 -#: agenda_culturel/models.py:1499 +#: agenda_culturel/forms.py:422 agenda_culturel/models.py:278 +#: agenda_culturel/models.py:1519 msgid "Place" msgstr "Lieu" -#: agenda_culturel/forms.py:420 +#: agenda_culturel/forms.py:424 msgid "Create a missing place" msgstr "Créer un lieu manquant" -#: agenda_culturel/forms.py:430 +#: agenda_culturel/forms.py:434 msgid "Add \"{}\" to the aliases of the place" msgstr "Ajouter « {} » aux alias du lieu" -#: agenda_culturel/forms.py:457 +#: agenda_culturel/forms.py:461 msgid "On saving, use aliases to detect all matching events with missing place" msgstr "" "Lors de l'enregistrement, utiliser des alias pour détecter tous les " "événements correspondants dont la place est manquante." -#: agenda_culturel/models.py:47 agenda_culturel/models.py:92 -#: agenda_culturel/models.py:239 agenda_culturel/models.py:1220 -#: agenda_culturel/models.py:1293 +#: agenda_culturel/models.py:48 agenda_culturel/models.py:93 +#: agenda_culturel/models.py:240 agenda_culturel/models.py:257 +#: agenda_culturel/models.py:1240 agenda_culturel/models.py:1313 msgid "Name" msgstr "Nom" -#: agenda_culturel/models.py:48 agenda_culturel/models.py:92 +#: agenda_culturel/models.py:49 agenda_culturel/models.py:93 msgid "Category name" msgstr "Nom de la catégorie" -#: agenda_culturel/models.py:53 +#: agenda_culturel/models.py:54 msgid "Content" msgstr "Contenu" -#: agenda_culturel/models.py:53 +#: agenda_culturel/models.py:54 msgid "Text as shown to the visitors" msgstr "Texte tel que présenté aux visiteureuses" -#: agenda_culturel/models.py:57 +#: agenda_culturel/models.py:58 msgid "URL path" msgstr "Chemin URL" -#: agenda_culturel/models.py:58 +#: agenda_culturel/models.py:59 msgid "URL path where the content is included." msgstr "Chemin URL où le contenu est présent." -#: agenda_culturel/models.py:62 +#: agenda_culturel/models.py:63 msgid "Static content" msgstr "Contenu statique" -#: agenda_culturel/models.py:63 +#: agenda_culturel/models.py:64 msgid "Static contents" msgstr "Contenus statiques" -#: agenda_culturel/models.py:95 +#: agenda_culturel/models.py:96 msgid "Alternative Name" msgstr "Nom alternatif" -#: agenda_culturel/models.py:96 +#: agenda_culturel/models.py:97 msgid "Alternative name used with a time period" msgstr "Nom alternatif utilisé avec une période de temps" -#: agenda_culturel/models.py:100 +#: agenda_culturel/models.py:101 msgid "Short name" msgstr "Nom court" -#: agenda_culturel/models.py:101 +#: agenda_culturel/models.py:102 msgid "Short name of the category" msgstr "Nom court de la catégorie" -#: agenda_culturel/models.py:105 +#: agenda_culturel/models.py:106 msgid "Color" msgstr "Couleur" -#: agenda_culturel/models.py:106 +#: agenda_culturel/models.py:107 msgid "Color used as background for the category" msgstr "Couleur utilisée comme fond de la catégorie" -#: agenda_culturel/models.py:112 +#: agenda_culturel/models.py:113 msgid "Pictogram" msgstr "Pictogramme" -#: agenda_culturel/models.py:113 +#: agenda_culturel/models.py:114 #, fuzzy #| msgid "Short name of the category" msgid "Pictogram of the category (svg format)" msgstr "Pictogramme de la catégorie (format svg)" -#: agenda_culturel/models.py:120 +#: agenda_culturel/models.py:121 msgid "Position for ordering categories" msgstr "Position pour ordonner les catégories" -#: agenda_culturel/models.py:169 +#: agenda_culturel/models.py:171 msgid "Categories" msgstr "Catégories" -#: agenda_culturel/models.py:174 agenda_culturel/models.py:175 +#: agenda_culturel/models.py:176 agenda_culturel/models.py:177 msgid "Duplicated events" msgstr "Événements dupliqués" -#: agenda_culturel/models.py:239 +#: agenda_culturel/models.py:240 +msgid "Name of the location" +msgstr "Nom de la position" + +#: agenda_culturel/models.py:243 +msgid "Main" +msgstr "Principale" + +#: agenda_culturel/models.py:244 +msgid "This location is one of the main locations (shown first)." +msgstr "Cette position est une position principale (affichée en premier)." + +#: agenda_culturel/models.py:249 +msgid "Reference location" +msgstr "Position de référence" + +#: agenda_culturel/models.py:250 +msgid "Reference locations" +msgstr "Positions de référence" + +#: agenda_culturel/models.py:257 msgid "Name of the place" msgstr "Nom du lieu" -#: agenda_culturel/models.py:241 +#: agenda_culturel/models.py:259 msgid "Address" msgstr "Adresse" -#: agenda_culturel/models.py:242 +#: agenda_culturel/models.py:260 msgid "Address of this place (without city name)" msgstr "Adresse de ce lieu (sans le nom de la ville)" -#: agenda_culturel/models.py:246 +#: agenda_culturel/models.py:264 msgid "City" msgstr "Ville" -#: agenda_culturel/models.py:246 +#: agenda_culturel/models.py:264 msgid "City name" msgstr "Nom de la ville" -#: agenda_culturel/models.py:251 +#: agenda_culturel/models.py:269 msgid "Alternative names" msgstr "Noms alternatifs" -#: agenda_culturel/models.py:253 +#: agenda_culturel/models.py:271 msgid "" "Alternative names or addresses used to match a place with the free-form " "location of an event." @@ -252,77 +268,77 @@ msgstr "" "Noms et adresses alternatives qui seront utilisées pour associer une adresse " "avec la localisation en forme libre d'un événement" -#: agenda_culturel/models.py:261 +#: agenda_culturel/models.py:279 msgid "Places" msgstr "Lieux" -#: agenda_culturel/models.py:314 agenda_culturel/models.py:1334 +#: agenda_culturel/models.py:332 agenda_culturel/models.py:1354 msgid "Published" msgstr "Publié" -#: agenda_culturel/models.py:315 +#: agenda_culturel/models.py:333 msgid "Draft" msgstr "Brouillon" -#: agenda_culturel/models.py:316 +#: agenda_culturel/models.py:334 msgid "Trash" msgstr "Corbeille" -#: agenda_culturel/models.py:327 +#: agenda_culturel/models.py:345 msgid "Title" msgstr "Titre" -#: agenda_culturel/models.py:327 +#: agenda_culturel/models.py:345 msgid "Short title" msgstr "Titre court" -#: agenda_culturel/models.py:331 agenda_culturel/models.py:1415 +#: agenda_culturel/models.py:349 agenda_culturel/models.py:1435 msgid "Status" msgstr "Status" -#: agenda_culturel/models.py:337 +#: agenda_culturel/models.py:355 msgid "Category of the event" msgstr "Catégorie de l'événement" -#: agenda_culturel/models.py:344 +#: agenda_culturel/models.py:362 msgid "Day of the event" msgstr "Date de l'événement" -#: agenda_culturel/models.py:347 agenda_culturel/models.py:348 +#: agenda_culturel/models.py:365 agenda_culturel/models.py:366 msgid "Starting time" msgstr "Heure de début" -#: agenda_culturel/models.py:354 +#: agenda_culturel/models.py:372 msgid "End day of the event" msgstr "Fin de l'événement" -#: agenda_culturel/models.py:356 +#: agenda_culturel/models.py:374 msgid "End day of the event, only required if different from the start day." msgstr "" "Date de fin de l'événement, uniquement nécessaire s'il est différent du " "premier jour de l'événement" -#: agenda_culturel/models.py:362 +#: agenda_culturel/models.py:380 msgid "Final time" msgstr "Heure de fin" -#: agenda_culturel/models.py:366 +#: agenda_culturel/models.py:384 msgid "Recurrence" msgstr "Récurrence" -#: agenda_culturel/models.py:371 agenda_culturel/models.py:1339 +#: agenda_culturel/models.py:389 agenda_culturel/models.py:1359 msgid "Location" msgstr "Localisation" -#: agenda_culturel/models.py:372 +#: agenda_culturel/models.py:390 msgid "Address of the event" msgstr "Adresse de l'événement" -#: agenda_culturel/models.py:378 +#: agenda_culturel/models.py:396 msgid "Location (free form)" msgstr "Localisation (forme libre)" -#: agenda_culturel/models.py:380 +#: agenda_culturel/models.py:398 msgid "" "Address of the event in case its not available in the already known places " "(free form)" @@ -330,213 +346,213 @@ msgstr "" "Addresse d'un événement si elle n'est pas déjà présente dans la liste des " "lieux disponible (forme libre)" -#: agenda_culturel/models.py:389 +#: agenda_culturel/models.py:407 msgid "Description" msgstr "Description" -#: agenda_culturel/models.py:390 +#: agenda_culturel/models.py:408 msgid "General description of the event" msgstr "Description générale de l'événement" -#: agenda_culturel/models.py:396 +#: agenda_culturel/models.py:414 msgid "Illustration (local image)" msgstr "Illustration (image locale)" -#: agenda_culturel/models.py:397 +#: agenda_culturel/models.py:415 msgid "Illustration image stored in the agenda server" msgstr "Image d'illustration stockée sur le serveur de l'agenda" -#: agenda_culturel/models.py:404 +#: agenda_culturel/models.py:422 msgid "Illustration" msgstr "Illustration" -#: agenda_culturel/models.py:405 +#: agenda_culturel/models.py:423 msgid "URL of the illustration image" msgstr "URL de l'image illustrative" -#: agenda_culturel/models.py:411 +#: agenda_culturel/models.py:429 msgid "Illustration description" msgstr "Description de l'illustration" -#: agenda_culturel/models.py:412 +#: agenda_culturel/models.py:430 msgid "Alternative text used by screen readers for the image" msgstr "Texte alternatif utiliser par les lecteurs d'écrans pour l'image" -#: agenda_culturel/models.py:420 +#: agenda_culturel/models.py:438 msgid "Importation source" msgstr "Source d'importation" -#: agenda_culturel/models.py:421 +#: agenda_culturel/models.py:439 msgid "Importation source used to detect removed entries." msgstr "Source d'importation utilisée pour détecter les éléments supprimés/" -#: agenda_culturel/models.py:427 +#: agenda_culturel/models.py:445 msgid "UUIDs" msgstr "UUIDs" -#: agenda_culturel/models.py:428 +#: agenda_culturel/models.py:446 msgid "UUIDs from import to detect duplicated entries." msgstr "UUIDs utilisés pendant l'import pour détecter les entrées dupliquées" -#: agenda_culturel/models.py:434 +#: agenda_culturel/models.py:452 msgid "URLs" msgstr "URLs" -#: agenda_culturel/models.py:435 +#: agenda_culturel/models.py:453 msgid "List of all the urls where this event can be found." msgstr "Liste de toutes les urls où l'événement peut être trouvé." -#: agenda_culturel/models.py:442 +#: agenda_culturel/models.py:460 msgid "Tags" msgstr "Étiquettes" -#: agenda_culturel/models.py:443 +#: agenda_culturel/models.py:461 msgid "A list of tags that describe the event." msgstr "Une liste d'étiquettes décrivant l'événement" -#: agenda_culturel/models.py:450 +#: agenda_culturel/models.py:468 msgid "Possibly duplicated" msgstr "Possibles doublons" -#: agenda_culturel/models.py:499 +#: agenda_culturel/models.py:517 msgid "Event" msgstr "Événement" -#: agenda_culturel/models.py:500 +#: agenda_culturel/models.py:518 msgid "Events" msgstr "Événements" -#: agenda_culturel/models.py:1211 +#: agenda_culturel/models.py:1231 msgid "Contact message" msgstr "Message de contact" -#: agenda_culturel/models.py:1212 +#: agenda_culturel/models.py:1232 msgid "Contact messages" msgstr "Messages de contact" -#: agenda_culturel/models.py:1215 +#: agenda_culturel/models.py:1235 msgid "Subject" msgstr "Sujet" -#: agenda_culturel/models.py:1216 +#: agenda_culturel/models.py:1236 msgid "The subject of your message" msgstr "Sujet de votre message" -#: agenda_culturel/models.py:1221 +#: agenda_culturel/models.py:1241 msgid "Your name" msgstr "Votre nom" -#: agenda_culturel/models.py:1227 +#: agenda_culturel/models.py:1247 msgid "Email address" msgstr "Adresse email" -#: agenda_culturel/models.py:1228 +#: agenda_culturel/models.py:1248 msgid "Your email address" msgstr "Votre adresse email" -#: agenda_culturel/models.py:1233 +#: agenda_culturel/models.py:1253 msgid "Message" msgstr "Message" -#: agenda_culturel/models.py:1233 +#: agenda_culturel/models.py:1253 msgid "Your message" msgstr "Votre message" -#: agenda_culturel/models.py:1238 agenda_culturel/views.py:883 +#: agenda_culturel/models.py:1258 agenda_culturel/views.py:916 msgid "Spam" msgstr "Spam" -#: agenda_culturel/models.py:1239 +#: agenda_culturel/models.py:1259 msgid "This message is a spam." msgstr "Ce message est un spam." -#: agenda_culturel/models.py:1244 agenda_culturel/views.py:878 +#: agenda_culturel/models.py:1264 agenda_culturel/views.py:911 msgid "Closed" msgstr "Fermé" -#: agenda_culturel/models.py:1246 +#: agenda_culturel/models.py:1266 msgid "this message has been processed and no longer needs to be handled" msgstr "Ce message a été traité et ne nécessite plus d'être pris en charge" -#: agenda_culturel/models.py:1251 +#: agenda_culturel/models.py:1271 msgid "Comments" msgstr "Commentaires" -#: agenda_culturel/models.py:1252 +#: agenda_culturel/models.py:1272 msgid "Comments on the message from the moderation team" msgstr "Commentaires sur ce message par l'équipe de modération" -#: agenda_culturel/models.py:1264 agenda_culturel/models.py:1395 +#: agenda_culturel/models.py:1284 agenda_culturel/models.py:1415 msgid "Recurrent import" msgstr "Import récurrent" -#: agenda_culturel/models.py:1265 +#: agenda_culturel/models.py:1285 msgid "Recurrent imports" msgstr "Imports récurrents" -#: agenda_culturel/models.py:1269 +#: agenda_culturel/models.py:1289 msgid "ical" msgstr "ical" -#: agenda_culturel/models.py:1270 +#: agenda_culturel/models.py:1290 msgid "ical no busy" msgstr "ical sans busy" -#: agenda_culturel/models.py:1271 +#: agenda_culturel/models.py:1291 msgid "ical no VC" msgstr "ical sans VC" -#: agenda_culturel/models.py:1272 +#: agenda_culturel/models.py:1292 msgid "lacoope.org" msgstr "lacoope.org" -#: agenda_culturel/models.py:1273 +#: agenda_culturel/models.py:1293 msgid "la comédie" msgstr "la comédie" -#: agenda_culturel/models.py:1274 +#: agenda_culturel/models.py:1294 msgid "le fotomat" msgstr "le fotomat" -#: agenda_culturel/models.py:1275 +#: agenda_culturel/models.py:1295 #, fuzzy #| msgid "la puce à loreille" msgid "la puce à l'oreille" msgstr "la puce à loreille" -#: agenda_culturel/models.py:1276 +#: agenda_culturel/models.py:1296 msgid "Plugin wordpress MEC" msgstr "Plugin wordpress MEC" -#: agenda_culturel/models.py:1277 -msgid "Événements d'une page" -msgstr "Événements d'une page" +#: agenda_culturel/models.py:1297 +msgid "Événements d'une page FB" +msgstr "Événements d'une page FB" -#: agenda_culturel/models.py:1278 +#: agenda_culturel/models.py:1298 msgid "la cour des 3 coquins" msgstr "la cour des 3 coquins" -#: agenda_culturel/models.py:1281 +#: agenda_culturel/models.py:1301 msgid "simple" msgstr "simple" -#: agenda_culturel/models.py:1282 +#: agenda_culturel/models.py:1302 msgid "Headless Chromium" msgstr "chromium sans interface" -#: agenda_culturel/models.py:1283 +#: agenda_culturel/models.py:1303 msgid "Headless Chromium (pause)" msgstr "chromium sans interface (pause)" -#: agenda_culturel/models.py:1288 +#: agenda_culturel/models.py:1308 msgid "daily" msgstr "chaque jour" -#: agenda_culturel/models.py:1290 +#: agenda_culturel/models.py:1310 msgid "weekly" msgstr "chaque semaine" -#: agenda_culturel/models.py:1295 +#: agenda_culturel/models.py:1315 msgid "" "Recurrent import name. Be careful to choose a name that is easy to " "understand, as it will be public and displayed on the sites About page." @@ -544,135 +560,135 @@ msgstr "" "Nom de l'import récurrent. Attention à choisir un nom compréhensible, car il " "sera public, et affiché sur la page à propos du site." -#: agenda_culturel/models.py:1302 +#: agenda_culturel/models.py:1322 msgid "Processor" msgstr "Processeur" -#: agenda_culturel/models.py:1305 +#: agenda_culturel/models.py:1325 msgid "Downloader" msgstr "Téléchargeur" -#: agenda_culturel/models.py:1312 +#: agenda_culturel/models.py:1332 msgid "Import recurrence" msgstr "Récurrence d'import" -#: agenda_culturel/models.py:1319 +#: agenda_culturel/models.py:1339 msgid "Source" msgstr "Source" -#: agenda_culturel/models.py:1320 +#: agenda_culturel/models.py:1340 msgid "URL of the source document" msgstr "URL du document source" -#: agenda_culturel/models.py:1324 +#: agenda_culturel/models.py:1344 msgid "Browsable url" msgstr "URL navigable" -#: agenda_culturel/models.py:1326 +#: agenda_culturel/models.py:1346 msgid "URL of the corresponding document that will be shown to visitors." msgstr "URL correspondant au document et qui sera montrée aux visiteurs" -#: agenda_culturel/models.py:1335 +#: agenda_culturel/models.py:1355 msgid "Status of each imported event (published or draft)" msgstr "Status de chaque événement importé (publié ou brouillon)" -#: agenda_culturel/models.py:1340 +#: agenda_culturel/models.py:1360 msgid "Address for each imported event" msgstr "Adresse de chaque événement importé" -#: agenda_culturel/models.py:1348 +#: agenda_culturel/models.py:1368 msgid "Category of each imported event" msgstr "Catégorie de chaque événement importé" -#: agenda_culturel/models.py:1354 +#: agenda_culturel/models.py:1374 msgid "Tags for each imported event" msgstr "Étiquettes de chaque événement importé" -#: agenda_culturel/models.py:1355 +#: agenda_culturel/models.py:1375 msgid "A list of tags that describe each imported event." msgstr "Une liste d'étiquettes décrivant chaque événement importé" -#: agenda_culturel/models.py:1381 +#: agenda_culturel/models.py:1401 msgid "Running" msgstr "En cours" -#: agenda_culturel/models.py:1382 +#: agenda_culturel/models.py:1402 msgid "Canceled" msgstr "Annulé" -#: agenda_culturel/models.py:1383 +#: agenda_culturel/models.py:1403 msgid "Success" msgstr "Succès" -#: agenda_culturel/models.py:1384 +#: agenda_culturel/models.py:1404 msgid "Failed" msgstr "Erreur" -#: agenda_culturel/models.py:1387 +#: agenda_culturel/models.py:1407 msgid "Batch importation" msgstr "Importation par lot" -#: agenda_culturel/models.py:1388 +#: agenda_culturel/models.py:1408 msgid "Batch importations" msgstr "Importations par lot" -#: agenda_culturel/models.py:1396 +#: agenda_culturel/models.py:1416 msgid "Reference to the recurrent import processing" msgstr "Référence du processus d'import récurrent" -#: agenda_culturel/models.py:1404 +#: agenda_culturel/models.py:1424 msgid "URL (if not recurrent import)" msgstr "URL (si pas d'import récurrent)" -#: agenda_culturel/models.py:1406 +#: agenda_culturel/models.py:1426 msgid "Source URL if no RecurrentImport is associated." msgstr "URL source si aucun import récurrent n'est associé" -#: agenda_culturel/models.py:1419 +#: agenda_culturel/models.py:1439 msgid "Error message" msgstr "Votre message" -#: agenda_culturel/models.py:1423 +#: agenda_culturel/models.py:1443 msgid "Number of collected events" msgstr "Nombre d'événements collectés" -#: agenda_culturel/models.py:1426 +#: agenda_culturel/models.py:1446 msgid "Number of imported events" msgstr "Nombre d'événements importés" -#: agenda_culturel/models.py:1429 +#: agenda_culturel/models.py:1449 msgid "Number of updated events" msgstr "Nombre d'événements mis à jour" -#: agenda_culturel/models.py:1432 +#: agenda_culturel/models.py:1452 msgid "Number of removed events" msgstr "Nombre d'événements supprimés" -#: agenda_culturel/models.py:1440 +#: agenda_culturel/models.py:1460 msgid "Weight" msgstr "Poids" -#: agenda_culturel/models.py:1441 +#: agenda_culturel/models.py:1461 msgid "The lower is the weight, the earlier the filter is applied" msgstr "Plus le poids est léger, plus le filtre sera appliqué tôt" -#: agenda_culturel/models.py:1448 +#: agenda_culturel/models.py:1468 msgid "Category applied to the event" msgstr "Catégorie appliquée à l'événement" -#: agenda_culturel/models.py:1453 +#: agenda_culturel/models.py:1473 msgid "Contained in the title" msgstr "Contenu dans le titre" -#: agenda_culturel/models.py:1454 +#: agenda_culturel/models.py:1474 msgid "Text contained in the event title" msgstr "Texte contenu dans le titre de l'événement" -#: agenda_culturel/models.py:1460 +#: agenda_culturel/models.py:1480 msgid "Exact title extract" msgstr "Extrait exact du titre" -#: agenda_culturel/models.py:1462 +#: agenda_culturel/models.py:1482 msgid "" "If checked, the extract will be searched for in the title using the exact " "form (capitals, accents)." @@ -680,19 +696,19 @@ msgstr "" "Si coché, l'extrait sera recherché dans le titre en utilisant la forme " "exacte (majuscules, accents)" -#: agenda_culturel/models.py:1468 +#: agenda_culturel/models.py:1488 msgid "Contained in the description" msgstr "Contenu dans la description" -#: agenda_culturel/models.py:1469 +#: agenda_culturel/models.py:1489 msgid "Text contained in the description" msgstr "Texte contenu dans la description" -#: agenda_culturel/models.py:1475 +#: agenda_culturel/models.py:1495 msgid "Exact description extract" msgstr "Extrait exact de description" -#: agenda_culturel/models.py:1477 +#: agenda_culturel/models.py:1497 msgid "" "If checked, the extract will be searched for in the description using the " "exact form (capitals, accents)." @@ -700,19 +716,19 @@ msgstr "" "Si coché, l'extrait sera recherché dans la description en utilisant la forme " "exacte (majuscules, accents)" -#: agenda_culturel/models.py:1483 +#: agenda_culturel/models.py:1503 msgid "Contained in the location" msgstr "Contenu dans la localisation" -#: agenda_culturel/models.py:1484 +#: agenda_culturel/models.py:1504 msgid "Text contained in the event location" msgstr "Texte contenu dans la localisation de l'événement" -#: agenda_culturel/models.py:1490 +#: agenda_culturel/models.py:1510 msgid "Exact location extract" msgstr "Extrait exact de localisation" -#: agenda_culturel/models.py:1492 +#: agenda_culturel/models.py:1512 msgid "" "If checked, the extract will be searched for in the location using the exact " "form (capitals, accents)." @@ -720,93 +736,93 @@ msgstr "" "Si coché, l'extrait sera recherché dans la localisation en utilisant la " "forme exacte (majuscules, accents)" -#: agenda_culturel/models.py:1500 +#: agenda_culturel/models.py:1520 msgid "Location from place" msgstr "Localisation depuis le lieu" -#: agenda_culturel/models.py:1507 +#: agenda_culturel/models.py:1527 msgid "Categorisation rule" msgstr "Règle de catégorisation" -#: agenda_culturel/models.py:1508 +#: agenda_culturel/models.py:1528 msgid "Categorisation rules" msgstr "Règles de catégorisation" -#: agenda_culturel/models.py:1575 agenda_culturel/models.py:1607 +#: agenda_culturel/models.py:1595 agenda_culturel/models.py:1627 msgid "Question" msgstr "Question" -#: agenda_culturel/models.py:1576 agenda_culturel/models.py:1614 +#: agenda_culturel/models.py:1596 agenda_culturel/models.py:1634 msgid "Text that will be shown to moderators" msgstr "Text tel que présenté aux modérateurices" -#: agenda_culturel/models.py:1582 +#: agenda_culturel/models.py:1602 msgid "Moderation question" msgstr "Question de modération" -#: agenda_culturel/models.py:1583 +#: agenda_culturel/models.py:1603 msgid "Moderation questions" msgstr "Questions de modération" -#: agenda_culturel/models.py:1608 +#: agenda_culturel/models.py:1628 msgid "Associated question from moderation" msgstr "Question associée pour la modération" -#: agenda_culturel/models.py:1613 +#: agenda_culturel/models.py:1633 msgid "Answer" msgstr "Réponse" -#: agenda_culturel/models.py:1620 +#: agenda_culturel/models.py:1640 msgid "Adds tags" msgstr "Ajoute les étiquettes" -#: agenda_culturel/models.py:1621 +#: agenda_culturel/models.py:1641 msgid "A list of tags that will be added if you choose this answer." msgstr "" "Une liste d'étiquettes qui seront ajoutées si vous choisissez cette réponse." -#: agenda_culturel/models.py:1627 +#: agenda_culturel/models.py:1647 msgid "Removes tags" msgstr "Retire les étiquettes" -#: agenda_culturel/models.py:1628 +#: agenda_culturel/models.py:1648 msgid "A list of tags that will be removed if you choose this answer." msgstr "" "Une liste d'étiquettes qui seront retirées si vous choisissez cette réponse." -#: agenda_culturel/settings/base.py:149 +#: agenda_culturel/settings/base.py:150 msgid "English" msgstr "anglais" -#: agenda_culturel/settings/base.py:150 +#: agenda_culturel/settings/base.py:151 msgid "French" msgstr "français" -#: agenda_culturel/views.py:132 +#: agenda_culturel/views.py:136 msgid "Recurrent import name" msgstr "Nome de l'import récurrent" -#: agenda_culturel/views.py:133 +#: agenda_culturel/views.py:137 msgid "Add another" msgstr "Ajouter un autre" -#: agenda_culturel/views.py:134 +#: agenda_culturel/views.py:138 msgid "Browse..." msgstr "Naviguer..." -#: agenda_culturel/views.py:135 +#: agenda_culturel/views.py:139 msgid "No file selected." msgstr "Pas de fichier sélectionné." -#: agenda_culturel/views.py:505 +#: agenda_culturel/views.py:533 msgid "The static content has been successfully updated." msgstr "Le contenu statique a été modifié avec succès." -#: agenda_culturel/views.py:514 agenda_culturel/views.py:562 +#: agenda_culturel/views.py:542 agenda_culturel/views.py:590 msgid "The event has been successfully modified." msgstr "L'événement a été modifié avec succès." -#: agenda_culturel/views.py:519 +#: agenda_culturel/views.py:547 msgid "" "Please note that this event has not been modified since it was last updated " "by import. If you modify any information from this import, the event will be " @@ -818,15 +834,15 @@ msgstr "" "l'événement sera désynchronisé d'avec la source, et nécessitera une fusion à " "chaque import automatique futurs." -#: agenda_culturel/views.py:531 +#: agenda_culturel/views.py:559 msgid "The event has been successfully deleted." msgstr "L'événement a été supprimé avec succès" -#: agenda_culturel/views.py:587 +#: agenda_culturel/views.py:615 msgid "The status has been successfully modified." msgstr "Le status a été modifié avec succès." -#: agenda_culturel/views.py:609 agenda_culturel/views.py:624 +#: agenda_culturel/views.py:637 agenda_culturel/views.py:657 msgid "" "The event has been submitted and will be published as soon as it has been " "validated by the moderation team." @@ -834,91 +850,91 @@ msgstr "" "L'événement a été soumis et sera publié dès qu'il aura été validé par " "l'équipe de modération." -#: agenda_culturel/views.py:618 +#: agenda_culturel/views.py:651 msgid "The event is saved." msgstr "L'événement est enregistré." -#: agenda_culturel/views.py:710 agenda_culturel/views.py:762 +#: agenda_culturel/views.py:743 agenda_culturel/views.py:795 msgid "{} has not been submitted since its already known: {}." msgstr "{} n'a pas été soumis car il est déjà connu: {}." -#: agenda_culturel/views.py:715 agenda_culturel/views.py:768 +#: agenda_culturel/views.py:748 agenda_culturel/views.py:801 msgid "" "{} has not been submitted since its already known and currently into " "moderation process." msgstr "{} n'a pas été soumis car il est déjà connu et en cours de modération" -#: agenda_culturel/views.py:725 +#: agenda_culturel/views.py:758 msgid "Integrating {} url(s) into our import process." msgstr "Intégration de {} url(s) dans notre processus d'import." -#: agenda_culturel/views.py:775 +#: agenda_culturel/views.py:808 msgid "Integrating {} into our import process." msgstr "Intégration de {} dans notre processus d'import." -#: agenda_culturel/views.py:838 +#: agenda_culturel/views.py:871 msgid "Your message has been sent successfully." msgstr "Votre message a été envoyé avec succès." -#: agenda_culturel/views.py:848 +#: agenda_culturel/views.py:881 msgid "The contact message has been successfully deleted." msgstr "Le message de contact a été supprimé avec succès." -#: agenda_culturel/views.py:862 +#: agenda_culturel/views.py:895 msgid "The contact message properties has been successfully modified." msgstr "Les propriétés du message de contact ont été modifié avec succès." -#: agenda_culturel/views.py:878 +#: agenda_culturel/views.py:911 msgid "Open" msgstr "Ouvert" -#: agenda_culturel/views.py:883 +#: agenda_culturel/views.py:916 msgid "Non spam" msgstr "Non spam" -#: agenda_culturel/views.py:946 +#: agenda_culturel/views.py:979 #, fuzzy #| msgid "The event has been successfully deleted." msgid "Spam has been successfully deleted." msgstr "L'événement a été supprimé avec succès" -#: agenda_culturel/views.py:963 +#: agenda_culturel/views.py:996 msgid "Search" msgstr "Rechercher" -#: agenda_culturel/views.py:1149 +#: agenda_culturel/views.py:1182 msgid "The import has been run successfully." msgstr "L'import a été lancé avec succès" -#: agenda_culturel/views.py:1168 +#: agenda_culturel/views.py:1201 msgid "The import has been canceled." msgstr "L'import a été annulé" -#: agenda_culturel/views.py:1242 +#: agenda_culturel/views.py:1275 msgid "The recurrent import has been successfully modified." msgstr "L'import récurrent a été modifié avec succès." -#: agenda_culturel/views.py:1251 +#: agenda_culturel/views.py:1284 msgid "The recurrent import has been successfully deleted." msgstr "L'import récurrent a été supprimé avec succès" -#: agenda_culturel/views.py:1291 +#: agenda_culturel/views.py:1324 msgid "The import has been launched." msgstr "L'import a été lancé" -#: agenda_culturel/views.py:1313 +#: agenda_culturel/views.py:1346 msgid "Imports has been launched." msgstr "Les imports ont été lancés" -#: agenda_culturel/views.py:1398 +#: agenda_culturel/views.py:1431 msgid "The merge has been successfully completed." msgstr "La fusion a été réalisée avec succès." -#: agenda_culturel/views.py:1432 +#: agenda_culturel/views.py:1465 msgid "Events have been marked as unduplicated." msgstr "Les événements ont été marqués comme non dupliqués." -#: agenda_culturel/views.py:1454 +#: agenda_culturel/views.py:1487 msgid "" "The selected event has been retained, while the other has been moved to the " "recycle bin." @@ -926,7 +942,7 @@ msgstr "" "L'événement sélectionné a été conservé, l'autre a été déplacé dans la " "corbeille." -#: agenda_culturel/views.py:1461 +#: agenda_culturel/views.py:1494 msgid "" "The selected event has been retained, while the others have been moved to " "the recycle bin." @@ -934,19 +950,19 @@ msgstr "" "L'événement sélectionné a été conservé, les autres ont été déplacés dans la " "corbeille." -#: agenda_culturel/views.py:1472 +#: agenda_culturel/views.py:1505 msgid "The event has been withdrawn from the group and made independent." msgstr "L'événement a été retiré du groupe et rendu indépendant." -#: agenda_culturel/views.py:1505 +#: agenda_culturel/views.py:1538 msgid "Cleaning up duplicates: {} item(s) removed." msgstr "Nettoyage des dupliqués: {} élément(s) supprimés." -#: agenda_culturel/views.py:1549 +#: agenda_culturel/views.py:1582 msgid "The event was successfully duplicated." msgstr "L'événement a été marqué dupliqué avec succès." -#: agenda_culturel/views.py:1557 +#: agenda_culturel/views.py:1590 msgid "" "The event has been successfully flagged as a duplicate. The moderation team " "will deal with your suggestion shortly." @@ -954,65 +970,68 @@ msgstr "" "L'événement a été signalé comme dupliqué avec succès. Votre suggestion sera " "prochainement prise en charge par l'équipe de modération." -#: agenda_culturel/views.py:1610 +#: agenda_culturel/views.py:1643 msgid "The categorisation rule has been successfully modified." msgstr "La règle de catégorisation a été modifiée avec succès." -#: agenda_culturel/views.py:1619 +#: agenda_culturel/views.py:1652 msgid "The categorisation rule has been successfully deleted." msgstr "La règle de catégorisation a été supprimée avec succès" -#: agenda_culturel/views.py:1641 agenda_culturel/views.py:1688 +#: agenda_culturel/views.py:1674 agenda_culturel/views.py:1721 msgid "The rules were successfully applied and 1 event was categorised." msgstr "" "Les règles ont été appliquées avec succès et 1 événement a été catégorisé" -#: agenda_culturel/views.py:1648 agenda_culturel/views.py:1695 +#: agenda_culturel/views.py:1681 agenda_culturel/views.py:1728 msgid "The rules were successfully applied and {} events were categorised." msgstr "" "Les règles ont été appliquées avec succès et {} événements ont été " "catégorisés" -#: agenda_culturel/views.py:1655 agenda_culturel/views.py:1702 +#: agenda_culturel/views.py:1688 agenda_culturel/views.py:1735 msgid "The rules were successfully applied and no events were categorised." msgstr "" "Les règles ont été appliquées avec succès et aucun événement n'a été " "catégorisé" -#: agenda_culturel/views.py:1742 +#: agenda_culturel/views.py:1775 msgid "The moderation question has been created with success." msgstr "La question de modération a été créée avec succès." -#: agenda_culturel/views.py:1868 agenda_culturel/views.py:1930 -#: agenda_culturel/views.py:1968 +#: agenda_culturel/views.py:1901 agenda_culturel/views.py:1963 +#: agenda_culturel/views.py:2001 msgid "{} events have been updated." msgstr "{} événements ont été mis à jour." -#: agenda_culturel/views.py:1871 agenda_culturel/views.py:1932 -#: agenda_culturel/views.py:1971 +#: agenda_culturel/views.py:1904 agenda_culturel/views.py:1965 +#: agenda_culturel/views.py:2004 msgid "1 event has been updated." msgstr "1 événement a été mis à jour" -#: agenda_culturel/views.py:1873 agenda_culturel/views.py:1934 -#: agenda_culturel/views.py:1973 +#: agenda_culturel/views.py:1906 agenda_culturel/views.py:1967 +#: agenda_culturel/views.py:2006 msgid "No events have been modified." msgstr "Aucun événement n'a été modifié." -#: agenda_culturel/views.py:1882 +#: agenda_culturel/views.py:1915 msgid "The place has been successfully updated." msgstr "Le lieu a été modifié avec succès." -#: agenda_culturel/views.py:1891 +#: agenda_culturel/views.py:1924 msgid "The place has been successfully created." msgstr "Le lieu a été créé avec succès." -#: agenda_culturel/views.py:1956 +#: agenda_culturel/views.py:1989 msgid "The selected place has been assigned to the event." msgstr "Le lieu sélectionné a été assigné à l'événement." -#: agenda_culturel/views.py:1960 +#: agenda_culturel/views.py:1993 msgid "A new alias has been added to the selected place." msgstr "Un nouvel alias a été créé pour le lieu sélectionné." +#~ msgid "Unknown" +#~ msgstr "Inconnue" + #~ msgid "This" #~ msgstr "Ce" diff --git a/src/agenda_culturel/migrations/0087_referencelocation.py b/src/agenda_culturel/migrations/0087_referencelocation.py new file mode 100644 index 0000000..85d47a5 --- /dev/null +++ b/src/agenda_culturel/migrations/0087_referencelocation.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.9 on 2024-10-16 12:55 + +import django.contrib.gis.geos.point +from django.db import migrations, models +import location_field.models.spatial + + +class Migration(migrations.Migration): + + dependencies = [ + ('agenda_culturel', '0086_alter_recurrentimport_processor'), + ] + + operations = [ + migrations.CreateModel( + name='ReferenceLocation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(help_text='Name of the location', verbose_name='Name')), + ('location', location_field.models.spatial.LocationField(default=django.contrib.gis.geos.point.Point(3.08333, 45.783329), srid=4326)), + ('main', models.BooleanField(default=False, help_text='This location is one of the main locations (shown first).', verbose_name='Main')), + ], + ), + ] diff --git a/src/agenda_culturel/migrations/0088_alter_referencelocation_options_and_more.py b/src/agenda_culturel/migrations/0088_alter_referencelocation_options_and_more.py new file mode 100644 index 0000000..2f78257 --- /dev/null +++ b/src/agenda_culturel/migrations/0088_alter_referencelocation_options_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.9 on 2024-10-16 18:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('agenda_culturel', '0087_referencelocation'), + ] + + operations = [ + migrations.AlterModelOptions( + name='referencelocation', + options={'verbose_name': 'Reference location', 'verbose_name_plural': 'Reference locations'}, + ), + migrations.AlterField( + model_name='referencelocation', + name='name', + field=models.CharField(help_text='Name of the location', unique=True, verbose_name='Name'), + ), + ] diff --git a/src/agenda_culturel/models.py b/src/agenda_culturel/models.py index 9189a33..1252678 100644 --- a/src/agenda_culturel/models.py +++ b/src/agenda_culturel/models.py @@ -236,6 +236,22 @@ class DuplicatedEvents(models.Model): s.delete() return nb +class ReferenceLocation(models.Model): + name = models.CharField(verbose_name=_("Name"), help_text=_("Name of the location"), unique=True, null=False) + location = LocationField(based_fields=["name"], zoom=12, default=Point(3.08333, 45.783329), srid=4326) + main = models.BooleanField( + verbose_name=_("Main"), + help_text=_("This location is one of the main locations (shown first)."), + default=False, + ) + + class Meta: + verbose_name = _("Reference location") + verbose_name_plural = _("Reference locations") + + def __str__(self): + return self.name + class Place(models.Model): name = models.CharField(verbose_name=_("Name"), help_text=_("Name of the place")) diff --git a/src/agenda_culturel/static/style.scss b/src/agenda_culturel/static/style.scss index ce218a8..6dc9243 100644 --- a/src/agenda_culturel/static/style.scss +++ b/src/agenda_culturel/static/style.scss @@ -137,7 +137,7 @@ details[role="list"] summary + ul li.selected>a:hover { margin-top: 0; } #filters .categories { - width: 75%; + width: 50%; float: left; text-align: left; line-height: 2em; @@ -152,6 +152,9 @@ details[role="list"] summary + ul li.selected>a:hover { padding: 0.2em 0.4em; } } + #filters details.active { + width: 50%; + } } @@ -855,6 +858,10 @@ form .buttons [role="button"] { .grid.two-columns.grid-reverse { grid-template-columns: 25% auto; } + .grid.two-columns-equal { + grid-column-gap: var(--nav-element-spacing-vertical); + grid-template-columns: 50% 50%; + } } diff --git a/src/agenda_culturel/templates/agenda_culturel/filter-inc.html b/src/agenda_culturel/templates/agenda_culturel/filter-inc.html index 2fd8837..a436e12 100644 --- a/src/agenda_culturel/templates/agenda_culturel/filter-inc.html +++ b/src/agenda_culturel/templates/agenda_culturel/filter-inc.html @@ -10,10 +10,10 @@ {% show_legend filter=filter %} -
+
{% if filter.is_active %} - Autres filtres : + Filtres : {% for t in filter.get_tags %} {{ t | tag_button }} {% endfor %} @@ -27,8 +27,9 @@ {{ c }} {% endfor %} {{ filter.get_recurrence_filtering }} + {{ filter.get_position_radius }} {% else %} - Autres filtres + Filtrer {% endif %} {% if filter.is_resetable %} @@ -37,7 +38,32 @@
- {{ filter.form.as_p }} +
+
+
Localisation
+ {% for f in filter.form.visible_fields %} + {% if f.id_for_label and f.id_for_label in "id_position,id_radius" %} +
+ {{ f.errors }} + {{ f.label_tag }} {{ f }} + {{ f.help_text }} +
+ {% endif %} + {% endfor %} +
+
+
Autres filtres
+ {% for f in filter.form.visible_fields %} + {% if not f.id_for_label or not f.id_for_label in "id_position,id_radius" %} +

+ {{ f.errors }} + {{ f.label_tag }} {{ f }} + {{ f.help_text }} +

+ {% endif %} + {% endfor %} +
+
diff --git a/src/agenda_culturel/views.py b/src/agenda_culturel/views.py index 330ac21..407680f 100644 --- a/src/agenda_culturel/views.py +++ b/src/agenda_culturel/views.py @@ -11,6 +11,9 @@ from django import forms from django.contrib.postgres.search import SearchQuery, SearchHeadline from django.utils.safestring import mark_safe +from django.contrib.gis.geos import Point +from django.contrib.gis.measure import D + from django.http import HttpResponseRedirect, HttpResponse from django.urls import reverse from collections import Counter @@ -48,6 +51,7 @@ from .models import ( ModerationQuestion, ModerationAnswer, Place, + ReferenceLocation ) from django.utils import timezone from django.utils.html import escape @@ -170,6 +174,18 @@ class EventFilter(django_filters.FilterSet): ("only_recurrent", "Montrer uniquement les événements récurrents"), ] + position = django_filters.ModelChoiceFilter( + label="À proximité de", + method="no_filter", + queryset=ReferenceLocation.objects.all().order_by("-main", "name__unaccent") + ) + + radius = django_filters.NumberFilter( + label="Distance maximum (km)", + method="no_filter", + widget=forms.NumberInput(attrs={"min": "1"}) + ) + exclude_tags = django_filters.MultipleChoiceFilter( label="Exclure les étiquettes", choices=[(t, t) for t in Event.get_all_tags()], @@ -180,7 +196,7 @@ class EventFilter(django_filters.FilterSet): ) tags = django_filters.MultipleChoiceFilter( - label="Filtrer par étiquettes", + label="Inclure les étiquettes", choices=[(t, t) for t in Event.get_all_tags()], lookup_expr="icontains", field_name="tags", @@ -188,7 +204,7 @@ class EventFilter(django_filters.FilterSet): ) recurrences = django_filters.ChoiceFilter( - label="Filtrer par récurrence", + label="Inclure la récurrence", choices=RECURRENT_CHOICES, method="filter_recurrences", ) @@ -201,12 +217,6 @@ class EventFilter(django_filters.FilterSet): widget=MultipleHiddenInput, ) - city = django_filters.MultipleChoiceFilter( - label="Filtrer par ville", - field_name="exact_location__city", - choices=[(c, c) for c in Place.get_all_cities()], - widget=forms.CheckboxSelectMultiple, - ) status = django_filters.MultipleChoiceFilter( label="Filtrer par status", @@ -217,7 +227,7 @@ class EventFilter(django_filters.FilterSet): class Meta: model = Event - fields = ["category", "city", "tags", "exclude_tags", "status", "recurrences"] + fields = ["category", "tags", "exclude_tags", "status", "recurrences"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -229,6 +239,18 @@ class EventFilter(django_filters.FilterSet): lookup = "__".join([name, "isnull"]) return queryset.filter(**{lookup: value == "remove_recurrent"}) + def no_filter(self, queryset, name, value): + return queryset + + @property + def qs(self): + parent = super().qs + if self.get_cleaned_data("position") is None or self.get_cleaned_data("radius") is None: + return parent + d = self.get_cleaned_data("radius") + p = self.get_cleaned_data("position").location + return parent.exclude(exact_location=False).filter(exact_location__location__distance_lt=(p, D(km=d))) + def get_url(self): if isinstance(self.form.data, QueryDict): return self.form.data.urlencode() @@ -296,12 +318,15 @@ class EventFilter(django_filters.FilterSet): def get_status(self): return self.get_cleaned_data("status") - def get_cities(self): - return self.get_cleaned_data("city") + def get_position(self): + return self.get_cleaned_data("position") + + def get_radius(self): + return self.get_cleaned_data("radius") def to_str(self, prefix=''): self.form.full_clean() - result = ' '.join([c.name for c in self.get_categories()] + [t for t in self.get_tags()] + [c for c in self.get_cities()]) + result = ' '.join([c.name for c in self.get_categories()] + [t for t in self.get_tags()] + [str(self.get_position()), str(self.get_radius())]) if len(result) > 0: result = prefix + result return result @@ -346,22 +371,19 @@ class EventFilter(django_filters.FilterSet): len(self.get_cleaned_data("tags")) != 0 or len(self.get_cleaned_data("exclude_tags")) != 0 or len(self.get_cleaned_data("recurrences")) != 0 - or len(self.get_cleaned_data("city")) != 0 + or ((not self.get_cleaned_data("position") is None) and (not self.get_cleaned_data("radius") is None)) ) def is_active(self, only_categories=False): if only_categories: return len(self.get_cleaned_data("category")) != 0 else: - if ( - len(self.get_cleaned_data("status")) != 0 - ): - return True return ( - len(self.get_cleaned_data("tags")) != 0 + len(self.get_cleaned_data("status")) != 0 + or len(self.get_cleaned_data("tags")) != 0 or len(self.get_cleaned_data("exclude_tags")) != 0 or len(self.get_cleaned_data("recurrences")) != 0 - or len(self.get_cleaned_data("city")) != 0 + or ((not self.get_cleaned_data("position") is None) and (not self.get_cleaned_data("radius") is None)) ) def is_selected(self, cat): @@ -376,6 +398,12 @@ class EventFilter(django_filters.FilterSet): return request return request + def get_position_radius(self): + if self.get_cleaned_data("position") is None or self.get_cleaned_data("radius") is None: + return "" + else: + return str(self.get_cleaned_data("position")) + ' (' + str(self.get_cleaned_data("radius")) + ' km)' + def mentions_legales(request): diff --git a/src/scripts/communes.json b/src/scripts/communes.json new file mode 100644 index 0000000..7bd12e1 --- /dev/null +++ b/src/scripts/communes.json @@ -0,0 +1,3259 @@ +[ + { + "com_name": "Apchat", + "geo_point_2d": { + "lon": 3.1474804148320086, + "lat": 45.37381114853485 + } + }, + { + "com_name": "Blanzat", + "geo_point_2d": { + "lon": 3.0734321992594693, + "lat": 45.827519889771104 + } + }, + { + "com_name": "La Bourboule", + "geo_point_2d": { + "lon": 2.7497632663819465, + "lat": 45.57962587936388 + } + }, + { + "com_name": "Brousse", + "geo_point_2d": { + "lon": 3.463733523523614, + "lat": 45.60017411607011 + } + }, + { + "com_name": "Chavaroux", + "geo_point_2d": { + "lon": 3.2586775182149337, + "lat": 45.8558933190783 + } + }, + { + "com_name": "Enval", + "geo_point_2d": { + "lon": 3.051687720048047, + "lat": 45.89718946580912 + } + }, + { + "com_name": "Fournols", + "geo_point_2d": { + "lon": 3.5895743175073824, + "lat": 45.52132562885522 + } + }, + { + "com_name": "Lachaux", + "geo_point_2d": { + "lon": 3.5943561036304854, + "lat": 45.992322334315176 + } + }, + { + "com_name": "Martres-sur-Morge", + "geo_point_2d": { + "lon": 3.219115152116495, + "lat": 45.93672377640076 + } + }, + { + "com_name": "Rochefort-Montagne", + "geo_point_2d": { + "lon": 2.8088746075068585, + "lat": 45.68210759983968 + } + }, + { + "com_name": "Saint-Gen\u00e8s-la-Tourette", + "geo_point_2d": { + "lon": 3.4809354768726046, + "lat": 45.517510677078036 + } + }, + { + "com_name": "Saint-Hilaire-la-Croix", + "geo_point_2d": { + "lon": 3.0452355074789126, + "lat": 46.039921269175544 + } + }, + { + "com_name": "Saint-Yvoine", + "geo_point_2d": { + "lon": 3.225868027347793, + "lat": 45.57501776275814 + } + }, + { + "com_name": "Sauvessanges", + "geo_point_2d": { + "lon": 3.8652476060006515, + "lat": 45.392634196715825 + } + }, + { + "com_name": "Thioli\u00e8res", + "geo_point_2d": { + "lon": 3.6933802259357367, + "lat": 45.58139724200495 + } + }, + { + "com_name": "Verneugheol", + "geo_point_2d": { + "lon": 2.520251679877813, + "lat": 45.75496387728297 + } + }, + { + "com_name": "Auzelles", + "geo_point_2d": { + "lon": 3.518595765420865, + "lat": 45.60692050509214 + } + }, + { + "com_name": "Beuri\u00e8res", + "geo_point_2d": { + "lon": 3.778994610714202, + "lat": 45.431530789234344 + } + }, + { + "com_name": "Antoingt", + "geo_point_2d": { + "lon": 3.184595722547293, + "lat": 45.50105854529884 + } + }, + { + "com_name": "Arlanc", + "geo_point_2d": { + "lon": 3.7229808394863393, + "lat": 45.42075953966001 + } + }, + { + "com_name": "Authezat", + "geo_point_2d": { + "lon": 3.1924514596104645, + "lat": 45.6386316736374 + } + }, + { + "com_name": "Bulhon", + "geo_point_2d": { + "lon": 3.391655320053028, + "lat": 45.88528915630852 + } + }, + { + "com_name": "Ceyssat", + "geo_point_2d": { + "lon": 2.9244854055179443, + "lat": 45.76989330164631 + } + }, + { + "com_name": "Champs", + "geo_point_2d": { + "lon": 3.0940285504635425, + "lat": 46.061431584851235 + } + }, + { + "com_name": "Charbonni\u00e8res-les-Vieilles", + "geo_point_2d": { + "lon": 3.0073321840693383, + "lat": 45.991528681806116 + } + }, + { + "com_name": "\u00c9gliseneuve-d'Entraigues", + "geo_point_2d": { + "lon": 2.8227863421580377, + "lat": 45.42133730793436 + } + }, + { + "com_name": "Espirat", + "geo_point_2d": { + "lon": 3.335365736166223, + "lat": 45.752797240849965 + } + }, + { + "com_name": "Jozerand", + "geo_point_2d": { + "lon": 3.098988097892878, + "lat": 46.02479636848371 + } + }, + { + "com_name": "Lapeyrouse", + "geo_point_2d": { + "lon": 2.8784597858246244, + "lat": 46.231766964406745 + } + }, + { + "com_name": "Laqueuille", + "geo_point_2d": { + "lon": 2.7460454863892636, + "lat": 45.65117566977608 + } + }, + { + "com_name": "La Monnerie-le-Montel", + "geo_point_2d": { + "lon": 3.611866440135882, + "lat": 45.873519262605534 + } + }, + { + "com_name": "Chambaron sur Morge", + "geo_point_2d": { + "lon": 3.1483150776829745, + "lat": 45.95413508255776 + } + }, + { + "com_name": "Orbeil", + "geo_point_2d": { + "lon": 3.2680554741506027, + "lat": 45.57154762061728 + } + }, + { + "com_name": "P\u00e9rignat-sur-Allier", + "geo_point_2d": { + "lon": 3.2347771499678304, + "lat": 45.72755638072832 + } + }, + { + "com_name": "Saint-Dier-d'Auvergne", + "geo_point_2d": { + "lon": 3.4821220185097035, + "lat": 45.67048823978804 + } + }, + { + "com_name": "Tauves", + "geo_point_2d": { + "lon": 2.6273920669507285, + "lat": 45.56359009808876 + } + }, + { + "com_name": "Viscomtat", + "geo_point_2d": { + "lon": 3.690172960581975, + "lat": 45.828699085575366 + } + }, + { + "com_name": "Artonne", + "geo_point_2d": { + "lon": 3.150738977028061, + "lat": 46.00586089706348 + } + }, + { + "com_name": "Bongheat", + "geo_point_2d": { + "lon": 3.426432502783181, + "lat": 45.724976836195765 + } + }, + { + "com_name": "Bort-l'\u00c9tang", + "geo_point_2d": { + "lon": 3.435657700709641, + "lat": 45.781602717988825 + } + }, + { + "com_name": "Chas", + "geo_point_2d": { + "lon": 3.3065866636107617, + "lat": 45.74727544036258 + } + }, + { + "com_name": "Clermont-Ferrand", + "main": true, + "geo_point_2d": { + "lon": 3.1153994509459313, + "lat": 45.78590931605406 + } + }, + { + "com_name": "Aulhat-Flat", + "geo_point_2d": { + "lon": 3.313177947891691, + "lat": 45.5738674751371 + } + }, + { + "com_name": "Malauzat", + "geo_point_2d": { + "lon": 3.0609346658090075, + "lat": 45.85972277248637 + } + }, + { + "com_name": "Les Martres-de-Veyre", + "geo_point_2d": { + "lon": 3.1999799920428207, + "lat": 45.68683823301241 + } + }, + { + "com_name": "Messeix", + "geo_point_2d": { + "lon": 2.533854153206075, + "lat": 45.61226674159499 + } + }, + { + "com_name": "Montpensier", + "geo_point_2d": { + "lon": 3.2265794615288854, + "lat": 46.03772032051342 + } + }, + { + "com_name": "Pouzol", + "geo_point_2d": { + "lon": 2.974156470450155, + "lat": 46.094874121300705 + } + }, + { + "com_name": "Riom", + "main": true, + "geo_point_2d": { + "lon": 3.13259085594027, + "lat": 45.89435053196184 + } + }, + { + "com_name": "Saint-Bonnet-le-Bourg", + "geo_point_2d": { + "lon": 3.5960722451558085, + "lat": 45.436842244338735 + } + }, + { + "com_name": "Saint-Jean-des-Olli\u00e8res", + "geo_point_2d": { + "lon": 3.4372258456289715, + "lat": 45.64161021401207 + } + }, + { + "com_name": "Solignat", + "geo_point_2d": { + "lon": 3.185044826964783, + "lat": 45.52343082517723 + } + }, + { + "com_name": "Tralaigues", + "geo_point_2d": { + "lon": 2.592764185068552, + "lat": 45.9017343316335 + } + }, + { + "com_name": "Le Vernet-Sainte-Marguerite", + "geo_point_2d": { + "lon": 2.938911290339094, + "lat": 45.61626095984027 + } + }, + { + "com_name": "Vodable", + "geo_point_2d": { + "lon": 3.134498816903619, + "lat": 45.50387217003881 + } + }, + { + "com_name": "Briffons", + "geo_point_2d": { + "lon": 2.6540138259904835, + "lat": 45.70068030158503 + } + }, + { + "com_name": "La Chapelle-Agnon", + "geo_point_2d": { + "lon": 3.6288558650465226, + "lat": 45.630080817604956 + } + }, + { + "com_name": "Cl\u00e9mensat", + "geo_point_2d": { + "lon": 3.105309813153393, + "lat": 45.56411970807651 + } + }, + { + "com_name": "La Forie", + "geo_point_2d": { + "lon": 3.753470358750935, + "lat": 45.58869249036867 + } + }, + { + "com_name": "Luzillat", + "geo_point_2d": { + "lon": 3.384979841423652, + "lat": 45.959040041306096 + } + }, + { + "com_name": "Moriat", + "geo_point_2d": { + "lon": 3.2592989492612463, + "lat": 45.40462162044676 + } + }, + { + "com_name": "Royat", + "geo_point_2d": { + "lon": 3.0403457521819957, + "lat": 45.75780004056534 + } + }, + { + "com_name": "Saint-Floret", + "geo_point_2d": { + "lon": 3.0940978777733843, + "lat": 45.53960516559085 + } + }, + { + "com_name": "Saint-Ignat", + "geo_point_2d": { + "lon": 3.2735316063816753, + "lat": 45.91998454234639 + } + }, + { + "com_name": "Saint-Romain", + "geo_point_2d": { + "lon": 3.8951998516244704, + "lat": 45.49255567466781 + } + }, + { + "com_name": "Sermentizon", + "geo_point_2d": { + "lon": 3.4860729510445094, + "lat": 45.76437680994485 + } + }, + { + "com_name": "Tr\u00e9mouille-Saint-Loup", + "geo_point_2d": { + "lon": 2.563214446671801, + "lat": 45.48582033156414 + } + }, + { + "com_name": "Le Vernet-Cham\u00e9ane", + "geo_point_2d": { + "lon": 3.4503758724033244, + "lat": 45.48832398083056 + } + }, + { + "com_name": "Vitrac", + "geo_point_2d": { + "lon": 2.895366482861551, + "lat": 45.97857161130726 + } + }, + { + "com_name": "Arconsat", + "geo_point_2d": { + "lon": 3.7165667634880477, + "lat": 45.89786439562639 + } + }, + { + "com_name": "Ars-les-Favets", + "geo_point_2d": { + "lon": 2.748577798601645, + "lat": 46.200238292335655 + } + }, + { + "com_name": "Aydat", + "geo_point_2d": { + "lon": 2.984326586256537, + "lat": 45.666617782915644 + } + }, + { + "com_name": "C\u00e9bazat", + "geo_point_2d": { + "lon": 3.1073339922236305, + "lat": 45.83212160453077 + } + }, + { + "com_name": "Chamali\u00e8res", + "main": true, + "geo_point_2d": { + "lon": 3.061838298868612, + "lat": 45.77475946884152 + } + }, + { + "com_name": "La Chapelle-Marcousse", + "geo_point_2d": { + "lon": 3.080964453230988, + "lat": 45.44177656406252 + } + }, + { + "com_name": "Effiat", + "geo_point_2d": { + "lon": 3.2687828999466673, + "lat": 46.04430443798744 + } + }, + { + "com_name": "Larodde", + "geo_point_2d": { + "lon": 2.5534305709061704, + "lat": 45.52469945479119 + } + }, + { + "com_name": "Lempty", + "geo_point_2d": { + "lon": 3.3293133661245693, + "lat": 45.829396081579105 + } + }, + { + "com_name": "Roche-Charles-la-Mayrand", + "geo_point_2d": { + "lon": 3.0198001972803397, + "lat": 45.44760591345817 + } + }, + { + "com_name": "Saint-Bonnet-pr\u00e8s-Riom", + "geo_point_2d": { + "lon": 3.11660774303076, + "lat": 45.928463856979995 + } + }, + { + "com_name": "Saint-Martin-des-Olmes", + "geo_point_2d": { + "lon": 3.803841039219326, + "lat": 45.52720099149879 + } + }, + { + "com_name": "Sauviat", + "geo_point_2d": { + "lon": 3.5570968556501725, + "lat": 45.71908332391171 + } + }, + { + "com_name": "Valbeleix", + "geo_point_2d": { + "lon": 2.9987440161181587, + "lat": 45.47436955089369 + } + }, + { + "com_name": "Valcivi\u00e8res", + "geo_point_2d": { + "lon": 3.820896368783431, + "lat": 45.60206767744897 + } + }, + { + "com_name": "Augnat", + "geo_point_2d": { + "lon": 3.179736995217094, + "lat": 45.41396939509897 + } + }, + { + "com_name": "Billom", + "geo_point_2d": { + "lon": 3.323969253468015, + "lat": 45.725080143675854 + } + }, + { + "com_name": "Brenat", + "geo_point_2d": { + "lon": 3.309699242625812, + "lat": 45.549665576382296 + } + }, + { + "com_name": "Combrailles", + "geo_point_2d": { + "lon": 2.640701354251028, + "lat": 45.84080985179006 + } + }, + { + "com_name": "Combronde", + "geo_point_2d": { + "lon": 3.0803374138388, + "lat": 45.985878225000754 + } + }, + { + "com_name": "Condat-l\u00e8s-Montboissier", + "geo_point_2d": { + "lon": 3.478274654421615, + "lat": 45.557250312792924 + } + }, + { + "com_name": "Courpi\u00e8re", + "geo_point_2d": { + "lon": 3.541483287751128, + "lat": 45.75842039468188 + } + }, + { + "com_name": "Espinasse", + "geo_point_2d": { + "lon": 2.710498820591308, + "lat": 46.03458236439827 + } + }, + { + "com_name": "Menat", + "geo_point_2d": { + "lon": 2.8949046491235735, + "lat": 46.11106778012594 + } + }, + { + "com_name": "Moissat", + "geo_point_2d": { + "lon": 3.351564070353416, + "lat": 45.77860612619066 + } + }, + { + "com_name": "Mont-Dore", + "geo_point_2d": { + "lon": 2.810031117004887, + "lat": 45.57568591843109 + } + }, + { + "com_name": "Montmorin", + "geo_point_2d": { + "lon": 3.358402373726642, + "lat": 45.69157587648629 + } + }, + { + "com_name": "Neuf-\u00c9glise", + "geo_point_2d": { + "lon": 2.8683364254831076, + "lat": 46.09806352382477 + } + }, + { + "com_name": "Palladuc", + "geo_point_2d": { + "lon": 3.642724005272892, + "lat": 45.908305397389476 + } + }, + { + "com_name": "Pionsat", + "geo_point_2d": { + "lon": 2.6850251803241285, + "lat": 46.11976857444729 + } + }, + { + "com_name": "Pulv\u00e9ri\u00e8res", + "geo_point_2d": { + "lon": 2.9229302560812727, + "lat": 45.88204027919822 + } + }, + { + "com_name": "Saint-Agoulin", + "geo_point_2d": { + "lon": 3.1290898651526518, + "lat": 46.04039297907939 + } + }, + { + "com_name": "Saint-Avit", + "geo_point_2d": { + "lon": 2.525583206682201, + "lat": 45.875866189426965 + } + }, + { + "com_name": "Saint-Ferr\u00e9ol-des-C\u00f4tes", + "geo_point_2d": { + "lon": 3.6974033145375618, + "lat": 45.53634369365399 + } + }, + { + "com_name": "Saint-Gen\u00e8s-du-Retz", + "geo_point_2d": { + "lon": 3.211359802413581, + "lat": 46.06316938470726 + } + }, + { + "com_name": "Saint-Maigner", + "geo_point_2d": { + "lon": 2.6865305797336183, + "lat": 46.078667145391016 + } + }, + { + "com_name": "Servant", + "geo_point_2d": { + "lon": 2.932001615437047, + "lat": 46.13844701615519 + } + }, + { + "com_name": "Seychalles", + "geo_point_2d": { + "lon": 3.336394336313523, + "lat": 45.80654285858718 + } + }, + { + "com_name": "Tallende", + "geo_point_2d": { + "lon": 3.1335753184103106, + "lat": 45.662026750977205 + } + }, + { + "com_name": "Vernines", + "geo_point_2d": { + "lon": 2.8773538883901275, + "lat": 45.66704834408379 + } + }, + { + "com_name": "Vertolaye", + "geo_point_2d": { + "lon": 3.738431212880943, + "lat": 45.653989359314856 + } + }, + { + "com_name": "Ch\u00e2teauneuf-les-Bains", + "geo_point_2d": { + "lon": 2.8869873503962804, + "lat": 46.025295059724556 + } + }, + { + "com_name": "Ch\u00e2teau-sur-Cher", + "geo_point_2d": { + "lon": 2.569116826161052, + "lat": 46.116543102833916 + } + }, + { + "com_name": "Coudes", + "geo_point_2d": { + "lon": 3.2022786389443287, + "lat": 45.61080865675239 + } + }, + { + "com_name": "Ferno\u00ebl", + "geo_point_2d": { + "lon": 2.422422010986228, + "lat": 45.81784072201071 + } + }, + { + "com_name": "Jumeaux", + "geo_point_2d": { + "lon": 3.3480983429360025, + "lat": 45.43449282332395 + } + }, + { + "com_name": "Montcel", + "geo_point_2d": { + "lon": 3.0636987422938495, + "lat": 46.01440168161059 + } + }, + { + "com_name": "Montel-de-Gelat", + "geo_point_2d": { + "lon": 2.5856533554220786, + "lat": 45.93905011694325 + } + }, + { + "com_name": "Orcet", + "geo_point_2d": { + "lon": 3.17379331605353, + "lat": 45.70540651495246 + } + }, + { + "com_name": "Parent", + "geo_point_2d": { + "lon": 3.2266852349252484, + "lat": 45.62381273674508 + } + }, + { + "com_name": "Peschadoires", + "geo_point_2d": { + "lon": 3.480519455703529, + "lat": 45.82681009514633 + } + }, + { + "com_name": "Saint-Donat", + "geo_point_2d": { + "lon": 2.704500384843015, + "lat": 45.46288796485278 + } + }, + { + "com_name": "Saint-Julien-la-Geneste", + "geo_point_2d": { + "lon": 2.741567476558839, + "lat": 46.04925708099318 + } + }, + { + "com_name": "Saint-Maurice", + "geo_point_2d": { + "lon": 3.2380576450979652, + "lat": 45.67047786905927 + } + }, + { + "com_name": "Beaumont", + "geo_point_2d": { + "lon": 3.0866880932311704, + "lat": 45.749738151310666 + } + }, + { + "com_name": "Celles-sur-Durolle", + "geo_point_2d": { + "lon": 3.651711507298715, + "lat": 45.872511984560184 + } + }, + { + "com_name": "Cisternes-la-For\u00eat", + "geo_point_2d": { + "lon": 2.7138312734012864, + "lat": 45.80816821842259 + } + }, + { + "com_name": "Giat", + "geo_point_2d": { + "lon": 2.476787484146231, + "lat": 45.79895559698386 + } + }, + { + "com_name": "Lezoux", + "geo_point_2d": { + "lon": 3.385973547042742, + "lat": 45.82916443569056 + } + }, + { + "com_name": "Maringues", + "geo_point_2d": { + "lon": 3.3390566746092523, + "lat": 45.92110660605403 + } + }, + { + "com_name": "Les Martres-d'Arti\u00e8re", + "geo_point_2d": { + "lon": 3.260401349848165, + "lat": 45.829961213636835 + } + }, + { + "com_name": "Perrier", + "geo_point_2d": { + "lon": 3.198580021779404, + "lat": 45.54511355350254 + } + }, + { + "com_name": "Puy-Guillaume", + "geo_point_2d": { + "lon": 3.4972316724463064, + "lat": 45.961301317295955 + } + }, + { + "com_name": "Puy-Saint-Gulmier", + "geo_point_2d": { + "lon": 2.6267885125597776, + "lat": 45.795084724756116 + } + }, + { + "com_name": "Saint-\u00c9tienne-sur-Usson", + "geo_point_2d": { + "lon": 3.401496202133548, + "lat": 45.50779208656532 + } + }, + { + "com_name": "Saint-Hilaire", + "geo_point_2d": { + "lon": 2.620185186904652, + "lat": 46.10574539819603 + } + }, + { + "com_name": "Saint-Julien-Puy-Lav\u00e8ze", + "geo_point_2d": { + "lon": 2.6798587035348533, + "lat": 45.662078281476624 + } + }, + { + "com_name": "Saint-Pierre-la-Bourlhonne", + "geo_point_2d": { + "lon": 3.7549260211687945, + "lat": 45.67727889272123 + } + }, + { + "com_name": "Sauvagnat", + "geo_point_2d": { + "lon": 2.6096721880355065, + "lat": 45.75519941315951 + } + }, + { + "com_name": "Ternant-les-Eaux", + "geo_point_2d": { + "lon": 3.128800945143262, + "lat": 45.48068741643206 + } + }, + { + "com_name": "Tourzel-Ronzi\u00e8res", + "geo_point_2d": { + "lon": 3.1182333042638626, + "lat": 45.52065923444672 + } + }, + { + "com_name": "Condat-en-Combraille", + "geo_point_2d": { + "lon": 2.565466501786973, + "lat": 45.86195858832052 + } + }, + { + "com_name": "Aubi\u00e8re", + "geo_point_2d": { + "lon": 3.125741432244928, + "lat": 45.75134193296833 + } + }, + { + "com_name": "Bansat", + "geo_point_2d": { + "lon": 3.3613933256211714, + "lat": 45.48300954756492 + } + }, + { + "com_name": "Besse-et-Saint-Anastaise", + "geo_point_2d": { + "lon": 2.9071201203747976, + "lat": 45.49688482939484 + } + }, + { + "com_name": "Bourg-Lastic", + "geo_point_2d": { + "lon": 2.563077111313249, + "lat": 45.657500285153574 + } + }, + { + "com_name": "Bromont-Lamothe", + "geo_point_2d": { + "lon": 2.810506680381358, + "lat": 45.832404834007924 + } + }, + { + "com_name": "Champ\u00e9ti\u00e8res", + "geo_point_2d": { + "lon": 3.67872888900543, + "lat": 45.51542880219681 + } + }, + { + "com_name": "La Chaulme", + "geo_point_2d": { + "lon": 3.957068323322477, + "lat": 45.47153133187368 + } + }, + { + "com_name": "Davayat", + "geo_point_2d": { + "lon": 3.1155008936681816, + "lat": 45.94695012369918 + } + }, + { + "com_name": "Joze", + "geo_point_2d": { + "lon": 3.304107016774923, + "lat": 45.86864732246823 + } + }, + { + "com_name": "Montpeyroux", + "geo_point_2d": { + "lon": 3.202942166487173, + "lat": 45.6253006769659 + } + }, + { + "com_name": "Mozac", + "geo_point_2d": { + "lon": 3.084769953106166, + "lat": 45.89235210600616 + } + }, + { + "com_name": "Prompsat", + "geo_point_2d": { + "lon": 3.0723774154203687, + "lat": 45.945089215616306 + } + }, + { + "com_name": "Roche-d'Agoux", + "geo_point_2d": { + "lon": 2.6408553930459613, + "lat": 46.04122559357906 + } + }, + { + "com_name": "Saint-Andr\u00e9-le-Coq", + "geo_point_2d": { + "lon": 3.3079378665657395, + "lat": 45.95790675693463 + } + }, + { + "com_name": "Saint-R\u00e9my-de-Chargnat", + "geo_point_2d": { + "lon": 3.3248354881436035, + "lat": 45.50943669645801 + } + }, + { + "com_name": "Saint-Sauves-d'Auvergne", + "geo_point_2d": { + "lon": 2.6928195108706734, + "lat": 45.61143880067948 + } + }, + { + "com_name": "Saulzet-le-Froid", + "geo_point_2d": { + "lon": 2.8919316063548486, + "lat": 45.63119834721808 + } + }, + { + "com_name": "Tortebesse", + "geo_point_2d": { + "lon": 2.65978300553278, + "lat": 45.727381891811135 + } + }, + { + "com_name": "Charbonnier-les-Mines", + "geo_point_2d": { + "lon": 3.2819518661127334, + "lat": 45.41832395961709 + } + }, + { + "com_name": "Lussat", + "geo_point_2d": { + "lon": 3.226500085346736, + "lat": 45.83826950303335 + } + }, + { + "com_name": "Olmet", + "geo_point_2d": { + "lon": 3.6638483439613685, + "lat": 45.71728141282788 + } + }, + { + "com_name": "Saint-Angel", + "geo_point_2d": { + "lon": 2.9394644008118163, + "lat": 46.001545128768875 + } + }, + { + "com_name": "Saint-Ours", + "geo_point_2d": { + "lon": 2.915065139946639, + "lat": 45.83935473456015 + } + }, + { + "com_name": "Saint-R\u00e9my-sur-Durolle", + "geo_point_2d": { + "lon": 3.584836376698309, + "lat": 45.89596557769968 + } + }, + { + "com_name": "Savennes", + "geo_point_2d": { + "lon": 2.4973734435605164, + "lat": 45.579717004868364 + } + }, + { + "com_name": "Teilh\u00e8de", + "geo_point_2d": { + "lon": 3.052790328564231, + "lat": 45.961418907373066 + } + }, + { + "com_name": "Varennes-sur-Morge", + "geo_point_2d": { + "lon": 3.1866317976730505, + "lat": 45.93995294677756 + } + }, + { + "com_name": "Yronde-et-Buron", + "geo_point_2d": { + "lon": 3.253354965348507, + "lat": 45.61027278860424 + } + }, + { + "com_name": "La Celle", + "geo_point_2d": { + "lon": 2.4742609038341685, + "lat": 45.84961000935222 + } + }, + { + "com_name": "Escoutoux", + "geo_point_2d": { + "lon": 3.5541359866259477, + "lat": 45.81568655216691 + } + }, + { + "com_name": "Job", + "geo_point_2d": { + "lon": 3.7627307259105875, + "lat": 45.62859968110441 + } + }, + { + "com_name": "Malintrat", + "geo_point_2d": { + "lon": 3.1911737630447923, + "lat": 45.81091717739705 + } + }, + { + "com_name": "Manglieu", + "geo_point_2d": { + "lon": 3.3564932316759215, + "lat": 45.612363643791404 + } + }, + { + "com_name": "Montaigut-le-Blanc", + "geo_point_2d": { + "lon": 3.079163092846616, + "lat": 45.5865140054144 + } + }, + { + "com_name": "Pontaumur", + "geo_point_2d": { + "lon": 2.6815145890801744, + "lat": 45.860516536912854 + } + }, + { + "com_name": "Sainte-Christine", + "geo_point_2d": { + "lon": 2.831175719596698, + "lat": 46.07237108005381 + } + }, + { + "com_name": "Saint-Georges-sur-Allier", + "geo_point_2d": { + "lon": 3.2612131139777896, + "lat": 45.71479154936235 + } + }, + { + "com_name": "Saint-Myon", + "geo_point_2d": { + "lon": 3.1292323827850463, + "lat": 45.987420215397755 + } + }, + { + "com_name": "Saint-Pierre-Colamine", + "geo_point_2d": { + "lon": 2.974852554533388, + "lat": 45.51464239308281 + } + }, + { + "com_name": "Saint-R\u00e9my-de-Blot", + "geo_point_2d": { + "lon": 2.9483055806078644, + "lat": 46.0778030283851 + } + }, + { + "com_name": "Sayat", + "geo_point_2d": { + "lon": 3.033731161723466, + "lat": 45.83916420220251 + } + }, + { + "com_name": "Augerolles", + "geo_point_2d": { + "lon": 3.6312624483806086, + "lat": 45.73694872146689 + } + }, + { + "com_name": "Cournols", + "geo_point_2d": { + "lon": 3.0371994547917196, + "lat": 45.6416745827187 + } + }, + { + "com_name": "Doranges", + "geo_point_2d": { + "lon": 3.6058975443856185, + "lat": 45.39953187447139 + } + }, + { + "com_name": "Landogne", + "geo_point_2d": { + "lon": 2.6486072824426516, + "lat": 45.8832715172038 + } + }, + { + "com_name": "Le Monestier", + "geo_point_2d": { + "lon": 3.652179869940221, + "lat": 45.55767026827795 + } + }, + { + "com_name": "Nonette-Orsonnette", + "geo_point_2d": { + "lon": 3.2886045937357076, + "lat": 45.480476395889056 + } + }, + { + "com_name": "Plauzat", + "geo_point_2d": { + "lon": 3.1480544770049006, + "lat": 45.62016307311142 + } + }, + { + "com_name": "Saint-Cirgues-sur-Couze", + "geo_point_2d": { + "lon": 3.1439217717580594, + "lat": 45.546575265642545 + } + }, + { + "com_name": "Saint-Denis-Combarnazat", + "geo_point_2d": { + "lon": 3.3481919830465516, + "lat": 45.975782034237575 + } + }, + { + "com_name": "Saint-Nectaire", + "geo_point_2d": { + "lon": 2.9975789951016076, + "lat": 45.591891478826504 + } + }, + { + "com_name": "Saint-Priest-Bramefant", + "geo_point_2d": { + "lon": 3.439620584591542, + "lat": 46.02868844270102 + } + }, + { + "com_name": "Sall\u00e8des", + "geo_point_2d": { + "lon": 3.3257613139733735, + "lat": 45.64628782030187 + } + }, + { + "com_name": "Valz-sous-Ch\u00e2teauneuf", + "geo_point_2d": { + "lon": 3.4217988933445507, + "lat": 45.43075006381825 + } + }, + { + "com_name": "Viverols", + "geo_point_2d": { + "lon": 3.8812232641526165, + "lat": 45.4324941717808 + } + }, + { + "com_name": "Beauregard-l'\u00c9v\u00eaque", + "geo_point_2d": { + "lon": 3.298525523489032, + "lat": 45.814261698045506 + } + }, + { + "com_name": "Cros", + "geo_point_2d": { + "lon": 2.6078502772908365, + "lat": 45.46667681522835 + } + }, + { + "com_name": "Domaize", + "geo_point_2d": { + "lon": 3.533462699661353, + "lat": 45.68670195982754 + } + }, + { + "com_name": "Limons", + "geo_point_2d": { + "lon": 3.4457514738988073, + "lat": 45.976107178895056 + } + }, + { + "com_name": "Mazoires", + "geo_point_2d": { + "lon": 3.0478097395977968, + "lat": 45.39500783045668 + } + }, + { + "com_name": "Moureuille", + "geo_point_2d": { + "lon": 2.8904596454257234, + "lat": 46.16254856337376 + } + }, + { + "com_name": "N\u00e9bouzat", + "geo_point_2d": { + "lon": 2.918286114427269, + "lat": 45.718193090755946 + } + }, + { + "com_name": "N\u00e9ronde-sur-Dore", + "geo_point_2d": { + "lon": 3.5073789930680443, + "lat": 45.79975941097085 + } + }, + { + "com_name": "Pignols", + "geo_point_2d": { + "lon": 3.285391411913401, + "lat": 45.64943039853655 + } + }, + { + "com_name": "Saint-Georges-de-Mons", + "geo_point_2d": { + "lon": 2.864422439085603, + "lat": 45.94273836512144 + } + }, + { + "com_name": "Saint-Priest-des-Champs", + "geo_point_2d": { + "lon": 2.748821044729957, + "lat": 45.971767020898646 + } + }, + { + "com_name": "Teilhet", + "geo_point_2d": { + "lon": 2.8166299424553705, + "lat": 46.10231231798727 + } + }, + { + "com_name": "Vensat", + "geo_point_2d": { + "lon": 3.166314698256003, + "lat": 46.054198435356675 + } + }, + { + "com_name": "Vollore-Ville", + "geo_point_2d": { + "lon": 3.611213942527748, + "lat": 45.78446567073912 + } + }, + { + "com_name": "Youx", + "geo_point_2d": { + "lon": 2.804016334234309, + "lat": 46.14059256555954 + } + }, + { + "com_name": "Blot-l'\u00c9glise", + "geo_point_2d": { + "lon": 2.958205280210276, + "lat": 46.03329886580416 + } + }, + { + "com_name": "Chapdes-Beaufort", + "geo_point_2d": { + "lon": 2.855748186127336, + "lat": 45.89278789123647 + } + }, + { + "com_name": "Crevant-Laveine", + "geo_point_2d": { + "lon": 3.4010953518893694, + "lat": 45.90243908734245 + } + }, + { + "com_name": "\u00c9gliseneuve-des-Liards", + "geo_point_2d": { + "lon": 3.420181653432267, + "lat": 45.56566309049351 + } + }, + { + "com_name": "\u00c9glisolles", + "geo_point_2d": { + "lon": 3.872001759583231, + "lat": 45.4676844898789 + } + }, + { + "com_name": "Grandeyrolles", + "geo_point_2d": { + "lon": 3.047342592577894, + "lat": 45.583153216394095 + } + }, + { + "com_name": "Laps", + "geo_point_2d": { + "lon": 3.2677593510816556, + "lat": 45.67103876977867 + } + }, + { + "com_name": "La Tour-d'Auvergne", + "geo_point_2d": { + "lon": 2.707440306366828, + "lat": 45.54417350942284 + } + }, + { + "com_name": "Miremont", + "geo_point_2d": { + "lon": 2.7175211712372938, + "lat": 45.9074637754203 + } + }, + { + "com_name": "Neuville", + "geo_point_2d": { + "lon": 3.442487551450841, + "lat": 45.751097415587445 + } + }, + { + "com_name": "Les Pradeaux", + "geo_point_2d": { + "lon": 3.291875980519577, + "lat": 45.51341880020081 + } + }, + { + "com_name": "Saint-Bonnet-le-Chastel", + "geo_point_2d": { + "lon": 3.637913826809165, + "lat": 45.46124812581844 + } + }, + { + "com_name": "Saint-Bonnet-l\u00e8s-Allier", + "geo_point_2d": { + "lon": 3.254837831422166, + "lat": 45.74000043356429 + } + }, + { + "com_name": "Saint-\u00c9tienne-des-Champs", + "geo_point_2d": { + "lon": 2.5790333592136574, + "lat": 45.816287337995995 + } + }, + { + "com_name": "Saint-Gervazy", + "geo_point_2d": { + "lon": 3.2130175118896074, + "lat": 45.4013832814843 + } + }, + { + "com_name": "Villeneuve", + "geo_point_2d": { + "lon": 3.1883806398245826, + "lat": 45.47828112477111 + } + }, + { + "com_name": "Le Broc", + "geo_point_2d": { + "lon": 3.251734407639125, + "lat": 45.50397217154974 + } + }, + { + "com_name": "Le Cendre", + "geo_point_2d": { + "lon": 3.1934106528026445, + "lat": 45.718009570641655 + } + }, + { + "com_name": "Chanonat", + "geo_point_2d": { + "lon": 3.0829978311839414, + "lat": 45.69531131522437 + } + }, + { + "com_name": "Chassagne", + "geo_point_2d": { + "lon": 3.0624950371012654, + "lat": 45.49326357206336 + } + }, + { + "com_name": "Courgoul", + "geo_point_2d": { + "lon": 3.046552311173715, + "lat": 45.51172617454689 + } + }, + { + "com_name": "Mazaye", + "geo_point_2d": { + "lon": 2.8744373668847585, + "lat": 45.78531982595174 + } + }, + { + "com_name": "P\u00e9rignat-l\u00e8s-Sarli\u00e8ve", + "geo_point_2d": { + "lon": 3.1431674543956443, + "lat": 45.73284238303546 + } + }, + { + "com_name": "Saint-Anth\u00e8me", + "geo_point_2d": { + "lon": 3.8967333424167845, + "lat": 45.55541027084116 + } + }, + { + "com_name": "Sauxillanges", + "geo_point_2d": { + "lon": 3.372584463698013, + "lat": 45.56312289438505 + } + }, + { + "com_name": "Voingt", + "geo_point_2d": { + "lon": 2.540951123410545, + "lat": 45.80619744630777 + } + }, + { + "com_name": "Aigueperse", + "geo_point_2d": { + "lon": 3.202062588812783, + "lat": 46.01432873968378 + } + }, + { + "com_name": "Ardes", + "geo_point_2d": { + "lon": 3.118435447073784, + "lat": 45.39874123530147 + } + }, + { + "com_name": "Chambon-sur-Lac", + "geo_point_2d": { + "lon": 2.869224237477639, + "lat": 45.56100653747931 + } + }, + { + "com_name": "Charbonni\u00e8res-les-Varennes", + "geo_point_2d": { + "lon": 2.979598075301741, + "lat": 45.898157053596144 + } + }, + { + "com_name": "Ch\u00e2teaugay", + "geo_point_2d": { + "lon": 3.0925746488337738, + "lat": 45.854180321007085 + } + }, + { + "com_name": "Ch\u00e2teldon", + "geo_point_2d": { + "lon": 3.5527093125452645, + "lat": 45.973645571004475 + } + }, + { + "com_name": "Ch\u00e2tel-Guyon", + "geo_point_2d": { + "lon": 3.0625146123646148, + "lat": 45.92073149951818 + } + }, + { + "com_name": "Chaumont-le-Bourg", + "geo_point_2d": { + "lon": 3.7657719768401363, + "lat": 45.45850017527477 + } + }, + { + "com_name": "Le Crest", + "geo_point_2d": { + "lon": 3.132817625803797, + "lat": 45.68910216524859 + } + }, + { + "com_name": "Fayet-Ronaye", + "geo_point_2d": { + "lon": 3.535659080363057, + "lat": 45.419115327014296 + } + }, + { + "com_name": "Marat", + "geo_point_2d": { + "lon": 3.6887047439184766, + "lat": 45.67330072222803 + } + }, + { + "com_name": "Murol", + "geo_point_2d": { + "lon": 2.9236131358187474, + "lat": 45.58639192572602 + } + }, + { + "com_name": "Pesli\u00e8res", + "geo_point_2d": { + "lon": 3.474194486340912, + "lat": 45.43780161338572 + } + }, + { + "com_name": "Saint-Alyre-\u00e8s-Montagne", + "geo_point_2d": { + "lon": 2.9725682953862274, + "lat": 45.37939108731595 + } + }, + { + "com_name": "Saint-Bonnet-pr\u00e8s-Orcival", + "geo_point_2d": { + "lon": 2.8639998849032113, + "lat": 45.708130788255744 + } + }, + { + "com_name": "Thuret", + "geo_point_2d": { + "lon": 3.261423906160596, + "lat": 45.97406894838942 + } + }, + { + "com_name": "Vertaizon", + "geo_point_2d": { + "lon": 3.2846631863847513, + "lat": 45.775425636217655 + } + }, + { + "com_name": "Virlet", + "geo_point_2d": { + "lon": 2.7023764715702248, + "lat": 46.154484958832924 + } + }, + { + "com_name": "Anzat-le-Luguet", + "geo_point_2d": { + "lon": 3.0121332649034867, + "lat": 45.33050244676841 + } + }, + { + "com_name": "Charnat", + "geo_point_2d": { + "lon": 3.4344148243186363, + "lat": 45.944850943276954 + } + }, + { + "com_name": "Espinchal", + "geo_point_2d": { + "lon": 2.8791510289515414, + "lat": 45.39495428760724 + } + }, + { + "com_name": "Mons", + "geo_point_2d": { + "lon": 3.422456501397914, + "lat": 46.00056499192279 + } + }, + { + "com_name": "Nohanent", + "geo_point_2d": { + "lon": 3.058123714238057, + "lat": 45.81111941014684 + } + }, + { + "com_name": "Olby", + "geo_point_2d": { + "lon": 2.8698405708367876, + "lat": 45.746070797295985 + } + }, + { + "com_name": "Parentignat", + "geo_point_2d": { + "lon": 3.285903256444427, + "lat": 45.53158992781121 + } + }, + { + "com_name": "Sainte-Agathe", + "geo_point_2d": { + "lon": 3.6223966513640575, + "lat": 45.821333344176935 + } + }, + { + "com_name": "Saint-Gal-sur-Sioule", + "geo_point_2d": { + "lon": 2.9940128315884427, + "lat": 46.108338769641804 + } + }, + { + "com_name": "Saint-Pierre-le-Chastel", + "geo_point_2d": { + "lon": 2.835450872739438, + "lat": 45.793241470424434 + } + }, + { + "com_name": "Saint-Sylvestre-Pragoulin", + "geo_point_2d": { + "lon": 3.395351902517566, + "lat": 46.04920217217785 + } + }, + { + "com_name": "Veyre-Monton", + "geo_point_2d": { + "lon": 3.1640734799294403, + "lat": 45.67323267928151 + } + }, + { + "com_name": "Champeix", + "geo_point_2d": { + "lon": 3.128027260302048, + "lat": 45.584762655702896 + } + }, + { + "com_name": "Ambert", + "main": true, + "geo_point_2d": { + "lon": 3.7568846508345506, + "lat": 45.55567832104365 + } + }, + { + "com_name": "Buss\u00e9ol", + "geo_point_2d": { + "lon": 3.2623249702659183, + "lat": 45.69330577747601 + } + }, + { + "com_name": "Bussi\u00e8res", + "geo_point_2d": { + "lon": 2.6474145679405012, + "lat": 46.064352917172826 + } + }, + { + "com_name": "Chanat-la-Mouteyre", + "geo_point_2d": { + "lon": 3.0062835144903004, + "lat": 45.82536940098116 + } + }, + { + "com_name": "Estandeuil", + "geo_point_2d": { + "lon": 3.444381688509755, + "lat": 45.68115843296875 + } + }, + { + "com_name": "Herment", + "geo_point_2d": { + "lon": 2.570392932309202, + "lat": 45.76364620563828 + } + }, + { + "com_name": "Isserteaux", + "geo_point_2d": { + "lon": 3.3813123362311592, + "lat": 45.65332964298481 + } + }, + { + "com_name": "Meilhaud", + "geo_point_2d": { + "lon": 3.1661585323457957, + "lat": 45.54337998893589 + } + }, + { + "com_name": "Perpezat", + "geo_point_2d": { + "lon": 2.7765238397611003, + "lat": 45.671625382844745 + } + }, + { + "com_name": "Pont-du-Ch\u00e2teau", + "main": true, + "geo_point_2d": { + "lon": 3.2398679745448864, + "lat": 45.79820943869307 + } + }, + { + "com_name": "Saint-Di\u00e9ry", + "geo_point_2d": { + "lon": 3.016368314084618, + "lat": 45.542893024238225 + } + }, + { + "com_name": "Saurier", + "geo_point_2d": { + "lon": 3.0559721798060613, + "lat": 45.535913517082854 + } + }, + { + "com_name": "Yssac-la-Tourette", + "geo_point_2d": { + "lon": 3.091499085566961, + "lat": 45.93422834919483 + } + }, + { + "com_name": "Aubusson-d'Auvergne", + "geo_point_2d": { + "lon": 3.5991881773440104, + "lat": 45.75334684270559 + } + }, + { + "com_name": "Baffie", + "geo_point_2d": { + "lon": 3.8283444092262875, + "lat": 45.47675454465279 + } + }, + { + "com_name": "Bergonne", + "geo_point_2d": { + "lon": 3.2172123232637615, + "lat": 45.50946479242657 + } + }, + { + "com_name": "Champagnat-le-Jeune", + "geo_point_2d": { + "lon": 3.416829437765207, + "lat": 45.44465382154983 + } + }, + { + "com_name": "Clerlande", + "geo_point_2d": { + "lon": 3.1902519248529266, + "lat": 45.91638779786377 + } + }, + { + "com_name": "Culhat", + "geo_point_2d": { + "lon": 3.344020049820272, + "lat": 45.86088138557284 + } + }, + { + "com_name": "Ennezat", + "geo_point_2d": { + "lon": 3.216255697233409, + "lat": 45.89540737661277 + } + }, + { + "com_name": "Issoire", + "main": true, + "geo_point_2d": { + "lon": 3.244722971565402, + "lat": 45.54551546108481 + } + }, + { + "com_name": "Loubeyrat", + "geo_point_2d": { + "lon": 3.006222335138361, + "lat": 45.93693233301613 + } + }, + { + "com_name": "Mirefleurs", + "geo_point_2d": { + "lon": 3.224679450956229, + "lat": 45.69098622583896 + } + }, + { + "com_name": "Novacelles", + "geo_point_2d": { + "lon": 3.6577124177086295, + "lat": 45.4296287241351 + } + }, + { + "com_name": "Orcines", + "geo_point_2d": { + "lon": 2.9969747055205014, + "lat": 45.787255836869406 + } + }, + { + "com_name": "Queuille", + "geo_point_2d": { + "lon": 2.837054446718383, + "lat": 45.97294018789502 + } + }, + { + "com_name": "Randan", + "geo_point_2d": { + "lon": 3.3634400789732237, + "lat": 46.011922210159454 + } + }, + { + "com_name": "Saillant", + "geo_point_2d": { + "lon": 3.9263330176739606, + "lat": 45.448757828917905 + } + }, + { + "com_name": "Saint-Cl\u00e9ment-de-Valorgue", + "geo_point_2d": { + "lon": 3.936471548142177, + "lat": 45.50045387083581 + } + }, + { + "com_name": "Saint-\u00c9loy-la-Glaci\u00e8re", + "geo_point_2d": { + "lon": 3.56790763442664, + "lat": 45.563582910478644 + } + }, + { + "com_name": "Saint-Germain-l'Herm", + "geo_point_2d": { + "lon": 3.544274000504837, + "lat": 45.46298654180578 + } + }, + { + "com_name": "Saint-Jean-d'Heurs", + "geo_point_2d": { + "lon": 3.4462343912949964, + "lat": 45.81512623872766 + } + }, + { + "com_name": "Saint-Laure", + "geo_point_2d": { + "lon": 3.2932300438455187, + "lat": 45.89773871775179 + } + }, + { + "com_name": "Saint-Sauveur-la-Sagne", + "geo_point_2d": { + "lon": 3.662991694943571, + "lat": 45.395155022052165 + } + }, + { + "com_name": "Sauvagnat-Sainte-Marthe", + "geo_point_2d": { + "lon": 3.208131730680432, + "lat": 45.58994722546103 + } + }, + { + "com_name": "Surat", + "geo_point_2d": { + "lon": 3.258951212077988, + "lat": 45.94030955956783 + } + }, + { + "com_name": "Bas-et-Lezat", + "geo_point_2d": { + "lon": 3.308472551855788, + "lat": 46.03697348954084 + } + }, + { + "com_name": "Bussi\u00e8res-et-Pruns", + "geo_point_2d": { + "lon": 3.2380705591738885, + "lat": 46.006642992887066 + } + }, + { + "com_name": "Ceyrat", + "geo_point_2d": { + "lon": 3.0649049012642573, + "lat": 45.738073993740535 + } + }, + { + "com_name": "Le Cheix", + "geo_point_2d": { + "lon": 3.1821943390206915, + "lat": 45.95728668576195 + } + }, + { + "com_name": "Collanges", + "geo_point_2d": { + "lon": 3.2152453291833267, + "lat": 45.43538828800324 + } + }, + { + "com_name": "Fayet-le-Ch\u00e2teau", + "geo_point_2d": { + "lon": 3.4099082712594164, + "lat": 45.679062831183636 + } + }, + { + "com_name": "Gimeaux", + "geo_point_2d": { + "lon": 3.0986575203633326, + "lat": 45.94910954193647 + } + }, + { + "com_name": "La Godivelle", + "geo_point_2d": { + "lon": 2.9176686918025445, + "lat": 45.38970100549755 + } + }, + { + "com_name": "Orcival", + "geo_point_2d": { + "lon": 2.838812837579917, + "lat": 45.65652767294931 + } + }, + { + "com_name": "Pasli\u00e8res", + "geo_point_2d": { + "lon": 3.5084520597339615, + "lat": 45.9233065386439 + } + }, + { + "com_name": "Picherande", + "geo_point_2d": { + "lon": 2.792473117876071, + "lat": 45.46966601461353 + } + }, + { + "com_name": "Prondines", + "geo_point_2d": { + "lon": 2.6837906688019584, + "lat": 45.759163863713525 + } + }, + { + "com_name": "Saint-Beauzire", + "geo_point_2d": { + "lon": 3.1844306281169077, + "lat": 45.85458894605646 + } + }, + { + "com_name": "Saint-Gervais-sous-Meymont", + "geo_point_2d": { + "lon": 3.61314789115372, + "lat": 45.670020908971274 + } + }, + { + "com_name": "Saint-Sandoux", + "geo_point_2d": { + "lon": 3.1083701529144863, + "lat": 45.63825735792241 + } + }, + { + "com_name": "Saint-Victor-la-Rivi\u00e8re", + "geo_point_2d": { + "lon": 2.9345205002039143, + "lat": 45.54871994371453 + } + }, + { + "com_name": "Vergheas", + "geo_point_2d": { + "lon": 2.622439506146564, + "lat": 46.024267587285685 + } + }, + { + "com_name": "Compains", + "geo_point_2d": { + "lon": 2.924115877824064, + "lat": 45.43642638579613 + } + }, + { + "com_name": "Cournon-d'Auvergne", + "main": true, + "geo_point_2d": { + "lon": 3.1863969000308425, + "lat": 45.74302062249931 + } + }, + { + "com_name": "Dorat", + "geo_point_2d": { + "lon": 3.4809875009817315, + "lat": 45.89538579518186 + } + }, + { + "com_name": "\u00c9gliseneuve-pr\u00e8s-Billom", + "geo_point_2d": { + "lon": 3.390119289399674, + "lat": 45.7162436875283 + } + }, + { + "com_name": "Mauzun", + "geo_point_2d": { + "lon": 3.4265047679023044, + "lat": 45.70450605789593 + } + }, + { + "com_name": "Noalhat", + "geo_point_2d": { + "lon": 3.462918800800963, + "lat": 45.91824825917803 + } + }, + { + "com_name": "Pessat-Villeneuve", + "geo_point_2d": { + "lon": 3.1584286332475044, + "lat": 45.92296619067177 + } + }, + { + "com_name": "Saint-Julien-de-Coppel", + "geo_point_2d": { + "lon": 3.311054763641114, + "lat": 45.69000596801847 + } + }, + { + "com_name": "Saint-Just", + "geo_point_2d": { + "lon": 3.80887569856948, + "lat": 45.458691707180684 + } + }, + { + "com_name": "Saint-Sulpice", + "geo_point_2d": { + "lon": 2.620014488974627, + "lat": 45.64663642015704 + } + }, + { + "com_name": "Auzat-la-Combelle", + "geo_point_2d": { + "lon": 3.3253511740320456, + "lat": 45.45070273652136 + } + }, + { + "com_name": "Bagnols", + "geo_point_2d": { + "lon": 2.6384187658300826, + "lat": 45.498210820939185 + } + }, + { + "com_name": "Charensat", + "geo_point_2d": { + "lon": 2.643808754342988, + "lat": 45.983593024879035 + } + }, + { + "com_name": "La Crouzille", + "geo_point_2d": { + "lon": 2.752513156237311, + "lat": 46.17182716003295 + } + }, + { + "com_name": "Cunlhat", + "geo_point_2d": { + "lon": 3.563015151121927, + "lat": 45.63009597630823 + } + }, + { + "com_name": "Gelles", + "geo_point_2d": { + "lon": 2.770582320804006, + "lat": 45.762215546682036 + } + }, + { + "com_name": "Gignat", + "geo_point_2d": { + "lon": 3.2190547020365172, + "lat": 45.486198257289416 + } + }, + { + "com_name": "Labessette", + "geo_point_2d": { + "lon": 2.535962007778934, + "lat": 45.49604296622665 + } + }, + { + "com_name": "Lamontgie", + "geo_point_2d": { + "lon": 3.3283688424671998, + "lat": 45.47471523577693 + } + }, + { + "com_name": "Marsac-en-Livradois", + "geo_point_2d": { + "lon": 3.7215981772804088, + "lat": 45.480333868245026 + } + }, + { + "com_name": "Saint-Maurice-pr\u00e8s-Pionsat", + "geo_point_2d": { + "lon": 2.592945546687132, + "lat": 46.06902828603198 + } + }, + { + "com_name": "Villossanges", + "geo_point_2d": { + "lon": 2.6451923466402096, + "lat": 45.918839523096196 + } + }, + { + "com_name": "Volvic", + "main": true, + "geo_point_2d": { + "lon": 3.018666916678083, + "lat": 45.86824389003399 + } + }, + { + "com_name": "Chabreloche", + "geo_point_2d": { + "lon": 3.6985190644293726, + "lat": 45.87145077329509 + } + }, + { + "com_name": "La Chapelle-sur-Usson", + "geo_point_2d": { + "lon": 3.392732978474967, + "lat": 45.463712803598106 + } + }, + { + "com_name": "Durtol", + "geo_point_2d": { + "lon": 3.050192439520055, + "lat": 45.79617509868806 + } + }, + { + "com_name": "Esteil", + "geo_point_2d": { + "lon": 3.3663355926735554, + "lat": 45.45308572849709 + } + }, + { + "com_name": "Glaine-Montaigut", + "geo_point_2d": { + "lon": 3.3861289401667793, + "lat": 45.7513098171588 + } + }, + { + "com_name": "Manzat", + "geo_point_2d": { + "lon": 2.9398061841689165, + "lat": 45.944677921583136 + } + }, + { + "com_name": "La Renaudie", + "geo_point_2d": { + "lon": 3.7095074192984465, + "lat": 45.74163953065324 + } + }, + { + "com_name": "Romagnat", + "geo_point_2d": { + "lon": 3.088277892957736, + "lat": 45.720765458256274 + } + }, + { + "com_name": "Saint-Saturnin", + "geo_point_2d": { + "lon": 3.074125512486369, + "lat": 45.66417351441827 + } + }, + { + "com_name": "Ceilloux", + "geo_point_2d": { + "lon": 3.516344939388757, + "lat": 45.65517311116584 + } + }, + { + "com_name": "\u00c9chandelys", + "geo_point_2d": { + "lon": 3.531953134844498, + "lat": 45.54638827039101 + } + }, + { + "com_name": "Mur-sur-Allier", + "geo_point_2d": { + "lon": 3.2394020474828142, + "lat": 45.75944088770279 + } + }, + { + "com_name": "Orl\u00e9at", + "geo_point_2d": { + "lon": 3.4387901245889827, + "lat": 45.859959399030046 + } + }, + { + "com_name": "Saint-Hilaire-les-Monges", + "geo_point_2d": { + "lon": 2.6651327719316815, + "lat": 45.80762225251758 + } + }, + { + "com_name": "Saint-Jean-en-Val", + "geo_point_2d": { + "lon": 3.364867019320609, + "lat": 45.51253559420274 + } + }, + { + "com_name": "Saint-Jean-Saint-Gervais", + "geo_point_2d": { + "lon": 3.3877021050311766, + "lat": 45.42135408134824 + } + }, + { + "com_name": "Saint-Pierre-Roche", + "geo_point_2d": { + "lon": 2.814300854104386, + "lat": 45.729267569960896 + } + }, + { + "com_name": "La Sauvetat", + "geo_point_2d": { + "lon": 3.1647627338120743, + "lat": 45.64264343930948 + } + }, + { + "com_name": "Thiers", + "main": true, + "geo_point_2d": { + "lon": 3.539565856379042, + "lat": 45.861856205367744 + } + }, + { + "com_name": "Aubiat", + "geo_point_2d": { + "lon": 3.192672797091027, + "lat": 45.980481738601284 + } + }, + { + "com_name": "Aulnat", + "geo_point_2d": { + "lon": 3.170797753058097, + "lat": 45.793080855648896 + } + }, + { + "com_name": "Beauregard-Vendon", + "geo_point_2d": { + "lon": 3.1134641338470423, + "lat": 45.965755764884086 + } + }, + { + "com_name": "Bouzel", + "geo_point_2d": { + "lon": 3.318414507096716, + "lat": 45.78062467794978 + } + }, + { + "com_name": "Aix-la-Fayette", + "geo_point_2d": { + "lon": 3.528727706766016, + "lat": 45.50712613888831 + } + }, + { + "com_name": "Les Ancizes-Comps", + "geo_point_2d": { + "lon": 2.805361390436619, + "lat": 45.93294332921972 + } + }, + { + "com_name": "Av\u00e8ze", + "geo_point_2d": { + "lon": 2.6060492948024563, + "lat": 45.59726544025061 + } + }, + { + "com_name": "Ayat-sur-Sioule", + "geo_point_2d": { + "lon": 2.886130673455308, + "lat": 46.0614929187274 + } + }, + { + "com_name": "Beaumont-l\u00e8s-Randan", + "geo_point_2d": { + "lon": 3.3836365501781103, + "lat": 45.99609744700276 + } + }, + { + "com_name": "Biollet", + "geo_point_2d": { + "lon": 2.69321817930053, + "lat": 45.992263918987625 + } + }, + { + "com_name": "Le Breuil-sur-Couze", + "geo_point_2d": { + "lon": 3.266989204088565, + "lat": 45.46696272658292 + } + }, + { + "com_name": "Chadeleuf", + "geo_point_2d": { + "lon": 3.1814118102505775, + "lat": 45.5816764235805 + } + }, + { + "com_name": "Chappes", + "geo_point_2d": { + "lon": 3.226534906398543, + "lat": 45.865167426613944 + } + }, + { + "com_name": "Entraigues", + "geo_point_2d": { + "lon": 3.2634859114156103, + "lat": 45.884209497663434 + } + }, + { + "com_name": "Goutti\u00e8res", + "geo_point_2d": { + "lon": 2.7754392362947926, + "lat": 46.06371482769322 + } + }, + { + "com_name": "Lempdes", + "geo_point_2d": { + "lon": 3.1928218556527783, + "lat": 45.772941538306064 + } + }, + { + "com_name": "Ludesse", + "geo_point_2d": { + "lon": 3.099501865398334, + "lat": 45.61595004791969 + } + }, + { + "com_name": "Marsat", + "geo_point_2d": { + "lon": 3.083552562624732, + "lat": 45.8735978932064 + } + }, + { + "com_name": "Medeyrolles", + "geo_point_2d": { + "lon": 3.818157961015175, + "lat": 45.407842289947446 + } + }, + { + "com_name": "Murat-le-Quaire", + "geo_point_2d": { + "lon": 2.7593819086380504, + "lat": 45.60391119442713 + } + }, + { + "com_name": "Neschers", + "geo_point_2d": { + "lon": 3.1651071723903454, + "lat": 45.592284882417964 + } + }, + { + "com_name": "Olloix", + "geo_point_2d": { + "lon": 3.050012008970118, + "lat": 45.622597104251234 + } + }, + { + "com_name": "Ravel", + "geo_point_2d": { + "lon": 3.3947584678691083, + "lat": 45.78734158428308 + } + }, + { + "com_name": "La Roche-Noire", + "geo_point_2d": { + "lon": 3.223516074660658, + "lat": 45.71366493299737 + } + }, + { + "com_name": "Sainte-Catherine", + "geo_point_2d": { + "lon": 3.4774201215651592, + "lat": 45.451071859483115 + } + }, + { + "com_name": "Saint-Flour-l'\u00c9tang", + "geo_point_2d": { + "lon": 3.509713502176409, + "lat": 45.71038690748676 + } + }, + { + "com_name": "Saint-Gen\u00e8s-Champespe", + "geo_point_2d": { + "lon": 2.725245643954161, + "lat": 45.4152782433435 + } + }, + { + "com_name": "Saint-Germain-Lembron", + "geo_point_2d": { + "lon": 3.243514313630847, + "lat": 45.4531553045484 + } + }, + { + "com_name": "Saint-Jacques-d'Ambur", + "geo_point_2d": { + "lon": 2.7660037563838746, + "lat": 45.896860903413945 + } + }, + { + "com_name": "Saint-Martin-des-Plains", + "geo_point_2d": { + "lon": 3.310845705799277, + "lat": 45.49504354947843 + } + }, + { + "com_name": "Singles", + "geo_point_2d": { + "lon": 2.552756231424953, + "lat": 45.56049295500694 + } + }, + { + "com_name": "Vichel", + "geo_point_2d": { + "lon": 3.2410202824042558, + "lat": 45.424152539285444 + } + }, + { + "com_name": "Vic-le-Comte", + "geo_point_2d": { + "lon": 3.2401611226494436, + "lat": 45.64421525934167 + } + }, + { + "com_name": "Vollore-Montagne", + "geo_point_2d": { + "lon": 3.6884577427727856, + "lat": 45.782916476820354 + } + }, + { + "com_name": "Chalus", + "geo_point_2d": { + "lon": 3.208726213346021, + "lat": 45.46456889532517 + } + }, + { + "com_name": "Chaptuzat", + "geo_point_2d": { + "lon": 3.1704980246184506, + "lat": 46.03020278414219 + } + }, + { + "com_name": "Chastreix", + "geo_point_2d": { + "lon": 2.753685170622438, + "lat": 45.51251572679104 + } + }, + { + "com_name": "Chidrac", + "geo_point_2d": { + "lon": 3.1507745386504844, + "lat": 45.55972187105067 + } + }, + { + "com_name": "Corent", + "geo_point_2d": { + "lon": 3.1926056553323314, + "lat": 45.66070476814951 + } + }, + { + "com_name": "Dore-l'\u00c9glise", + "geo_point_2d": { + "lon": 3.7571422661444203, + "lat": 45.377627258472614 + } + }, + { + "com_name": "La Goutelle", + "geo_point_2d": { + "lon": 2.7470709032983978, + "lat": 45.84450718247276 + } + }, + { + "com_name": "Grandrif", + "geo_point_2d": { + "lon": 3.8345902205925912, + "lat": 45.5203407323333 + } + }, + { + "com_name": "Heume-l'\u00c9glise", + "geo_point_2d": { + "lon": 2.7218666961521807, + "lat": 45.721015891632874 + } + }, + { + "com_name": "Lastic", + "geo_point_2d": { + "lon": 2.5702759311814334, + "lat": 45.70063608368587 + } + }, + { + "com_name": "Lisseuil", + "geo_point_2d": { + "lon": 2.935103287335729, + "lat": 46.05683911278468 + } + }, + { + "com_name": "M\u00e9n\u00e9trol", + "geo_point_2d": { + "lon": 3.1332056168388487, + "lat": 45.86165411758876 + } + }, + { + "com_name": "Montfermy", + "geo_point_2d": { + "lon": 2.7981822826475, + "lat": 45.87120846135747 + } + }, + { + "com_name": "Olliergues", + "geo_point_2d": { + "lon": 3.6358797213924183, + "lat": 45.690356975884 + } + }, + { + "com_name": "Reignat", + "geo_point_2d": { + "lon": 3.3570718231441967, + "lat": 45.74975625295314 + } + }, + { + "com_name": "Ris", + "geo_point_2d": { + "lon": 3.5129799688233154, + "lat": 46.004399161245246 + } + }, + { + "com_name": "La Roche-Blanche", + "geo_point_2d": { + "lon": 3.137287042943747, + "lat": 45.71349051048946 + } + }, + { + "com_name": "Saint-Amant-Tallende", + "geo_point_2d": { + "lon": 3.1096175903350316, + "lat": 45.66731602338749 + } + }, + { + "com_name": "Saint-\u00c9loy-les-Mines", + "geo_point_2d": { + "lon": 2.8424261412281644, + "lat": 46.163737755567524 + } + }, + { + "com_name": "Saint-Germain-pr\u00e8s-Herment", + "geo_point_2d": { + "lon": 2.553147509167706, + "lat": 45.7236885246214 + } + }, + { + "com_name": "Sauret-Besserve", + "geo_point_2d": { + "lon": 2.8025849948127877, + "lat": 45.98939930091068 + } + }, + { + "com_name": "Tr\u00e9zioux", + "geo_point_2d": { + "lon": 3.4727716582571175, + "lat": 45.71949276296685 + } + }, + { + "com_name": "Usson", + "geo_point_2d": { + "lon": 3.34234622274591, + "lat": 45.52741513272071 + } + }, + { + "com_name": "Vassel", + "geo_point_2d": { + "lon": 3.3122836754788643, + "lat": 45.76077194819151 + } + }, + { + "com_name": "Auri\u00e8res", + "geo_point_2d": { + "lon": 2.915833971432157, + "lat": 45.681620879472554 + } + }, + { + "com_name": "Beaulieu", + "geo_point_2d": { + "lon": 3.286577863106621, + "lat": 45.44342965821841 + } + }, + { + "com_name": "Brassac-les-Mines", + "geo_point_2d": { + "lon": 3.3212579683933323, + "lat": 45.41954388984752 + } + }, + { + "com_name": "Buxi\u00e8res-sous-Montaigut", + "geo_point_2d": { + "lon": 2.8366560438924298, + "lat": 46.2020605848385 + } + }, + { + "com_name": "La Cellette", + "geo_point_2d": { + "lon": 2.7263296982288323, + "lat": 46.09611127965248 + } + }, + { + "com_name": "Boudes", + "geo_point_2d": { + "lon": 3.183159309206807, + "lat": 45.45234709164083 + } + }, + { + "com_name": "Durmignat", + "geo_point_2d": { + "lon": 2.89333192168604, + "lat": 46.196853912771886 + } + }, + { + "com_name": "Grandval", + "geo_point_2d": { + "lon": 3.6506116426939386, + "lat": 45.59666729384686 + } + }, + { + "com_name": "Mareugheol", + "geo_point_2d": { + "lon": 3.1610775865409444, + "lat": 45.4838295664353 + } + }, + { + "com_name": "Montaigut-en-Combraille", + "geo_point_2d": { + "lon": 2.8009371289980693, + "lat": 46.18014727544682 + } + }, + { + "com_name": "Pardines", + "geo_point_2d": { + "lon": 3.1825104774394695, + "lat": 45.56248475321971 + } + }, + { + "com_name": "Pontgibaud", + "geo_point_2d": { + "lon": 2.853247050641699, + "lat": 45.82637634990919 + } + }, + { + "com_name": "Saint-Alyre-d'Arlanc", + "geo_point_2d": { + "lon": 3.6271034343156234, + "lat": 45.36749181348497 + } + }, + { + "com_name": "Saint-Babel", + "geo_point_2d": { + "lon": 3.300544497941931, + "lat": 45.60247379163185 + } + }, + { + "com_name": "Saint-Cl\u00e9ment-de-R\u00e9gnat", + "geo_point_2d": { + "lon": 3.2952399805885397, + "lat": 45.997988286812124 + } + }, + { + "com_name": "Saint-Gen\u00e8s-Champanelle", + "geo_point_2d": { + "lon": 2.999162382779412, + "lat": 45.72292521568951 + } + }, + { + "com_name": "Saint-H\u00e9rent", + "geo_point_2d": { + "lon": 3.1408528195246372, + "lat": 45.460054076593174 + } + }, + { + "com_name": "Saint-Quentin-sur-Sauxillanges", + "geo_point_2d": { + "lon": 3.4158935188967003, + "lat": 45.545244905539626 + } + }, + { + "com_name": "Sardon", + "geo_point_2d": { + "lon": 3.2223550150529077, + "lat": 45.9636321792011 + } + }, + { + "com_name": "Sug\u00e8res", + "geo_point_2d": { + "lon": 3.4120938066775004, + "lat": 45.60000263711813 + } + }, + { + "com_name": "Tours-sur-Meymont", + "geo_point_2d": { + "lon": 3.576441665748581, + "lat": 45.673406468273406 + } + }, + { + "com_name": "Varennes-sur-Usson", + "geo_point_2d": { + "lon": 3.323570943777543, + "lat": 45.53539505546282 + } + }, + { + "com_name": "Villeneuve-les-Cerfs", + "geo_point_2d": { + "lon": 3.329494934915236, + "lat": 46.0190135537847 + } + }, + { + "com_name": "Bertignat", + "geo_point_2d": { + "lon": 3.691036808978655, + "lat": 45.6174058800256 + } + }, + { + "com_name": "Le Brugeron", + "geo_point_2d": { + "lon": 3.7428275391975427, + "lat": 45.7121418654769 + } + }, + { + "com_name": "Chambon-sur-Dolore", + "geo_point_2d": { + "lon": 3.6250174795902703, + "lat": 45.49697323744115 + } + }, + { + "com_name": "Chauriat", + "geo_point_2d": { + "lon": 3.277588506071955, + "lat": 45.744037133808206 + } + }, + { + "com_name": "Dauzat-sur-Vodable", + "geo_point_2d": { + "lon": 3.082591005453441, + "lat": 45.47131856850418 + } + }, + { + "com_name": "Gerzat", + "geo_point_2d": { + "lon": 3.1540980432550967, + "lat": 45.828039221350345 + } + }, + { + "com_name": "Madriat", + "geo_point_2d": { + "lon": 3.1755185221452806, + "lat": 45.43553981700462 + } + }, + { + "com_name": "Marcillat", + "geo_point_2d": { + "lon": 3.034331449284435, + "lat": 46.07766345790317 + } + }, + { + "com_name": "Mayres", + "geo_point_2d": { + "lon": 3.6994589097610926, + "lat": 45.386321465683714 + } + }, + { + "com_name": "Le Quartier", + "geo_point_2d": { + "lon": 2.7608043509012057, + "lat": 46.12180496942844 + } + }, + { + "com_name": "Renti\u00e8res", + "geo_point_2d": { + "lon": 3.1202937157466204, + "lat": 45.42481999790067 + } + }, + { + "com_name": "Saint-Amant-Roche-Savine", + "geo_point_2d": { + "lon": 3.60801910028295, + "lat": 45.578264749562905 + } + }, + { + "com_name": "Saint-Gervais-d'Auvergne", + "geo_point_2d": { + "lon": 2.8313103539688145, + "lat": 46.018958697113874 + } + }, + { + "com_name": "Saint-Martin-d'Olli\u00e8res", + "geo_point_2d": { + "lon": 3.449360080164631, + "lat": 45.41722455133426 + } + }, + { + "com_name": "Saint-Pardoux", + "geo_point_2d": { + "lon": 3.0059107953348594, + "lat": 46.05487294301883 + } + }, + { + "com_name": "Saint-Quintin-sur-Sioule", + "geo_point_2d": { + "lon": 3.06951724611971, + "lat": 46.092520306484275 + } + }, + { + "com_name": "Saint-Victor-Montvianeix", + "geo_point_2d": { + "lon": 3.6115173029293937, + "lat": 45.938209890725005 + } + }, + { + "com_name": "Saint-Vincent", + "geo_point_2d": { + "lon": 3.1257812451294926, + "lat": 45.546978643799605 + } + }, + { + "com_name": "Verri\u00e8res", + "geo_point_2d": { + "lon": 3.0353599186029507, + "lat": 45.568200824365626 + } + }, + { + "com_name": "Vinzelles", + "geo_point_2d": { + "lon": 3.415096927114058, + "lat": 45.92787609417295 + } + } +] \ No newline at end of file diff --git a/src/scripts/create_reference_locations.py b/src/scripts/create_reference_locations.py new file mode 100644 index 0000000..8683580 --- /dev/null +++ b/src/scripts/create_reference_locations.py @@ -0,0 +1,17 @@ +import json, os + +from django.contrib.gis.geos import Point + +from agenda_culturel.models import ReferenceLocation + +def run(): + input_file = os.path.dirname(__file__) + os.path.sep + "communes.json" + data = [] + with open(input_file, 'r') as file: + data = json.load(file) + + objs = [ReferenceLocation(location=Point(c["geo_point_2d"]["lon"], c["geo_point_2d"]["lat"]), name=c["com_name"], main="main" in c) for c in data] + + objs = ReferenceLocation.objects.bulk_create(objs, ignore_conflicts=True) + +