Django session: Object of type is not JSON serializable?

Добрый вечер. Столкнулся с аналогичной проблемой Django session(ошибка сериализации). Создал 2 приложения под корзину и под избранное. Если отключаю 1 из них в settings, то другое работает без ошибок. Либо если добавить товар в избранное и корзину - работает, в противном случае получаю ошибку
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Goods is not JSON serializable

# Ошибка: корзина пустая, 1 товар в избранном
{'1': {}} # print(self.session.get('favorites'))
{} # print(self.session.get('cart'))

Сохранение и удаление работает. Ошибка возникает при выводе, предполагаю что в __iter__

services.py
from apps.goods.models import Goods

class Favorites(object):

  def __init__(self, request):
    """ Initialize the favorites """
    self.session = request.session
    favorites = self.session.get('favorites')

    if not favorites:
      favorites = self.session['favorites'] = {}
    self.favorites = favorites

  def save(self):
    """ 
    Mark the session as "modified" to make sure it gets saved
    """
    # добавил строку из решения по ссылке но не помогло
    # self.session['favorites'] = self.favorites = self.session.get('favorites', []) 
    
    self.session.modified = True

  def add(self, goods):
    """
    Add a goods to the favorite
    """
    goods_id = str(goods.id)
    if goods_id not in self.favorites:
      self.favorites[goods_id] = {}
    self.save()

  def remove(self, goods):
    """
    Remove a goods from the favorite
    """
    goods_id = str(goods.id)
    if goods_id in self.favorites:
      del self.favorites[goods_id]
      self.save()                          

  def __iter__(self):
    """
    Iterate over the items in the favorites and get the goods 
    from the database.
    """
    goods_ids = self.favorites.keys()    
    products = Goods.objects.filter(id__in=goods_ids)
    favorites = self.favorites.copy()
    for product in products:
      favorites[str(product.id)]['goods'] = product        
  
    for item in favorites.values():
        yield item

  def __len__(self):
    return len(self.favorites)


views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.views.decorators.http import require_POST
from apps.goods.models import Goods
from .services import Favorites

def favorites(request):
  favorites = Favorites(request)
  return render(request, 'wishlist/favorites.html', {'favorites': favorites})

def add_favorites(request, goods_id):
  favorites = Favorites(request)
  goods = get_object_or_404(Goods, id=goods_id)
  favorites.add(goods = goods)
  return redirect('favorites')

def remove_favorites(request, goods_id):
  favorites = Favorites(request)
  goods = get_object_or_404(Goods, id=goods_id)
  favorites.remove(goods)
  return redirect('favorites')


В services для корзины аналогично, но с добавлением доп.данных
apps.cart.services

from decimal import Decimal
from apps.goods.models import Goods


class Cart(object):

  def __init__(self, request):
    """ Initialize the cart. """
    self.session = request.session
    cart = self.session.get('cart')
    if not cart:
        # save an empty cart in the session
        cart = self.session['cart'] = {}
    self.cart = cart


  def add(self, goods, size, quantity=1, update_quantity=False):
      """
      Add a goods to the cart or update its quantity.
      """
      goods_id = str(goods.id) + size
      if goods_id not in self.cart:
          self.cart[goods_id] = {'id': str(goods.id),
                                 'quantity': 0, 
                                 'price': goods.price,
                                 'size': size}
      if update_quantity:
          self.cart[goods_id]['quantity'] = quantity
      else:
          self.cart[goods_id]['quantity'] += quantity
      self.save()


  def save(self):
    """ 
    Mark the session as "modified" to make sure it gets saved
    """
    # строка из решения по ссылке не помогло
    # self.session['cart'] = self.cart = self.session.get('cart', [])
    self.session.modified = True


  def remove(self, goods, size):
    """
    Remove a goods from the cart
    """
    goods_id = str(goods.id) + size
    if goods_id in self.cart:
      del self.cart[goods_id]
      self.save()
  

  def __iter__(self):
    """
    Iterate over the items in the cart and get the goods 
    from the database.
    """
    goods_ids = list()
    for key in self.cart.values():
      goods_ids.append(key['id'])

    # get the product objects and add them to the cart
    products = Goods.objects.filter(id__in=goods_ids)
    cart = self.cart.copy()
    for product in products:
        for el in self.cart.values():
          id = str(product.id)
          if el['id'] == id:
            cart[ id + el['size'] ]['goods'] = product
            self.cart[ id + el['size'] ]['price'] = product.price
  
    for item in cart.values():
        item['total_price'] = item['price'] * item['quantity']
        yield item
  

  def __len__(self):
    """
    Count all items in the cart.
    """
    return sum(item['quantity'] for item in self.cart.values())


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


  def clear(self):
    """
    Remove cart from session
    """ 
    del self.session['cart']
    self.save()



Никак не могу понять из-за чего конфликт?
  • Вопрос задан
  • 2727 просмотров
Решения вопроса 2
@deliro
Агрессивное программирование
Ты в сессию добавляешь объект модели ORM. Сессия JSON сериализованная. Объект модели не сериалируется в JSON (внезапно)
Ответ написан
@redskye798
Комментатор выше прав в том, что в сессию нельзя передавать объекты ORM. Однако автор и не пытается (осознанно) передать в сессию объект. Он думает, что в методе __iter__ добавляет объект product к копии self.favorites, а затем отдаёт в yield, не меняя исходный self.favorites. Увы, исходный self.favorites всё же меняется, и в сессию пытается пролезть объект ORM. Для решения проблемы нужно изменить способ копирования объекта self.favorites.

Импортируем модуль copy и заменяем favorites = self.favorites.copy() на favorites = copy.deep_copy(self.favorites)
Должно сработать.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы