Есть ли способ это исправить? - PullRequest
0 голосов
/ 29 марта 2020

Я пытаюсь разработать веб-сайт для интернет-магазина, где пользователи могут добавлять товары в свои корзины. Когда пользователь добавляет продукт или удаляет его, я не знаю, почему общая цена не является правильной. Я новичок в Django. Как я могу это исправить?

Мои views.py:

from django.shortcuts import render, redirect, HttpResponseRedirect, Http404
from products.models import Product
from .models import Cart
from django.contrib import messages
from django.urls import reverse
from django.utils.safestring import mark_safe


def cart(request):
    cart = Cart.objects.all()[0]
    context = {"cart":cart}
    template = 'shopping_cart/cart.html'
    return render(request, template, context)


def add_to_cart(request, slug):
    cart = Cart.objects.all()[0]
    try:
        product = Product.objects.get(slug=slug)
    except Product.DoesNotExist:
        raise Http404
    except:
        pass 
    if not product in cart.products.all():
        cart.products.add(product)
        messages.success(request, mark_safe("Product added to cart. Go to <a href='cart/'>cart</a>"))
        return redirect('myshop-home')
    else:
        cart.products.remove(product)
        messages.success(request, mark_safe("Product removed from cart"))


    new_total = 0.00
    for item in cart.products.all():
        new_total += float(item.price)

    cart.total = new_total
    cart.save()

   return HttpResponseRedirect(reverse('cart'))

Мои models.py:

from django.db import models
from products.models import Product


class Cart(models.Model):
    products = models.ManyToManyField(Product, null=True, blank=True)
    total = models.DecimalField(max_digits=100, decimal_places=2, default = 0.00)

    def __unicode__(self):
        return "Cart"

Ответы [ 2 ]

1 голос
/ 29 марта 2020

Вы не включили модель для Product, но я предполагаю, что у вас там есть и DecimalField.

Я думаю, что ваша единственная проблема может заключаться в том, что вы конвертируете во float. Использование DecimalField здесь правильно, и причина этого в том, что вы хотите избежать float, потому что float не так точен, как вы думаете.

from decimal import Decimal
# ...
    new_total = Decimal()
    for item in cart.products.all():
        new_total += item.price
cart.total = new_total
cart.save()

Или, что еще лучше, используя встроенные sum () и итератор (здесь не нужно импортировать десятичное число):

cart.total = sum(item.price for item in cart.products.all())
cart.save()

Кроме того, это быстрее, если не загружать все объекты из базы данных:

cart.total = sum(cart.products.values_list('price', flat=True))
cart.save()
1 голос
/ 29 марта 2020

Вы должны ассоциировать тележки с сессиями. Таким образом, любой пользователь будет иметь собственную корзину независимо от состояния входа в систему. Для удобства вы можете go с пользовательским промежуточным программным обеспечением:

# middleware.py
def cart_from_request(self, request):       
    try:
        cart_pk = request.session.get('_cart_pk')
        return Cart.objects.get(pk=cart_pk)
    except Cart.DoesNotExist:
        cart = Cart.objects.create()
        request.session['_cart_pk'] = cart.pk
        return cart

class CartMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        request.cart = cart_from_request(request)
        return self.get_response(request)

И добавить его в свой стек промежуточного программного обеспечения:

# settings.py

MIDDLEWARE = [
    # ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    # ...
    'dotted.path.to.middleware.CartMiddleware',
    # ...
]

И в любом представлении теперь вы можете просто получить доступ к request.cart. Это сказанное, имея корзину, поддерживающую ее собственное общее количество, является ненужной избыточностью. Почему бы не сделать его собственностью:

from django.db.models.aggregates import Sum

class Cart(...):
    # ...

    @property
    def total(self):
        return self.products.aggregate(total=Sum('price'))['total'] or 0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...