From 1cabae10e86acc7eeac5ab5bd3eb15adcb996d0a Mon Sep 17 00:00:00 2001 From: Jannis Portmann Date: Sat, 15 Apr 2023 13:16:40 +0200 Subject: [PATCH] Filter offers --- pflaenzli/pflaenzli/forms.py | 10 +++++++ .../pflaenzli/templates/offer/search.html | 23 ++++++++++++++-- pflaenzli/pflaenzli/utils/distance.py | 12 ++++++++- pflaenzli/pflaenzli/views.py | 27 ++++++++++++++++--- 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/pflaenzli/pflaenzli/forms.py b/pflaenzli/pflaenzli/forms.py index 7e898c7..e334684 100644 --- a/pflaenzli/pflaenzli/forms.py +++ b/pflaenzli/pflaenzli/forms.py @@ -1,5 +1,6 @@ from django import forms from django.contrib.auth.forms import UserCreationForm +from django.utils.safestring import mark_safe from friendly_captcha.fields import FrcCaptchaField from .models import Offer, PflaenzliUser @@ -17,3 +18,12 @@ class RegistrationForm(UserCreationForm): fields = UserCreationForm.Meta.fields + ('email', 'zipcode',) captcha = FrcCaptchaField() + + +class FilterForm(forms.Form): + text = forms.CharField(max_length=128, required=False, label=mark_safe( + ' Search')) + zipcode = forms.CharField(max_length=4, required=False, label=mark_safe( + ' Zipcode')) + distance = forms.IntegerField(required=False, label=mark_safe( + ' Distance (km)')) diff --git a/pflaenzli/pflaenzli/templates/offer/search.html b/pflaenzli/pflaenzli/templates/offer/search.html index 2ebb033..8aca173 100644 --- a/pflaenzli/pflaenzli/templates/offer/search.html +++ b/pflaenzli/pflaenzli/templates/offer/search.html @@ -1,10 +1,29 @@ {% extends 'base.html' %} {% load static %} +{% load crispy_forms_tags %} {% block title %}Offers{% endblock %} {% block content %} -

Offers

+

+ Offers + +

+
+ {% csrf_token %} + {{ form|crispy }} + +
{% if offers %} -
+
{% for offer in offers %}
diff --git a/pflaenzli/pflaenzli/utils/distance.py b/pflaenzli/pflaenzli/utils/distance.py index 2015eca..403f00e 100644 --- a/pflaenzli/pflaenzli/utils/distance.py +++ b/pflaenzli/pflaenzli/utils/distance.py @@ -1,6 +1,7 @@ from geopy.distance import distance import os from pandas import read_pickle +from django.db.models import F, Func path = os.path.dirname(os.path.abspath(__file__)) @@ -9,7 +10,7 @@ df = read_pickle(os.path.join(path, 'plz.pkl')) def calculate_distance(zip_1, zip_2): if zip_1 == zip_2: - return None + return 0 zip_1_coords = tuple(df[df.index == zip_1].values) zip_2_coords = tuple(df[df.index == zip_2].values) @@ -17,3 +18,12 @@ def calculate_distance(zip_1, zip_2): dist = round(distance((zip_1_coords), (zip_2_coords)).kilometers) return None if dist > 400 else dist + + +def filter_by_distance(qs, filter_zipcode, max_dist): + filtered_offers = [] + for offer in qs: + d = calculate_distance(int(offer.zipcode), int(filter_zipcode)) + if d is not None and d <= max_dist: + filtered_offers.append(offer) + return filtered_offers diff --git a/pflaenzli/pflaenzli/views.py b/pflaenzli/pflaenzli/views.py index 4eede75..480c502 100644 --- a/pflaenzli/pflaenzli/views.py +++ b/pflaenzli/pflaenzli/views.py @@ -5,17 +5,25 @@ from django.contrib.auth import login from django.contrib.auth.decorators import login_required from django.http import HttpResponseForbidden -from .forms import CreateOfferForm, RegistrationForm +from .forms import CreateOfferForm, RegistrationForm, FilterForm from .models import PflaenzliUser, Offer, Wish from .mail import send_offer_email from .upload import generate_unique_filename -from .utils.distance import calculate_distance +from .utils.distance import calculate_distance, filter_by_distance def list_offers(request, filters=None): offers = Offer.objects.all() - return render(request, "offer/search.html", {"offers": offers}) + + if request.method == "POST": + form = FilterForm(request.POST, request.FILES) + if form.is_valid(): + offers = filter_offers(offers, form) + else: + form = FilterForm() + + return render(request, "offer/search.html", {"offers": offers, "form": form}) @login_required @@ -114,3 +122,16 @@ def register_user(request): form = RegistrationForm() return render(request, "basic_form.html", {"form": form, "button_label": "Register", "title": "Registeration"}) + + +def filter_offers(offers, form): + if form.cleaned_data['text']: + offers = offers.filter(title__icontains=form.cleaned_data['text']) + + if form.cleaned_data['zipcode']: + if form.cleaned_data['distance']: + offers = filter_by_distance(offers, form.cleaned_data['zipcode'], form.cleaned_data['distance']) + else: + offers = offers.filter(zipcode=int(form.cleaned_data['zipcode'])) + + return offers