Ошибка типа: Объект типа «Продукт» не сериализуется в формате JSON

#python #json #django #django-sessions

Вопрос:

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

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

Это представление, которое выполняется после завершения всех платежей:

 #I am not pasting the imports, all fine with them

basket = Basket(request)
orders = Orders(request)

### We are looping through the all items we are storing in basket to create for each one, single order
for basketitem in basket:
    #This order is automatically created for admin, just ignore it, it's working fine
    order = Order.objects.create(user_id=user_id, product=basketitem['product'], size=basketitem['size'], quantity=basketitem['quantity'], full_name=full_name, address1=address1,
                                 address2=address2, postcode=postcode, town=town, country=country, total_paid=baskettotal, order_key=order_key, authenticated=False)

    #This is the main problem, this is trying to get a product from database "Product" comparing id from database to id that we store in basket in django sessions
    product = get_object_or_404(
        Product, id=int(basketitem['productid']))

    orders.add(product=product, quantity=basketitem['quantity'], size=basketitem['size'], full_name=full_name, address1=address1,
               address2=address2, postcode=postcode, town=town, country=country, created=now.strftime("%d/%m/%Y %H:%M:%S"))
 

И после этого возникает ошибка «Объект типа»Продукт» не сериализуется в формате JSON».

полная обратная связь:

 Internal Server Error: /orders/add/
Traceback (most recent call last):
  File "D:GitHubEcommerce-Storevenvlibsite-packagesdjangocorehandlersexception.py", line 47, in inner
    response = get_response(request)
  File "D:GitHubEcommerce-Storevenvlibsite-packagesdjangoutilsdeprecation.py", line 119, in __call__
    response = self.process_response(request, response)
  File "D:GitHubEcommerce-Storevenvlibsite-packagesdjangocontribsessionsmiddleware.py", line 61, in process_response
    request.session.save()
  File "D:GitHubEcommerce-Storevenvlibsite-packagesdjangocontribsessionsbackendsdb.py", line 83, in save
    obj = self.create_model_instance(data)
  File "D:GitHubEcommerce-Storevenvlibsite-packagesdjangocontribsessionsbackendsdb.py", line 70, in create_model_instance
    session_data=self.encode(data),
  File "D:GitHubEcommerce-Storevenvlibsite-packagesdjangocontribsessionsbackendsbase.py", line 116, in encode
    compress=True,
  File "D:GitHubEcommerce-Storevenvlibsite-packagesdjangocoresigning.py", line 110, in dumps
    return TimestampSigner(key, salt=salt).sign_object(obj, serializer=serializer, compress=compress)
  File "D:GitHubEcommerce-Storevenvlibsite-packagesdjangocoresigning.py", line 172, in sign_object
    data = serializer().dumps(obj)
  File "D:GitHubEcommerce-Storevenvlibsite-packagesdjangocoresigning.py", line 87, in dumps
    return json.dumps(obj, separators=(',', ':')).encode('latin-1')
  File "C:UsersuserAppDataLocalProgramsPythonPython36libjson__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "C:UsersuserAppDataLocalProgramsPythonPython36libjsonencoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:UsersuserAppDataLocalProgramsPythonPython36libjsonencoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "C:UsersuserAppDataLocalProgramsPythonPython36libjsonencoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'Product' is not JSON serializable
 

Basket.py

 class Basket():
    def __init__(self, request):
        self.session = request.session
        basket = self.session.get('bt')
        if 'bt' not in request.session:
            basket = self.session['bt'] = {}
        self.basket = basket

    def add(self, product, quantity, size):
        product_id = str(product.id)

        if product_id not in self.basket:
            self.basket[product_id] = {'productid': int(product.id), 'price': int(
                product.price), 'quantity': int(quantity), 'size': int(size)}

        self.session.modified = True
 

Orders.py

 from decimal import Decimal

from store.models import Product


class Orders():
    def __init__(self, request):
        self.session = request.session
        orders = self.session.get('os')
        if 'os' not in request.session:
            orders = self.session['os'] = {}
        self.orders = orders

    def add(self, product, quantity, size, full_name, address1, address2, postcode, town, country, created):
        product_id = str(product.id)

        if product_id not in self.orders:
            self.orders[product_id] = {'price': int(
                product.price), 'quantity': int(quantity), 'size': int(size), 'full_name': str(full_name),
                'address1': str(address1), 'address2': str(address2), 'postcode': str(postcode), 'town': str(town),
                'country': str(country), 'created': str(created)
            }

        self.session.modified = True

    def delete(self, product):
        product_id = str(product)

        if product_id in self.orders:
            del self.orders[product_id]

        self.session.modified = True

    def clear(self):
        del self.session['os']
        self.session.modified = True

    def __iter__(self):
        product_ids = self.orders.keys()
        products = Product.products.filter(id__in=product_ids)
        orders = self.orders.copy()

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

        for item in orders.values():
            item['price'] = float(item['price'])
            item['total_price'] = item['price'] * item['quantity']
            yield item

    def __len__(self):
        return sum(item['quantity'] for item in self.orders.values())

    def get_total_price(self):
        return sum(float(item['price']) * item['quantity'] for item in self.orders.values())
 

Интересно, почему аналогичная операция, которая выполняется, не выдает ту же ошибку

 def basket_add(request):
    '''
    Handles data captured from ajax and adds product to basket,
    updates the actual amount of products in basket.
    '''
    basket = Basket(request)
    if request.POST.get('action') == 'post':
        product_id = int(request.POST.get('productid'))
        quantity = int(request.POST.get('quantity'))
        size = int(request.POST.get('size'))
        product = get_object_or_404(Product, id=product_id)
        basket.add(product=product, quantity=quantity, size=size)
        basket_quantity = basket.__len__()
        response = JsonResponse({'quantity': basket_quantity})
        return response
 

Есть какие-нибудь решения?

Комментарии:

1. Что такое Product ? Это вопрос о сериализации этого объекта, и большая часть другого представленного кода, скорее всего, не связана. Это помогло бы показать обратную связь, чтобы мы точно видели, что терпит неудачу.

2. @tdelaney Извините, дайте мне секунду

3. Можете ли вы поделиться всей обратной связью?

4. Конечно, подожди секунду @bdbd

5. Я не знаю решения, но вот ссылка на сериализацию django: docs.djangoproject.com/en/3.2/topics/serialization

Ответ №1:

Ошибка, о которой вы упомянули, вызвана default методом кодирования json. Это означает, что модуль json не распознает Product объект. Django имеет встроенный механизм сериализации для сериализации объекта модели в объект JSON.

Если вы не хотите использовать способ Django для сериализации данных, вам может потребоваться определить пользовательский кодер[1] для обработки Product объекта.

[1] https://docs.python.org/3/library/json.html#encoders-and-decoders