Filter offers

This commit is contained in:
Jannis Portmann 2023-04-15 13:16:40 +02:00
parent cad77f6a4a
commit 1cabae10e8
4 changed files with 66 additions and 6 deletions

View file

@ -1,5 +1,6 @@
from django import forms from django import forms
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from django.utils.safestring import mark_safe
from friendly_captcha.fields import FrcCaptchaField from friendly_captcha.fields import FrcCaptchaField
from .models import Offer, PflaenzliUser from .models import Offer, PflaenzliUser
@ -17,3 +18,12 @@ class RegistrationForm(UserCreationForm):
fields = UserCreationForm.Meta.fields + ('email', 'zipcode',) fields = UserCreationForm.Meta.fields + ('email', 'zipcode',)
captcha = FrcCaptchaField() captcha = FrcCaptchaField()
class FilterForm(forms.Form):
text = forms.CharField(max_length=128, required=False, label=mark_safe(
'<i class="fa-solid fa-magnifying-glass"></i> Search'))
zipcode = forms.CharField(max_length=4, required=False, label=mark_safe(
'<i class="fa-solid fa-location-dot"></i> Zipcode'))
distance = forms.IntegerField(required=False, label=mark_safe(
'<i class="fa-solid fa-signs-post"></i> Distance (km)'))

View file

@ -1,10 +1,29 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load static %} {% load static %}
{% load crispy_forms_tags %}
{% block title %}Offers{% endblock %} {% block title %}Offers{% endblock %}
{% block content %} {% block content %}
<h1>Offers</h1> <h1 class="mt-3">
Offers
<button class="btn btn-pfl"
type="button"
data-bs-toggle="collapse"
data-bs-target="#filterCollapse"
aria-expanded="true"
aria-controls="filterCollapse">
<i class="fa-solid fa-filter"></i> Filter
</button>
</h1>
<form method="post"
enctype="multipart/form-data"
class="collapse"
id="filterCollapse">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-pfl">Filter</button>
</form>
{% if offers %} {% if offers %}
<div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 mb-3 row-gap-5"> <div class="row row-cols-1 row-cols-md-2 row-cols-xl-3 mt-3 mb-3 row-gap-5">
{% for offer in offers %} {% for offer in offers %}
<div class="col"> <div class="col">
<div class="card h-100 p-0"> <div class="card h-100 p-0">

View file

@ -1,6 +1,7 @@
from geopy.distance import distance from geopy.distance import distance
import os import os
from pandas import read_pickle from pandas import read_pickle
from django.db.models import F, Func
path = os.path.dirname(os.path.abspath(__file__)) 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): def calculate_distance(zip_1, zip_2):
if zip_1 == zip_2: if zip_1 == zip_2:
return None return 0
zip_1_coords = tuple(df[df.index == zip_1].values) zip_1_coords = tuple(df[df.index == zip_1].values)
zip_2_coords = tuple(df[df.index == zip_2].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) dist = round(distance((zip_1_coords), (zip_2_coords)).kilometers)
return None if dist > 400 else dist 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

View file

@ -5,17 +5,25 @@ from django.contrib.auth import login
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
from .forms import CreateOfferForm, RegistrationForm from .forms import CreateOfferForm, RegistrationForm, FilterForm
from .models import PflaenzliUser, Offer, Wish from .models import PflaenzliUser, Offer, Wish
from .mail import send_offer_email from .mail import send_offer_email
from .upload import generate_unique_filename 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): def list_offers(request, filters=None):
offers = Offer.objects.all() 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 @login_required
@ -114,3 +122,16 @@ def register_user(request):
form = RegistrationForm() form = RegistrationForm()
return render(request, "basic_form.html", {"form": form, "button_label": "Register", "title": "Registeration"}) 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