Реализуете функцию «Сохранить на потом» в приложении Django Shopping Cart? - PullRequest
1 голос
/ 13 марта 2019

Я пытаюсь научить себя 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 (Saved For Later List), затем просто скопировал большую часть кода из класса cart прямо в него и настроил их для простогоlist, что-то вроде этого

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, чтобы он мог быть сериализуемым (в функции add класса cart), но код и сайт работают отлично, как они есть.Он только сломался и дал мне эту ошибку, когда я добавил код SFLList и попытался интегрировать его.

Я провел весь день вчера, пытаясь заставить мой новый класс SFLList работать, но безрезультатно.В итоге я просто отменил изменения и вернулся к своей последней фиксации (до того, как я сделал SFLList и изменения, связанные с ним).Как и ожидалось, нет TypeError из-за Decimal, когда это просто класс Cart, определенный именно так, как я его здесь.

Я чувствую, что должен быть более простой способ сделать это.Все, что нужно «сохранить на потом» - это то же самое, что моя корзина уже делает, но без книги в корзине.Обычно то, что я делал бы на языке, таком как Java или C ++ или что-то еще, - это просто создать массив и переместить в него экземпляры «Книги», а затем просто выполнить итерацию по массиву и распечатать все атрибуты каждой книги по порядку.Я впервые работаю с чем-то вроде Django, где, по-видимому, в основном все делается с помощью запросов к базе данных.Кажется, мне не нравится, что я действительно могу использовать массив или список для хранения вещей внутри моделей - самое близкое, что я обнаружил, это что-то, называемое ArrayField, но, видимо, оно требует, чтобы ваша база данных была "Postgres", что я не думаю,мой проект использует (settings.py имеет базу данных, настроенную как sqlite3).

Какой лучший способ сделать это?

1 Ответ

1 голос
/ 13 марта 2019

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

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
...