feat(v2): streamline saved searches and favorites flows

This commit is contained in:
Alfredo Di Stasio
2026-03-13 14:40:38 +01:00
parent 0ed4fc57b8
commit 20d3ee7dae
6 changed files with 198 additions and 4 deletions

View File

@ -1,4 +1,8 @@
from django import forms
import json
from decimal import Decimal
from apps.players.forms import PlayerSearchForm
from .models import SavedSearch
@ -10,3 +14,61 @@ class SavedSearchForm(forms.ModelForm):
widgets = {
"name": forms.TextInput(attrs={"placeholder": "e.g. EuroLeague guards under 24"}),
}
class SavedSearchUpdateForm(forms.ModelForm):
filters_json = forms.CharField(
required=False,
label="Filters (JSON)",
widget=forms.Textarea(attrs={"rows": 8, "class": "font-mono"}),
help_text="Structured search filters payload. Leave blank to keep current filters.",
)
class Meta:
model = SavedSearch
fields = ["name", "is_public", "filters_json"]
widgets = {
"name": forms.TextInput(attrs={"placeholder": "e.g. Italian wings - updated"}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance and self.instance.pk and not self.initial.get("filters_json"):
self.initial["filters_json"] = json.dumps(self.instance.filters, indent=2, sort_keys=True)
def clean_filters_json(self):
raw = self.cleaned_data.get("filters_json")
if not raw:
return self.instance.filters
try:
parsed = json.loads(raw)
except json.JSONDecodeError as exc:
raise forms.ValidationError("Invalid JSON format.") from exc
if not isinstance(parsed, dict):
raise forms.ValidationError("Filters JSON must be an object.")
form = PlayerSearchForm(parsed)
if not form.is_valid():
raise forms.ValidationError("Filters JSON contains invalid search parameters.")
validated = {}
for key, value in form.cleaned_data.items():
if value in (None, ""):
continue
if hasattr(value, "pk"):
validated[key] = value.pk
elif isinstance(value, Decimal):
validated[key] = str(value)
else:
validated[key] = value
if not validated:
raise forms.ValidationError("Filters JSON does not contain valid searchable filters.")
return validated
def save(self, commit=True):
instance = super().save(commit=False)
instance.filters = self.cleaned_data["filters_json"]
if commit:
instance.save()
return instance

View File

@ -7,7 +7,7 @@ from django.utils import timezone
from django.views import View
from django.views.generic import ListView, TemplateView, UpdateView
from .forms import SavedSearchForm
from .forms import SavedSearchForm, SavedSearchUpdateForm
from .models import FavoritePlayer, SavedSearch
from .services.saved_searches import extract_filters_from_params, saved_search_to_querystring
@ -81,7 +81,7 @@ class SavedSearchCreateView(LoginRequiredMixin, View):
class SavedSearchUpdateView(LoginRequiredMixin, UpdateView):
model = SavedSearch
form_class = SavedSearchForm
form_class = SavedSearchUpdateForm
template_name = "scouting/saved_search_edit.html"
def get_queryset(self):
@ -96,6 +96,13 @@ class SavedSearchDeleteView(LoginRequiredMixin, View):
def post(self, request, pk, *args, **kwargs):
saved_search = get_object_or_404(SavedSearch, pk=pk, user=request.user)
saved_search.delete()
if request.headers.get("HX-Request") == "true":
saved_searches = SavedSearch.objects.filter(user=request.user).order_by("-updated_at")
return render(
request,
"scouting/partials/saved_search_table.html",
{"saved_searches": saved_searches},
)
messages.success(request, "Saved search deleted.")
return redirect("scouting:index")