Séparation des vues places

This commit is contained in:
SebF 2025-04-04 10:17:59 +02:00
parent 4183b7c764
commit 897d8c6ea9
4 changed files with 299 additions and 288 deletions

View File

@ -46,6 +46,18 @@ from .views import (
rename_tag,
delete_tag,
TagCreateView,
# Places
PlaceCreateView,
PlaceDeleteView,
PlaceDetailView,
PlaceDetailViewPast,
PlaceFromEventCreateView,
PlaceListAdminView,
PlaceListView,
PlaceUpdateView,
UnknownPlaceAddView,
UnknownPlacesListView,
fix_unknown_places,
# TODO pas encore trié
home,
week_view,
@ -56,16 +68,7 @@ from .views import (
recent,
administration,
activite,
PlaceDeleteView,
PlaceDetailView,
PlaceDetailViewPast,
PlaceUpdateView,
PlaceListView,
PlaceListAdminView,
UnknownPlaceAddView,
UnknownPlacesListView,
fix_duplicate,
fix_unknown_places,
clear_cache,
export_event_ical,
MessageDeleteView,
@ -93,8 +96,6 @@ from .views import (
event_search_full,
recurrent_imports,
delete_cm_spam,
PlaceCreateView,
PlaceFromEventCreateView,
update_from_source,
change_status_event,
EventDeleteView,
@ -229,6 +230,48 @@ urlpatterns = [
OrganisationUpdateView.as_view(),
name="edit_organisation",
),
# Places
path("places/add", PlaceCreateView.as_view(), name="add_place"),
path("place/<int:pk>/delete", PlaceDeleteView.as_view(), name="delete_place"),
path("place/<int:pk>", PlaceDetailView.as_view(), name="view_place"),
path(
"place/<int:pk>-<extra>",
PlaceDetailView.as_view(),
name="view_place_fullname",
),
path(
"place/<int:pk>/past",
PlaceDetailViewPast.as_view(),
name="view_place_past",
),
path(
"place/<int:pk>-<extra>/past",
PlaceDetailViewPast.as_view(),
name="view_place_past_fullname",
),
path(
"places/add/<int:pk>",
PlaceFromEventCreateView.as_view(),
name="add_place_from_event",
),
path("places/list", PlaceListAdminView.as_view(), name="view_places_admin"),
path("places/", PlaceListView.as_view(), name="view_places"),
path("place/<int:pk>/edit", PlaceUpdateView.as_view(), name="edit_place"),
path(
"event/<int:pk>/addplace",
UnknownPlaceAddView.as_view(),
name="add_place_to_event",
),
path(
"events/unknown-places",
UnknownPlacesListView.as_view(),
name="view_unknown_places",
),
path(
"events/unknown-places/fix",
fix_unknown_places,
name="fix_unknown_places",
),
# TODO pas encore trié
path("", home, name="home"),
path("cat:<cat>/", home, name="home_category"),
@ -432,48 +475,7 @@ urlpatterns = [
export_ical,
name="export_ical_organisation",
),
path(
"place/<int:pk>/past",
PlaceDetailViewPast.as_view(),
name="view_place_past",
),
path("place/<int:pk>", PlaceDetailView.as_view(), name="view_place"),
path("place/<int:place_pk>/ical", export_ical, name="export_ical_place"),
path(
"place/<int:pk>-<extra>/past",
PlaceDetailViewPast.as_view(),
name="view_place_past_fullname",
),
path(
"place/<int:pk>-<extra>",
PlaceDetailView.as_view(),
name="view_place_fullname",
),
path("place/<int:pk>/edit", PlaceUpdateView.as_view(), name="edit_place"),
path("place/<int:pk>/delete", PlaceDeleteView.as_view(), name="delete_place"),
path("places/", PlaceListView.as_view(), name="view_places"),
path("places/list", PlaceListAdminView.as_view(), name="view_places_admin"),
path("places/add", PlaceCreateView.as_view(), name="add_place"),
path(
"places/add/<int:pk>",
PlaceFromEventCreateView.as_view(),
name="add_place_from_event",
),
path(
"events/unknown-places",
UnknownPlacesListView.as_view(),
name="view_unknown_places",
),
path(
"events/unknown-places/fix",
fix_unknown_places,
name="fix_unknown_places",
),
path(
"event/<int:pk>/addplace",
UnknownPlaceAddView.as_view(),
name="add_place_to_event",
),
path(
"event/<int:year>/<int:month>/<int:day>/<int:pk>/ical",
export_event_ical,

View File

@ -3,4 +3,5 @@ from .errors import *
from .general_pages_views import *
from .moderation_views import *
from .organisations_views import *
from .places_views import *
from .tag_views import *

View File

@ -32,7 +32,7 @@ from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.timezone import datetime
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, ListView
from django.views.generic import DetailView
from django.views.generic.edit import (
CreateView,
DeleteView,
@ -66,14 +66,12 @@ from ..forms import (
BatchImportationForm,
CategorisationForm,
CategorisationRuleImportForm,
EventAddPlaceForm,
EventForm,
EventFormWithContact,
FixDuplicates,
MergeDuplicates,
MessageEventForm,
MessageForm,
PlaceForm,
RecurrentImportForm,
SelectEventInList,
SimpleContactForm,
@ -96,7 +94,6 @@ from ..models import (
remove_accents,
UserProfile,
)
from ..utils import PlaceGuesser
from .utils import get_event_qs
logger = logging.getLogger(__name__)
@ -2138,238 +2135,6 @@ def apply_categorisation_rules(request):
return HttpResponseRedirect(reverse_lazy("categorisation_rules"))
#########################
## Places
#########################
class PlaceListView(ListView):
model = Place
ordering = ["name__unaccent"]
class PlaceListAdminView(PermissionRequiredMixin, ListView):
model = Place
paginate_by = 10
permission_required = "agenda_culturel.add_place"
ordering = ["name__unaccent"]
template_name = "agenda_culturel/place_list_admin.html"
class PlaceDetailView(ListView):
model = Place
template_name = "agenda_culturel/place_detail.html"
paginate_by = 10
def get_queryset(self):
self.place = get_object_or_404(Place, pk=self.kwargs["pk"])
return (
get_event_qs(self.request)
.filter(exact_location=self.place)
.filter(
Q(other_versions__isnull=True)
| Q(other_versions__representative=F("pk"))
| Q(other_versions__representative__isnull=True)
)
.filter(start_day__gte=datetime.now())
.order_by("start_day")
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["object"] = self.place
return context
class PlaceDetailViewPast(PlaceDetailView):
def get_queryset(self):
self.place = get_object_or_404(Place, pk=self.kwargs["pk"])
self.past = True
return (
get_event_qs(self.request)
.filter(exact_location=self.place)
.filter(
Q(other_versions__isnull=True)
| Q(other_versions__representative=F("pk"))
| Q(other_versions__representative__isnull=True)
)
.filter(start_day__lte=datetime.now())
.order_by("-start_day")
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["past"] = self.past
return context
class UpdatePlaces:
def form_valid(self, form):
result = super().form_valid(form)
p = form.instance
if not hasattr(self, "nb_applied"):
self.nb_applied = 0
# if required, find all matching events
if form.apply():
self.nb_applied += p.associate_matching_events()
if self.nb_applied > 1:
messages.success(
self.request,
_("{} events have been updated.").format(self.nb_applied),
)
elif self.nb_applied == 1:
messages.success(self.request, _("1 event has been updated."))
else:
messages.info(self.request, _("No events have been modified."))
return result
class PlaceUpdateView(
UpdatePlaces, PermissionRequiredMixin, SuccessMessageMixin, UpdateView
):
model = Place
permission_required = "agenda_culturel.change_place"
success_message = _("The place has been successfully updated.")
form_class = PlaceForm
class PlaceCreateView(
UpdatePlaces, PermissionRequiredMixin, SuccessMessageMixin, CreateView
):
model = Place
permission_required = "agenda_culturel.add_place"
success_message = _("The place has been successfully created.")
form_class = PlaceForm
class PlaceDeleteView(PermissionRequiredMixin, DeleteView):
model = Place
permission_required = "agenda_culturel.delete_place"
success_url = reverse_lazy("view_places_admin")
class UnknownPlacesListView(PermissionRequiredMixin, ListView):
model = Event
permission_required = "agenda_culturel.add_place"
paginate_by = 10
ordering = ["-pk"]
template_name = "agenda_culturel/place_unknown_list.html"
queryset = Event.get_qs_events_with_unkwnon_place()
def fix_unknown_places(request):
# get all places
places = Place.objects.all()
# get all events without exact location
u_events = Event.get_qs_events_with_unkwnon_place()
to_be_updated = []
# try to find matches
for ue in u_events:
for p in places:
if p.match(ue):
ue.exact_location = p
to_be_updated.append(ue)
continue
# update events with a location
Event.objects.bulk_update(to_be_updated, fields=["exact_location"])
# create a success message
nb = len(to_be_updated)
if nb > 1:
messages.success(request, _("{} events have been updated.").format(nb))
elif nb == 1:
messages.success(request, _("1 event has been updated."))
else:
messages.info(request, _("No events have been modified."))
# come back to the list of places
return HttpResponseRedirect(reverse_lazy("view_unknown_places"))
class UnknownPlaceAddView(PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
model = Event
permission_required = (
"agenda_culturel.change_place",
"agenda_culturel.change_event",
)
form_class = EventAddPlaceForm
template_name = "agenda_culturel/place_unknown_form.html"
def form_valid(self, form):
self.modified_event = form.cleaned_data.get("place")
self.add_alias = form.cleaned_data.get("add_alias")
result = super().form_valid(form)
if form.cleaned_data.get("place"):
messages.success(
self.request,
_("The selected place has been assigned to the event."),
)
if form.cleaned_data.get("add_alias"):
messages.success(
self.request,
_("A new alias has been added to the selected place."),
)
nb_applied = form.cleaned_data.get("place").associate_matching_events()
if nb_applied > 1:
messages.success(
self.request,
_("{} events have been updated.").format(nb_applied),
)
elif nb_applied == 1:
messages.success(self.request, _("1 event has been updated."))
else:
messages.info(self.request, _("No events have been modified."))
return result
def get_success_url(self):
if self.modified_event:
return reverse_lazy("view_unknown_places")
else:
param = "?add=1" if self.add_alias else ""
return reverse_lazy("add_place_from_event", args=[self.object.pk]) + param
class PlaceFromEventCreateView(PlaceCreateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["event"] = self.event
return context
def get_initial(self, *args, **kwargs):
initial = super().get_initial(**kwargs)
self.event = get_object_or_404(Event, pk=self.kwargs["pk"])
if self.event.location and "add" in self.request.GET:
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["postcode"] = postcode
initial["city"] = city
initial["location"] = ""
return initial
def form_valid(self, form):
result = super().form_valid(form)
self.event.exact_location = form.instance
self.event.save(update_fields=["exact_location"])
return result
def get_success_url(self):
return self.event.get_absolute_url()
def statistics(request, pk=None):
if pk is not None:
rimport = RecurrentImport.objects.filter(pk=pk)

View File

@ -0,0 +1,243 @@
from datetime import datetime
from django.contrib import messages
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.db.models import F, Q
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import ListView, UpdateView, CreateView, DeleteView
from .utils import get_event_qs
from ..forms import PlaceForm, EventAddPlaceForm
from ..models import Place, Event
from ..utils import PlaceGuesser
class PlaceListView(ListView):
model = Place
ordering = ["name__unaccent"]
class PlaceListAdminView(PermissionRequiredMixin, ListView):
model = Place
paginate_by = 10
permission_required = "agenda_culturel.add_place"
ordering = ["name__unaccent"]
template_name = "agenda_culturel/place_list_admin.html"
class PlaceDetailView(ListView):
model = Place
template_name = "agenda_culturel/place_detail.html"
paginate_by = 10
def get_queryset(self):
self.place = get_object_or_404(Place, pk=self.kwargs["pk"])
return (
get_event_qs(self.request)
.filter(exact_location=self.place)
.filter(
Q(other_versions__isnull=True)
| Q(other_versions__representative=F("pk"))
| Q(other_versions__representative__isnull=True)
)
.filter(start_day__gte=datetime.now())
.order_by("start_day")
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["object"] = self.place
return context
class PlaceDetailViewPast(PlaceDetailView):
def get_queryset(self):
self.place = get_object_or_404(Place, pk=self.kwargs["pk"])
self.past = True
return (
get_event_qs(self.request)
.filter(exact_location=self.place)
.filter(
Q(other_versions__isnull=True)
| Q(other_versions__representative=F("pk"))
| Q(other_versions__representative__isnull=True)
)
.filter(start_day__lte=datetime.now())
.order_by("-start_day")
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["past"] = self.past
return context
class UpdatePlaces:
def form_valid(self, form):
result = super().form_valid(form)
p = form.instance
if not hasattr(self, "nb_applied"):
self.nb_applied = 0
# if required, find all matching events
if form.apply():
self.nb_applied += p.associate_matching_events()
if self.nb_applied > 1:
messages.success(
self.request,
_("{} events have been updated.").format(self.nb_applied),
)
elif self.nb_applied == 1:
messages.success(self.request, _("1 event has been updated."))
else:
messages.info(self.request, _("No events have been modified."))
return result
class PlaceUpdateView(
UpdatePlaces, PermissionRequiredMixin, SuccessMessageMixin, UpdateView
):
model = Place
permission_required = "agenda_culturel.change_place"
success_message = _("The place has been successfully updated.")
form_class = PlaceForm
class PlaceCreateView(
UpdatePlaces, PermissionRequiredMixin, SuccessMessageMixin, CreateView
):
model = Place
permission_required = "agenda_culturel.add_place"
success_message = _("The place has been successfully created.")
form_class = PlaceForm
class PlaceDeleteView(PermissionRequiredMixin, DeleteView):
model = Place
permission_required = "agenda_culturel.delete_place"
success_url = reverse_lazy("view_places_admin")
class UnknownPlacesListView(PermissionRequiredMixin, ListView):
model = Event
permission_required = "agenda_culturel.add_place"
paginate_by = 10
ordering = ["-pk"]
template_name = "agenda_culturel/place_unknown_list.html"
queryset = Event.get_qs_events_with_unkwnon_place()
def fix_unknown_places(request):
# get all places
places = Place.objects.all()
# get all events without exact location
u_events = Event.get_qs_events_with_unkwnon_place()
to_be_updated = []
# try to find matches
for ue in u_events:
for p in places:
if p.match(ue):
ue.exact_location = p
to_be_updated.append(ue)
continue
# update events with a location
Event.objects.bulk_update(to_be_updated, fields=["exact_location"])
# create a success message
nb = len(to_be_updated)
if nb > 1:
messages.success(request, _("{} events have been updated.").format(nb))
elif nb == 1:
messages.success(request, _("1 event has been updated."))
else:
messages.info(request, _("No events have been modified."))
# come back to the list of places
return HttpResponseRedirect(reverse_lazy("view_unknown_places"))
class UnknownPlaceAddView(PermissionRequiredMixin, SuccessMessageMixin, UpdateView):
model = Event
permission_required = (
"agenda_culturel.change_place",
"agenda_culturel.change_event",
)
form_class = EventAddPlaceForm
template_name = "agenda_culturel/place_unknown_form.html"
def form_valid(self, form):
self.modified_event = form.cleaned_data.get("place")
self.add_alias = form.cleaned_data.get("add_alias")
result = super().form_valid(form)
if form.cleaned_data.get("place"):
messages.success(
self.request,
_("The selected place has been assigned to the event."),
)
if form.cleaned_data.get("add_alias"):
messages.success(
self.request,
_("A new alias has been added to the selected place."),
)
nb_applied = form.cleaned_data.get("place").associate_matching_events()
if nb_applied > 1:
messages.success(
self.request,
_("{} events have been updated.").format(nb_applied),
)
elif nb_applied == 1:
messages.success(self.request, _("1 event has been updated."))
else:
messages.info(self.request, _("No events have been modified."))
return result
def get_success_url(self):
if self.modified_event:
return reverse_lazy("view_unknown_places")
else:
param = "?add=1" if self.add_alias else ""
return reverse_lazy("add_place_from_event", args=[self.object.pk]) + param
class PlaceFromEventCreateView(PlaceCreateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["event"] = self.event
return context
def get_initial(self, *args, **kwargs):
initial = super().get_initial(**kwargs)
self.event = get_object_or_404(Event, pk=self.kwargs["pk"])
if self.event.location and "add" in self.request.GET:
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["postcode"] = postcode
initial["city"] = city
initial["location"] = ""
return initial
def form_valid(self, form):
result = super().form_valid(form)
self.event.exact_location = form.instance
self.event.save(update_fields=["exact_location"])
return result
def get_success_url(self):
return self.event.get_absolute_url()