Skip to content

Commit 8f3a67c

Browse files
Finished Chapter 10
1 parent 3e13383 commit 8f3a67c

File tree

7 files changed

+63
-3
lines changed

7 files changed

+63
-3
lines changed

cart/templates/cart/detail.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ <h1>Your shopping cart</h1>
2828
2929
3030
31+
32+
3133
{% if product.image %}{{ product.image.url }}{% else %}{% static "img/no_image.png" %}{% endif %}">
3234
</a>
3335
</td>
@@ -80,6 +82,20 @@ <h1>Your shopping cart</h1>
8082

8183
</tbody>
8284
</table>
85+
{% if recommended_products %}
86+
<div class="recommendations cart">
87+
<h3>People who bought this also bought</h3>
88+
{% for p in recommended_products %}
89+
<div class="item">
90+
<a href="{{ p.get_absolute_url }}">
91+
<img src="
92+
{% if p.image %}{{ p.image.url }}{% else %}{% static "img/no_image.png" %}{% endif %}">
93+
</a>
94+
<p><a href="{{ p.get_absolute_url }}">{{ p.name }}</a></p>
95+
</div>
96+
{% endfor %}
97+
</div>
98+
{% endif %}
8399
<p>Apply a coupon:</p>
84100
<form action="{% url "coupons:apply" %}" method="post">
85101
{{ coupon_apply_form }}

cart/views.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from coupons.froms import CouponApplyForm
55
from shop.models import Product
6+
from shop.recommender import Recommender
67
from .cart import Cart
78
from .forms import CartAddProductForm
89

@@ -36,12 +37,18 @@ def cart_detail(request):
3637
'override': True,
3738
}
3839
)
40+
cart_products = [item for item in cart]
41+
if cart_products:
42+
r = Recommender()
43+
recommended_products = r.suggest_products_for(cart_products, 4)
44+
recommended_products = []
3945
coupon_apply_form = CouponApplyForm()
4046
return render(
4147
request,
4248
'cart/detail.html',
4349
context={
4450
'cart': cart,
45-
'coupon_apply_form': coupon_apply_form
51+
'coupon_apply_form': coupon_apply_form,
52+
'recommended_products': recommended_products
4653
}
4754
)

payment/tasks.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
from celery import shared_task
55
# from django.contrib.staticfiles import finders
66
from django.core.mail import EmailMessage
7+
from django.shortcuts import get_object_or_404
78
from django.template.loader import render_to_string
89

910
from orders.models import Order
11+
from shop.models import Product
12+
from shop.recommender import Recommender
1013

1114

1215
@shared_task
@@ -35,3 +38,12 @@ def payment_completed(order_id):
3538
)
3639
# send e-mail
3740
email.send()
41+
42+
43+
@shared_task
44+
def add_items_for_recommender(order_id):
45+
order = get_object_or_404(Order, id=order_id)
46+
product_ids = order.items.values_list('product_id', flat=True)
47+
products = Product.objects.filter(id__in=product_ids)
48+
r = Recommender()
49+
r.products_bought(products)

payment/webhooks.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from django.views.decorators.csrf import csrf_exempt
66

77
from orders.models import Order
8-
from .tasks import payment_completed
8+
from .tasks import payment_completed, add_items_for_recommender
99

1010

1111
@csrf_exempt
@@ -33,7 +33,9 @@ def stripe_webhook(request):
3333
order.stripe_id = session.payment_intent
3434
order.save()
3535
# launch asynchronous task
36+
add_items_for_recommender.delay(order.id)
3637
payment_completed.delay(order.id)
38+
3739
except ValueError:
3840
# Invalid payload
3941
return HttpResponse(status=400)

shop/recommender.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class Recommender:
1414
def get_product_key(self, id):
1515
return f'product:{id}:purchased_with'
1616

17-
def products_brought(self, products):
17+
def products_bought(self, products):
1818
product_ids = [product.id for product in products]
1919
for product_id in product_ids:
2020
for with_id in product_ids:
@@ -50,3 +50,7 @@ def suggest_products_for(self, products, max_result=6):
5050
suggested_products.sort(key=lambda x: suggested_product_ids.index(x.id))
5151

5252
return suggested_products
53+
54+
def clear_purchases(self):
55+
for id in Product.objects.values_list('id', flat=True):
56+
r.delete(self.get_product_key(id))

shop/templates/shop/product/detail.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,20 @@ <h2>
2020
<input type="submit" value="Add to cart">
2121
</form>
2222
{{ product.description|linebreaks }}
23+
{% if recommended_products %}
24+
<div class="recommendations">
25+
<h3>People who bought this also bought</h3>
26+
{% for p in recommended_products %}
27+
<div class="item">
28+
<a href="{{ p.get_absolute_url }}">
29+
<img src="
30+
31+
{% if p.image %}{{ p.image.url }}{% else %}{% static "img/no_image.png" %}{% endif %}">
32+
</a>
33+
<p><a href="{{ p.get_absolute_url }}">{{ p.name }}</a></p>
34+
</div>
35+
{% endfor %}
36+
</div>
37+
{% endif %}
2338
</div>
2439
{% endblock %}

shop/views.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from cart.forms import CartAddProductForm
44
from .models import Product, Category
5+
from .recommender import Recommender
56

67

78
def product_list(request, category_slug=None):
@@ -27,11 +28,14 @@ def product_list(request, category_slug=None):
2728
def product_detail(request, id, slug):
2829
product = get_object_or_404(Product, available=True, id=id, slug=slug)
2930
cart_product_form = CartAddProductForm()
31+
r = Recommender()
32+
recommended_products = r.suggest_products_for([product], 4)
3033
return render(
3134
request,
3235
'shop/product/detail.html',
3336
context={
3437
'product': product,
3538
'cart_product_form': cart_product_form,
39+
'recommended_products': recommended_products,
3640
}
3741
)

0 commit comments

Comments
 (0)