Suggestions pour les champs d'un nouveau lieu

Voir #231
This commit is contained in:
Jean-Marie Favreau 2024-12-06 18:10:11 +01:00
parent 27ceac1e46
commit 91907be984
4 changed files with 139 additions and 4 deletions

View File

@ -16,6 +16,7 @@ from django.forms import (
) )
from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget from django_better_admin_arrayfield.forms.widgets import DynamicArrayWidget
from .utils import PlaceGuesser
from .models import ( from .models import (
Event, Event,
RecurrentImport, RecurrentImport,
@ -741,13 +742,17 @@ class PlaceForm(ModelForm):
fields = "__all__" fields = "__all__"
widgets = {"location": TextInput()} widgets = {"location": TextInput()}
def __init__(self, *args, **kwargs):
self.force_adjust = kwargs.pop("force_adjust", None)
super().__init__(*args, **kwargs)
def as_grid(self): def as_grid(self):
return mark_safe( result = ('<div class="grid"><div>'
'<div class="grid"><div>'
+ super().as_p() + super().as_p()
+ '</div><div><div class="map-widget">' + '</div><div><div class="map-widget">'
+ '<div id="map_location" style="width: 100%; aspect-ratio: 16/9"></div><p>Cliquez pour ajuster la position GPS</p></div></div></div>' + '<div id="map_location" style="width: 100%; aspect-ratio: 16/9"></div><p>Cliquez pour ajuster la position GPS</p></div></div></div>')
)
return mark_safe(result)
def apply(self): def apply(self):
return self.cleaned_data.get("apply_to_all") return self.cleaned_data.get("apply_to_all")

View File

@ -22,6 +22,7 @@
<article> <article>
{% if event %} {% if event %}
<p>Création d'un lieu depuis l'événement « {{ event }} » (voir en bas de page le détail de l'événement).</p> <p>Création d'un lieu depuis l'événement « {{ event }} » (voir en bas de page le détail de l'événement).</p>
<p><strong>Remarque&nbsp;:</strong> les champs ont été pré-remplis à partir de la description sous forme libre et n'est probablement pas parfaite.</p>
{% endif %} {% endif %}
<form method="post">{% csrf_token %} <form method="post">{% csrf_token %}
{{ form.as_grid }} {{ form.as_grid }}

View File

@ -0,0 +1,114 @@
from agenda_culturel.models import ReferenceLocation
import re
import unicodedata
class PlaceGuesser:
def __init__(self):
self.__citynames = list(ReferenceLocation.objects.values_list("name__lower__unaccent", "name")) + [("clermont-fd", "Clermont-Ferrand"), ("aurillac", "Aurillac"), ("montlucon", "Montluçon"), ("montferrand", "Clermont-Ferrand")]
self.__citynames = [(x[0].replace("-", " "), x[1]) for x in self.__citynames]
def __remove_accents(self, input_str):
if input_str is None:
return None
nfkd_form = unicodedata.normalize("NFKD", input_str)
return "".join([c for c in nfkd_form if not unicodedata.combining(c)])
def __guess_is_address(self, part):
toponyms = ["bd", "rue", "avenue", "place", "boulevard", "allee", ]
part = part.strip()
if re.match(r'^[0-9]', part):
return True
elems = part.split(" ")
return any([self.__remove_accents(e.lower()) in toponyms for e in elems])
def __clean_address(self, addr):
toponyms = ["bd", "rue", "avenue", "place", "boulevard", "allée", "bis", "ter", "ZI"]
for t in toponyms:
addr = re.sub(" " + t + " ", " " + t + " ", addr, flags=re.IGNORECASE)
return addr
def __guess_city_name(self, part):
part = part.strip().replace(" - ", "-")
if len(part) == 0:
return None
part = self.__remove_accents(part.lower()).replace("-", " ")
match = [x[1] for x in self.__citynames if x[0] == part]
if len(match) > 0:
return match[0]
else:
return None
def __guess_city_name_postcode(self, part):
with_pc = re.search(r'^(.*)(([0-9][ ]*){5})(.*)$', part)
if with_pc:
p1 = self.__guess_city_name(with_pc.group(1).strip())
postcode = with_pc.group(2).replace(" ", "")
p2 = self.__guess_city_name(with_pc.group(4).strip())
return postcode, p2, p1
else:
return None, self.__guess_city_name(part), None
def __guess_name_address(self, part):
with_num = re.search(r'^(([^0-9])+)([0-9]+)(.*)', part)
if with_num:
name = with_num.group(1)
return name, part[len(name):]
else:
return "", part
def guess_address_elements(self, alias):
parts = re.split(r'[,/à]', alias)
parts = [p1 for p1 in [p.strip() for p in parts] if p1 != "" and p1.lower() != "france"]
name = ""
address = ""
postcode = ""
city = ""
possible_city = ""
oparts = []
for part in parts:
p, c, possible_c = self.__guess_city_name_postcode(part)
if not possible_c is None:
possible_city = possible_c
if not c is None and city == "":
city = c
if not p is None and postcode == "":
postcode = p
if p is None and c is None:
oparts.append(part)
if city == "" and possible_city != "":
city = possible_city
else:
if len(oparts) == 0 and not possible_city != "":
oparts = [possible_city]
if city == "":
alias_simple = self.__remove_accents(alias.lower()).replace("-", " ")
mc = [x[1] for x in self.__citynames if alias_simple.endswith(" " + x[0])]
if len(mc) == 1:
city = mc[0]
if len(oparts) > 0:
if not self.__guess_is_address(oparts[0]):
name = oparts[0]
address = ", ".join(oparts[1:])
else:
name, address = self.__guess_name_address(", ".join(oparts))
address = self.__clean_address(address)
if name == "" and possible_city != "" and possible_city != city:
name = possible_city
return name, address, postcode, city

View File

@ -12,6 +12,7 @@ from django.contrib.postgres.search import SearchQuery, SearchHeadline
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from honeypot.decorators import check_honeypot from honeypot.decorators import check_honeypot
from .utils import PlaceGuesser
from django.contrib.gis.geos import Point from django.contrib.gis.geos import Point
@ -1864,16 +1865,30 @@ class UnknownPlaceAddView(PermissionRequiredMixin, SuccessMessageMixin, UpdateVi
class PlaceFromEventCreateView(PlaceCreateView): class PlaceFromEventCreateView(PlaceCreateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context["event"] = self.event context["event"] = self.event
return context return context
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
if self.event.location and "add" in self.request.GET:
kwargs["force_adjust"] = True
return kwargs
def get_initial(self, *args, **kwargs): def get_initial(self, *args, **kwargs):
initial = super().get_initial(**kwargs) initial = super().get_initial(**kwargs)
self.event = get_object_or_404(Event, pk=self.kwargs["pk"]) self.event = get_object_or_404(Event, pk=self.kwargs["pk"])
if self.event.location and "add" in self.request.GET: if self.event.location and "add" in self.request.GET:
initial["aliases"] = [self.event.location] initial["aliases"] = [self.event.location]
guesser = PlaceGuesser()
name, address, postcode, city = guesser.guess_address_elements(self.event.location)
initial["name"] = name
initial["address"] = address
initial["city"] = city
return initial return initial
def form_valid(self, form): def form_valid(self, form):