Skip to content

Commit 4cf3af1

Browse files
Implemented post-filtering with 2 parameters: km range and upcoming events
1 parent a9411d0 commit 4cf3af1

File tree

7 files changed

+104
-235
lines changed

7 files changed

+104
-235
lines changed

pugliaeventi/views.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,16 @@ def index(request):
2727
if search_rec_form.is_valid():
2828
mood = search_rec_form.cleaned_data.get('mood')
2929
companionship = search_rec_form.cleaned_data.get('companionship')
30+
distance = search_rec_form.cleaned_data.get('km_range')
31+
any_events = search_rec_form.cleaned_data.get('any_events')
3032
lightfm_user_id = constant.DJANGO_USER_ID_BASE_START_LIGHTFM + request.user.id
3133
contextual_lightfm_user_id = str(lightfm_user_id) + str(mood) + str(companionship)
32-
recommended_places = lightfm_manager.find_recommendations(contextual_lightfm_user_id)
34+
35+
recommended_places = lightfm_manager.find_recommendations(
36+
contextual_lightfm_user_id,
37+
request.user.profile.location,
38+
int(distance),
39+
any_events)
3340

3441
context = {
3542
'search_form': search_rec_form,

recommender_webapp/common/constant.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@
1515
RATINGS_PER_CONTEXT_CONF = 5
1616
CONTEXTS = 6
1717
DJANGO_USER_ID_BASE_START_LIGHTFM = 100
18-
NUM_RECOMMENDATIONS = 30
18+
NUM_RECOMMENDATIONS_TO_SHOW = 30
19+
NUM_RECOMMENDATIONS_FROM_LIGHTFM = 300
20+

recommender_webapp/common/lightfm_manager.py

+32-8
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import csv
2+
from datetime import datetime
23

34
from recommender_webapp.common import constant
45
from engine import lightfm_pugliaeventi
5-
from recommender_webapp.models import Place
6+
from recommender_webapp.models import Place, Distanza, Event
67

78

89
def add_user(user_id, user_location, user_contexts, data):
@@ -49,15 +50,38 @@ def add_rating(contextual_lightfm_user_id, place_id, rating):
4950
lightfm_pugliaeventi.add_rating_to_model(max_user_id, max_item_id, contextual_lightfm_user_id, place_id, rating)
5051

5152

52-
def find_recommendations(user):
53+
def find_recommendations(user, user_location, distance, any_events):
5354
recommended_places = []
5455
user = int(user) - 1 # LightFM uses a zero-based indexing
5556
model, data = lightfm_pugliaeventi.learn_model()
56-
recommendations = lightfm_pugliaeventi.find_recommendations(user, model, data)
57-
places_to_show = recommendations[:constant.NUM_RECOMMENDATIONS]
58-
for place in places_to_show:
59-
place_id = place + 1 # Because the LightFM zero-based indexing
60-
place = Place.objects.get(placeId=place_id)
61-
recommended_places.append(place)
57+
recommendations = lightfm_pugliaeventi.find_recommendations(user, model, data)[:constant.NUM_RECOMMENDATIONS_FROM_LIGHTFM]
58+
recommendation_objects = []
59+
for index in recommendations:
60+
place_id = index + 1 # Because the LightFM zero-based indexing
61+
if Place.objects.filter(placeId=place_id).exists():
62+
place = Place.objects.get(placeId=place_id)
63+
recommendation_objects.append(place)
64+
65+
if any_events:
66+
recommendations_with_events = []
67+
for place in recommendation_objects:
68+
if Event.objects.filter(place=place, date_from__gte=datetime.today().date()).exists():
69+
recommendations_with_events.append(place)
70+
recommendation_objects = recommendations_with_events
71+
72+
if distance:
73+
locations_in_range = [distance[0] for distance in
74+
Distanza.objects.filter(cittaA=user_location,
75+
distanza__lte=distance).order_by('distanza').values_list('cittaB')]
76+
locations_in_range = [user_location] + locations_in_range
77+
for place in recommendation_objects:
78+
if place.location in locations_in_range:
79+
recommended_places.append(place)
80+
if len(recommended_places) == constant.NUM_RECOMMENDATIONS_TO_SHOW:
81+
break
82+
else:
83+
places_to_show = recommendation_objects[:constant.NUM_RECOMMENDATIONS_TO_SHOW]
84+
for place in places_to_show:
85+
recommended_places.append(place)
6286

6387
return recommended_places

recommender_webapp/forms.py

+32-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,15 @@ def clean(self, *args, **kwargs):
5555
return super(UserRegisterForm, self).clean(*args, **kwargs)
5656

5757

58-
# This form is used for searching recommendations and also for adding a new rating
58+
class SearchRecommendationDistanceRange(ChoiceEnum):
59+
__order__ = 'unlimited km20 km40 km60'
60+
unlimited = 0
61+
km20 = 20
62+
km40 = 40
63+
km60 = 60
64+
65+
66+
# This form is used for searching recommendations
5967
class SearchRecommendationForm(forms.Form):
6068
mood = forms.ChoiceField(
6169
required=True,
@@ -67,9 +75,30 @@ class SearchRecommendationForm(forms.Form):
6775
widget=forms.Select,
6876
choices=[choice[::-1] for choice in Companionship.choices()]
6977
)
78+
km_range = forms.ChoiceField(
79+
required=False,
80+
widget=forms.Select,
81+
choices=[choice[::-1] for choice in SearchRecommendationDistanceRange.choices()],
82+
label='Distance'
83+
)
84+
any_events = forms.BooleanField(initial=False, required=False, label='Any events')
85+
86+
87+
# This form is used for adding a new rating
88+
class AddRatingForm(forms.Form):
89+
mood = forms.ChoiceField(
90+
required=True,
91+
widget=forms.Select,
92+
choices=[choice[::-1] for choice in Mood.choices()]
93+
)
94+
companionship = forms.ChoiceField(
95+
required=True,
96+
widget=forms.Select,
97+
choices=[choice[::-1] for choice in Companionship.choices()]
98+
)
7099

71100

72-
class DistanceRange(ChoiceEnum):
101+
class SearchPlacesDistanceRange(ChoiceEnum):
73102
__order__ = 'km5 km10'
74103
km5 = 5
75104
km10 = 10
@@ -82,7 +111,7 @@ class SearchNearPlacesForm(forms.Form):
82111
km_range = forms.ChoiceField(
83112
required=True,
84113
widget=forms.Select,
85-
choices=[choice[::-1] for choice in DistanceRange.choices()]
114+
choices=[choice[::-1] for choice in SearchPlacesDistanceRange.choices()]
86115
)
87116

88117

recommender_webapp/views.py

+23-42
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
from django.views.decorators.csrf import csrf_protect
99

1010
from recommender_webapp.common import lightfm_manager, constant
11-
from recommender_webapp.forms import ProfileForm, UserRegisterForm, SearchNearPlacesForm, DistanceRange, \
12-
SearchRecommendationForm, FullProfileForm
11+
from recommender_webapp.forms import ProfileForm, UserRegisterForm, SearchNearPlacesForm, SearchPlacesDistanceRange, \
12+
AddRatingForm, FullProfileForm
1313
from recommender_webapp.models import Comune, Distanza, Place, Mood, Companionship, Rating, User, Profile, Event
1414

1515

@@ -115,26 +115,18 @@ def profile_configuration(request):
115115

116116
close_places = []
117117
user_location = request.user.profile.location
118-
distances_in_range = Distanza.objects.filter(cittaA=user_location, distanza__lte=constant.KM_RANGE_CONFIGURATION).order_by('distanza')
119-
120-
user_location_places = Place.objects.filter(location=user_location)
121-
for place in user_location_places:
122-
place_dict = vars(place)
123-
place_dict['labels'] = place.labels()
124-
rated_place = Rating.objects.filter(place=place, user=request.user.profile)
125-
if rated_place:
126-
place_dict['rated'] = True
127-
rated_places.append(place_dict)
128-
else:
129-
close_places.append(place_dict)
130-
131-
for distance in distances_in_range:
132-
places = Place.objects.filter(location=distance.cittaB)
118+
locations_in_range = [distance[0] for distance in
119+
Distanza.objects.filter(
120+
cittaA=user_location,
121+
distanza__lte=constant.KM_RANGE_CONFIGURATION).order_by('distanza').values_list('cittaB')]
122+
locations_in_range = [user_location] + locations_in_range
123+
124+
for location in locations_in_range:
125+
places = Place.objects.filter(location=location)
133126
for place in places:
134127
place_dict = vars(place)
135128
place_dict['labels'] = place.labels()
136-
rated_place = Rating.objects.filter(place=place)
137-
if rated_place:
129+
if Rating.objects.filter(place=place, user=request.user.profile).exists():
138130
place_dict['rated'] = True
139131
rated_places.append(place_dict)
140132
else:
@@ -175,42 +167,31 @@ def add_rating_config(request, place_id, mood, companionship):
175167

176168
def close_places(request):
177169
context = {}
178-
rated_places = []
179170
close_places = []
180171

181172
if request.user.is_authenticated:
182173

183174
search_near_places_form = SearchNearPlacesForm(request.POST or None)
184-
initial_km_range = (DistanceRange.km5.name, DistanceRange.km5.value)
175+
initial_km_range = (SearchPlacesDistanceRange.km5.name, SearchPlacesDistanceRange.km5.value)
185176
search_near_places_form.fields['km_range'].initial = initial_km_range
186177

187178
if search_near_places_form.is_valid():
188179
km_range = search_near_places_form.cleaned_data.get('km_range')
189180
user_location = request.user.profile.location
190-
distances_in_range = Distanza.objects.filter(cittaA=user_location, distanza__lte=km_range).order_by('distanza')
191-
192-
user_location_places = Place.objects.filter(location=user_location)
193-
for place in user_location_places:
194-
place_dict = vars(place)
195-
place_dict['labels'] = place.labels()
196-
rated_place = Rating.objects.filter(place=place, user=request.user.profile)
197-
if rated_place:
198-
place_dict['rated'] = True
199-
rated_places.append(place_dict)
200-
else:
201-
close_places.append(place_dict)
202-
203-
for distance in distances_in_range:
204-
places = Place.objects.filter(location=distance.cittaB)
181+
locations_in_range = [distance[0] for distance in
182+
Distanza.objects.filter(
183+
cittaA=user_location,
184+
distanza__lte=km_range).order_by('distanza').values_list('cittaB')]
185+
locations_in_range = [user_location] + locations_in_range
186+
187+
for distance in locations_in_range:
188+
places = Place.objects.filter(location=distance)
205189
for place in places:
206190
place_dict = vars(place)
207191
place_dict['labels'] = place.labels()
208-
rated_place = Rating.objects.filter(place=place)
209-
if rated_place:
192+
if Rating.objects.filter(place=place).exists():
210193
place_dict['rated'] = True
211-
rated_places.append(place_dict)
212-
else:
213-
close_places.append(place_dict)
194+
close_places.append(place_dict)
214195

215196
context = {
216197
'search_form': search_near_places_form,
@@ -253,7 +234,7 @@ def place_details(request, place_id):
253234
context = {}
254235
if request.user.is_authenticated:
255236

256-
search_rec_form = SearchRecommendationForm(request.POST or None)
237+
search_rec_form = AddRatingForm(request.POST or None)
257238
initial_mood = (Mood.joyful.name, Mood.joyful.value)
258239
search_rec_form.fields['mood'].initial = initial_mood
259240

templates/index.html

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ <h5 class="text-center">Search recommendations right for you</h5>
2626
<div class="col-auto my-1">
2727
{{ search_form.companionship|as_crispy_field }}
2828
</div>
29+
<div class="col-auto my-1">
30+
{{ search_form.km_range|as_crispy_field }}
31+
</div>
32+
<div class="col-auto my-1">
33+
{{ search_form.any_events|as_crispy_field }}
34+
</div>
2935
<div class="col-auto my-1">
3036
<button type="submit" class="btn btn-primary" onclick="modal();">Search</button>
3137
</div>

0 commit comments

Comments
 (0)