TypeError: 类型为 Decimal 的对象无法序列化为 JSON | Django

3
我遇到了一个非常不寻常的错误,让我感到有些困惑。当我迭代购物车项目并尝试查看它们时,会抛出TypeError类型为Decimal的对象无法进行JSON序列化的错误。但是如果我从模板中删除该块,然后刷新页面,再将相同的块添加回模板并刷新页面,则可以运行。我已添加一些屏幕截图。请看一下,并帮忙解决这个问题。
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

错误

错误截图

引起错误的代码块

输入图片说明

删除该代码块

输入图片说明

删除代码块并刷新页面后

输入图片说明

添加代码块

输入图片说明

添加代码块并刷新页面后

输入图片说明

可以看到,在删除代码块之前有错误,删除代码块并刷新页面,再添加代码块回到模板并再次刷新页面后,似乎正常工作了。 你能帮我解决这个问题吗?


你在哪里调用了序列化器? - crimsonpython24
他没有使用任何序列化器。 - Kishan Parmar
我这里没有使用任何序列化器 @crimsonpython24 - Debopriyo Das
@crimsonpython24,您可以查看cart.py文件中Cart类的__iter__方法。 - Debopriyo Das
@DebopriyoDas 你找到解决方案了吗?或者知道为什么会出现这个问题吗?我也遇到了类似的问题,但是我没有使用任何序列化器。 - M. Gar
1个回答

0

这一行的问题

for product in products:
    cart[str(product.id)]['product'] = product 

产品实例有一个十进制字段,即价格字段,该字段无法进行JSON序列化。 因此,为了解决这个错误,您可以将要在模板中使用的产品字段明确添加到会话数据中以进行循环。 例如:

cart[str(product.id)]['product_name'] = product.name
cart[str(product.id)]['product_price'] = float(product.price) 

对于价格字段,您可以使用浮点数而不是将其转换为十进制:

for item in cart.values():
    item['price'] = float(item['price']) 

谢谢你的回答。我不再将我的购物车保存在会话中了,而是创建了一个模型来跟踪各种参数。 - Debopriyo Das

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接