Не использую десятичные дроби, но полученный объект типа Decimal не является JSON сериализуемым

мое представление работает отлично, но когда я пытаюсь сохранить результат ModelForm в сессии

хранится, но полученный Object типа Decimal не является JSON serializable

это не имеет смысла, потому что я не храню десятичные числа на сессии

PS: я храню результат ModelForm в сессии, потому что мне нужно перенаправить пользователя на внешний url после того, как он вернется, мне нужно, чтобы эти данные хранились в сессии

Здесь вид

def cart_detail(request):
    cart = Cart(request)
    order_form = OrderCreateForm()
    for item in cart:
        item['update_quantity_form'] = CartAddProductForm(initial={'quantity': item['quantity'], 'override': True})

    if cart.__len__() :
        if request.method == 'POST':
            order_form = OrderCreateForm(request.POST)
            if order_form.is_valid():
                order = order_form.save(commit=False)
                
                for item in order_form.cleaned_data.items():
                    request.session[str(item[0])] = str(item[1])
                    
                    print(request.session[str(item[0])])

              

                #also tried this way and same result
                # request.session['order_data'] = order_form.cleaned_data
                #also tried this way and same result

                # request.session['first_name'] = order_form.cleaned_data['first_name'] 
                # request.session['order_phone'] = str(order_form.cleaned_data['phone'])    
                # print('type => ', request.session['order_phone'])
              
                if request.user.is_authenticated:
                    order.user = request.user
                order.save()
                for item in cart:
                    OrderItem.objects.create(order=order,product=item['product'],price=item['price'],quantity=item['quantity'],attribute_1 = ['attrbute_1'], attribute_2 = ['attrbute_2'], attribute_3 = ['attrbute_3'])
                context = {
                    'order': order,
                    'total_price': total_price,
                    'delivery': order.delivery_cost,
                    'total_price_with_delivery': total_price_with_delivery,
                }
                
                print('here i am')

                return render(request, 'created.html', context)
            else: 
                print('errorforms', order_form.errors)
                messages.error(request, order_form.errors)
                return render(request, 'cart.html', {'cart':cart, 'form' : order_form, 'wilayas': wilayas, 'communes': communes})
        else:
            order_form = OrderCreateForm()
            if request.user.is_authenticated:
                initial_data = {
                    'first_name' : request.user.first_name,
                    'email' : request.user.email,
                    'phone' : request.user.profile.phone_number,
                    'address' : request.user.profile.address,
                }
                print('the form is not valid')
                order_form = OrderCreateForm(request.POST or None, initial=initial_data)
    context = {
        'cart': cart,
        'form' : order_form,
    }
    return render(request, 'cart.html', context)

** ФОРМА **

class OrderCreateForm(forms.ModelForm):

class Meta:
    model = Order
    fields = ['first_name',  'address', 'campany', 'email', 'phone', 'wilaya', 'commune', 'note']
    required = ('phone',)

Я не думаю, что проблема в сессии

я также закомментировал все методы модели заказа

я даже не знаю, где на самом деле проблема

когда я удаляю этот блок, все работает нормально

            for item in order_form.cleaned_data.items():
                request.session['order_data_'+str(item[0])] = str(item[1])
                print(request.session[str(item[0])])

но когда он здесь, печать работает

Я думаю, что ваша проблема заключается в этой строке в cart.py

cart = self.session[settings.CART_SESSION_ID] = {}

Вы установили свою корзину равной значению в дикте вашей сессии, и тем самым вы изменяете сессию каждый раз, когда изменяете свою корзину. Поэтому, используя классы Decimal или Product, Django пытается сериализовать данные до того, как вы их санируете. Вы должны выполнить свою логику до установки переменной сессии.

Я думаю, что вам лучше использовать модель для того, что вы пытаетесь сделать. Вы также захотите рассчитывать свои цены в центах (или наименьшей единице для любой валюты), чтобы избежать ошибок округления.

Отредактировано для дальнейшего разъяснения:

В cart.py у вас есть следующая строка.

cart = self.session[settings.CART_SESSION_ID] = {}

Справа налево, вы назначаете {} на self.session[settings.CART_SESSION_ID], а затем self.session[settings.CART_SESSION_ID] на cart

Например, если посмотреть на этот блок кода

def __iter__(self):
    ...
    for item in cart.values():
        item['price'] = Decimal(item['price'])
    ...

Вы не просто изменяете cart.item.price. Вы также изменяете self.session[setting.CART_SESSION_ID].item.price. Проблема в том, что в Django, когда вы изменяете сессию, он сериализует ваши изменения в JSON. Поскольку self.session ссылается на сессию пользователя (в __init__), Django пытается сериализовать объект Decimal и выдает ошибку.

Чтобы исправить это, вы можете изменить соответствующую часть вашего __init__ с

cart = self.session.get(settings.CART_SESSION_ID) 
if not cart:
    cart = self.session[settings.CART_SESSION_ID] = {}
self.cart = cart

to

cart = self.session.get(settings.CART_SESSION_ID)
self.cart = cart.copy() if cart else {}

и сделать свой метод save()

def save():
    self.session.modified=True
    self.session[settings.CART_SESSION_ID] = self.cart
Вернуться на верх