I am getting quite unusual error. I got pretty confused because of this. When I iterate over the cart items and try to view them it throws a TypeError Object of type Decimal is not JSON serializable. But if i remove the block from my templates then refresh the page and again add the same block to my templates and refresh the page it works. I have added some screenshots. Please have a look and help me out with this
cart.py
class Cart(object):
def __init__(self, request):
"""
Initialize the cart
"""
self.session = request.session
cart = self.session.get(settings.CART_SESSION_ID)
if not cart:
# save an empty cart in the session
cart = self.session[settings.CART_SESSION_ID] = {}
self.cart = cart
def add(self, product, quantity=1, override_quantity=False):
"""
Add a product to the cart or update its quantity
"""
product_id = str(product.id)
if product_id not in self.cart:
self.cart[product_id] = {
'quantity': 0,
'price': str(product.price)
}
if override_quantity:
self.cart[product_id]['quantity'] = quantity
else:
self.cart[product_id]['quantity'] += quantity
self.save()
def __iter__(self):
"""
Iterate over the items in the cart
and get the products from the database
"""
product_ids = self.cart.keys()
# get the product objects and add the o the cart
products = Product.objects.filter(id__in=product_ids)
cart = self.cart.copy()
for product in products:
cart[str(product.id)]['product'] = product
for item in cart.values():
item['price'] = Decimal(item['price'])
item['total_price'] = item['price'] * item['quantity']
yield item
def get_total_price(self):
"""
Calculate the total cost of the items in the cart
"""
return sum(Decimal(item['price']) * item['quantity'] for item in self.cart.values())
orders.py
def order_create(request):
cart = Cart(request)
order = None
address_form = AddressCheckoutForm()
billing_address_id = request.session.get('billing_address_id', None)
shipping_address_id = request.session.get('shipping_address_id', None)
order, created = Order.objects.get_or_create(user=request.user, ordered=False)
if shipping_address_id:
shipping_address = Address.objects.get(id=shipping_address_id)
order.shipping_address = shipping_address
del request.session['shipping_address_id']
if billing_address_id:
billing_address = Address.objects.get(id=billing_address_id)
order.billing_address = billing_address
del request.session['billing_address_id']
if billing_address_id or shipping_address_id:
order.save()
if request.method == 'POST':
for item in cart:
OrderItem.objects.create(
order=order,
product=item['product'],
price=item['price'],
quantity=item['quantity']
)
order.ordered = True
order.save()
cart.clear()
return render(request, 'orders/order/created.html', {'order': order})
return render(request, 'orders/order/create.html', {'cart': cart, 'address_form': address_form, 'object': order})
create.html
<h1>Checkout</h1>
{% if not object.shipping_address %}
<h3>Shipping</h3>
{% url "addresses:checkout_address_create" as checkout_address_create %}
{% include 'address/form.html' with form=address_form next_url=request.build_absolute_uri action_url=checkout_address_create address_type='shipping' %}
{% elif not object.billing_address %}
<h3>Billing</h3>
{% url "addresses:checkout_address_create" as checkout_address_create %}
{% include 'address/form.html' with form=address_form next_url=request.build_absolute_uri action_url=checkout_address_create address_type='billing' %}
{% else %}
{% for item in cart %}
{{ item.quantity }} X {{ item.product.name }}
{{ item.total_price }}
{% endfor %}
<p>Total Price: {{ cart.get_total_price }}</p>
<form action="" method="POST">
{% csrf_token %}
<p><input type="submit" value="Place Order"></p>
</form>
{% endif %}
Traceback
Internal Server Error: /order/create/
Traceback (most recent call last):
File "/home/duke/Monday/truck-giggle/env/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/duke/Monday/truck-giggle/env/lib/python3.8/site-packages/django/utils/deprecation.py", line 96, in __call__
response = self.process_response(request, response)
File "/home/duke/Monday/truck-giggle/env/lib/python3.8/site-packages/django/contrib/sessions/middleware.py", line 58, in process_response
request.session.save()
File "/home/duke/Monday/truck-giggle/env/lib/python3.8/site-packages/django/contrib/sessions/backends/db.py", line 83, in save
obj = self.create_model_instance(data)
File "/home/duke/Monday/truck-giggle/env/lib/python3.8/site-packages/django/contrib/sessions/backends/db.py", line 70, in create_model_instance
session_data=self.encode(data),
File "/home/duke/Monday/truck-giggle/env/lib/python3.8/site-packages/django/contrib/sessions/backends/base.py", line 105, in encode
serialized = self.serializer().dumps(session_dict)
File "/home/duke/Monday/truck-giggle/env/lib/python3.8/site-packages/django/core/signing.py", line 87, in dumps
return json.dumps(obj, separators=(',', ':')).encode('latin-1')
File "/usr/lib/python3.8/json/__init__.py", line 234, in dumps
return cls(
File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python3.8/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Decimal is not JSON serializable
[29/Jul/2020 14:20:17] "GET /order/create/ HTTP/1.1" 500 102125
The error
code block that is raising the error
removing the block
after removing the block and refreshing the page
adding the block again
after adding the block and refreshing the page
As you can see before removing the code block the error is there, after removing it and refreshing the page and adding the code block back to the templates and refreshing the page again seems to work fine. Can you please help me out with this?
5
The problem here at this line
for product in products:
cart[str(product.id)]['product'] = product
product’s instance has a decimal field, the price field, which is not JSON serializable.
So to solve this error, you can add explicitly the product’s fields, you want to use in the template, into the session data to loop over.
For instance:
cart[str(product.id)]['product_name'] = product.name
cart[str(product.id)]['product_price'] = float(product.price)
and for the price field, instead of converting it into Decimal, you can use float:
for item in cart.values():
item['price'] = float(item['price'])
1