在Django Shopping Cart应用程序中实现“稍后保存”功能?

时间:2019-03-13 19:09:08

标签: python django database shopping-cart

我正试图通过使用它来建立一个电子商务站点来自学Django。我现在正在购物车上。它是使用Django会话实现的,并且目前运行良好,但是我无法实现“在线保存”功能,您可以在许多在线商店(例如Amazon或其他商店)中找到该功能,以允许用户从购物车中删除商品而是将其放在一个列表中,使他们可以从购物车页面轻松查看该列表。在继续之前,这是我当前购物车的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})

因此,按照我设置购物车的方式,设置“稍后保存”功能的最简单/最有效的方法是什么?我最初试图做的是创建另一个与Cart类类似的类,除了它称为SFLList(保存为以后的列表),然后将大部分代码从cart类复制粘贴到该类上,并对其进行了简单的调整。列表,像这样

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的错误,因为“ Decimal类型不可JSON序列化”或类似的结果,这似乎与我将price属性转换为str的方式有关。它可能是可序列化的(在cart类的add函数中),但是代码和站点可以按原样完美工作。当我添加SFLList代码并尝试对其进行集成时,它只是崩溃了,并给了我那个错误。

昨天我整天都在努力使新的SFLList类正常工作,但无济于事。我最终只是放弃所做的更改并恢复到我的最新提交(在创建SFLList和与之相关的更改之前)。不出所料,当它只是Cart类时,就不会因为Decimal而出现TypeError了,完全按照我在这里定义的那样。

我觉得必须有一种更简单的方法来做到这一点。 “为以后保存”所要做的只是我的购物车已经做的完全相同的事情,但是没有将书放在购物车中。通常,我会用Java或C ++之类的语言执行操作,或者只是创建一个数组并将“ Book”实例移入其中,然后遍历该数组并按顺序打印每本书的所有属性。这是我第一次使用Django之类的工具,其中大部分事情似乎都是通过数据库查询完成的。似乎我不喜欢真正使用数组或列表在模型中存储东西-我发现最接近的东西叫ArrayField,但显然它要求您的数据库为“ Postgres”,我认为这不是我的项目正在使用(settings.py的数据库设置为sqlite3)。

最好的方法是什么?

1 个答案:

答案 0 :(得分:1)

我想您可以像这样在购物车词典中设置布尔变量来简化问题

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