在 Django 购物车应用程序中实现 "Save For Later" 功能?

Implementing "Save For Later" functionality in a Django Shopping Cart App?

我正在尝试通过使用 Django 创建一个电子商务网站来自学 Django。我现在正在处理购物车;它是使用 Django 会话实现的,目前运行良好,但我在实现 "save for later" 功能时遇到了问题,您可以在许多在线商店(即亚马逊或其他任何网站)上找到该功能,该功能允许用户从他们的购物车中删除商品而是将它们放在一个列表中,使他们可以从购物车页面轻松查看。在我继续之前,这是我当前购物车的 views.py 和 cart.py:

cart.py:

from decimal import Decimal
from django.conf import settings
from bookDetails.models import Book




# This is the cart class.
class Cart(object):
    # Constructor method for the class - includes a request parameter
    def __init__(self, request):
        # Start by creating a session for the new cart
        self.session = request.session

        userCart = self.session.get(settings.CART_SESSION_ID)

        if not userCart:
            userCart = self.session[settings.CART_SESSION_ID] = {}

        self.userCart = userCart

    def save(self):
        self.session.modified = True

    def add(self, book, amount=1, change_amount=False):
        book_id = str(book.id)

        if book_id not in self.userCart:
            self.userCart[book_id] = {'amount': 0,
                                      'author': book.book_author,
                                      'author_bio': book.author_bio,
                                      'description': book.book_description,
                                      'genre': book.book_genre,
                                      'publishing_info': book.publishing_info,
                                      'avg_rating': str(book.avg_rating),
                                      'price': str(book.price)}

        if change_amount:
            self.userCart[book_id]['amount'] = amount
        else:
            self.userCart[book_id]['amount'] += amount

        self.save()


    def remove(self, book):
        book_id = str(book.id)

        if book_id in self.userCart:
            del self.userCart[book_id]
            self.save()


    def __iter__(self):

        book_ids = self.userCart.keys()

        books = Book.objects.filter(id__in=book_ids)

        cart = self.userCart.copy()

        for book in books:
            cart[str(book.id)]['book'] = book

        for book in cart.values():
            book['price'] = Decimal(book['price'])

            book['total_price'] = book['price'] * book['amount']

            yield book

    def __len__(self):
        return sum(book['amount'] for book in self.userCart.values())

    def get_total_price(self):
        return sum((book['price'] * book['amount']) for book in self.userCart.values())

    def clear(self):
        del self.session[settings.CART_SESSION_ID]
        self.save()

Views.py:

from django.shortcuts import render, redirect, get_object_or_404

from django.views.decorators.http import require_POST

# This is the Book model from the bookDetails package I made.
from bookDetails.models import Book
# These are the cart and cart forms.
from .cart import Cart
from .forms import AddToCartForm

@require_POST
def addToCart(request, book_id):
    userCart = Cart(request)
    book = get_object_or_404(Book, id=book_id)


    form = AddToCartForm(request.POST)

    if form.is_valid():
        data = form.cleaned_data
        userCart.add(book=book,
                     amount=data['amount'],
                     change_amount=data['change_amount'])


    return redirect('cart:cart_info')

def removeFromCart(request, book_id):
    userCart = Cart(request)

    book = get_object_or_404(Book, id=book_id)

    userCart.remove(book)

    return redirect('cart:cart_info')

def cart_info(request):
    userCart = Cart(request)


    for current in userCart:
        current['update_amount_form'] = AddToCartForm(
            initial={'amount': current['amount'],
                     'change_amount': True}
        )

    return render(request, 'cart/info.html', {'userCart': userCart})


# This view displays the checkout page

def checkout(request):
    userCart = Cart(request)

    userCart.clear()

    return render(request, 'cart/checkout.html', {'userCart': userCart})

鉴于我设置购物车的方式,设置 "save for later" 功能的 simplest/most 有效方法是什么?我最初尝试做的是创建另一个 class 就像购物车 class 一样,除了它被称为 SFLList(为以后列表保存),然后只是从购物车中复制粘贴大部分代码 class 放在上面并调整它们以获得一个简单的列表,像这样

class SFLList(object):

        def __init__(self, request):

            self.session = request.session

            SFL = self.session.get(settings.SFL_SESSION_ID)

            if not SFL:
                SFL = self.session[settings.SFL_SESSION_ID] = {}

            self.SFL = SFL
# Below this would go functions like addSFL, removeSFL, 
# and the __iter__ function, all redefined to work with SFLList

...但这最终给了我一个 TypeError 因为 "the Decimal type is not JSON serializable" 或类似的东西,这看起来可能与我将 price 属性转换为 str 的方式有关,所以它可以可序列化(在购物车 class 的添加功能中),但代码和站点按原样运行得非常好。当我添加 SFLList 代码并尝试集成它时,它才崩溃并给了我那个错误。

我昨天花了一整天时间试图让我的新 SFLList class 工作,但无济于事。我最终只是放弃了更改并恢复到我最近的提交(在我制作 SFLList 和与之相关的更改之前)。正如预期的那样,没有 TypeError 因为 Decimal 当它只是购物车时 class,完全按照我在这里得到的定义。

我觉得必须有一种更简单的方法来做到这一点。 "saved for later" 所要做的就是我的购物车已经做的完全相同的事情,但没有将书放在购物车中。通常我会用 Java 或 C++ 之类的语言做的只是创建一个数组并将 "Book" 实例移入其中,然后遍历该数组并打印每本书的所有属性命令。这是我第一次使用像 Django 这样的东西,其中的事情似乎主要是通过数据库查询来完成的。我似乎不喜欢我真的可以使用数组或列表来存储模型中的东西——我发现最接近的东西是一个叫做 ArrayField 的东西,但显然它要求你的数据库是 "Postgres",我不知道不认为我的项目正在使用(settings.py 数据库设置为 sqlite3)。

最好的方法是什么?

我认为您可以像这样在购物车商品字典中设置一个布尔变量来简化问题

self.userCart[book_id] = {
  'amount': 0,
  'author': book.book_author,
  'author_bio': book.author_bio,
  'description': book.book_description,
  'genre': book.book_genre,
  'publishing_info': book.publishing_info,
  'avg_rating': str(book.avg_rating),
  'price': str(book.price),
  'for_later': False  # saved for later if True
}

如果您只想要购物车中的图书,您可以:

def get_books_ids(self):
   books_ids = []
   for key, val in self.userCart.items():
       if not val['for_later']:
           books_ids.append(key)
   return books_ids

def __iter__(self):
  book_ids = self.get_books_ids()

  books = Book.objects.filter(id__in=book_ids)

  cart = self.userCart.copy()

  for book in books:
      cart[str(book.id)]['book'] = book

  for book in cart.values():
      book['price'] = Decimal(book['price'])

      book['total_price'] = book['price'] * book['amount']

      yield book