Django购物车和商品模型-获取数量以进行更新

Rut*_*net 0 python django django-models django-views

我正在开发Django购物车应用程序。我有两种型号的购物车和物品。我正在尝试将数量添加到购物篮中时更新数量,但无法使视图正常工作。我在使item_obj分配工作时遇到问题-在这里我需要对模型管理器做任何事情吗?任何帮助都非常感谢。

型号

class Cart(models.Model):
    user = models.ForeignKey(User, null=True, blank=True)
    products = models.ManyToManyField(Product, blank=True)
    total = models.DecimalField(default=0.00, max_digits=10, decimal_places=2)
    updated = models.DateTimeField(auto_now=True)
    timestamp = models.DateTimeField(auto_now_add=True)

    objects = CartManager()

    def __str__(self):
        return str(self.id)

class Item(models.Model):
    item = models.ForeignKey(Product, null=True)
    cart = models.ForeignKey(Cart, null=True)
    quantity = models.PositiveIntegerField()
Run Code Online (Sandbox Code Playgroud)

Views.py提取

    def cart_update(request):
        product_id = request.POST.get('product_id')
        product_obj = Item.objects.get(id=product_id)
        print(item_id)
        item_obj = Item.objects.get(id=product_id)
        cart_obj, new_obj = Cart.objects.new_or_get(request)
        if item_obj in cart_obj.products.all():
            cart_obj.products.add(product_obj)
            item_obj.quantity += 1
            item_obj.save()
        else:
            cart_obj.products.add(product_obj)
        return redirect("cart:home")

EDIT
Run Code Online (Sandbox Code Playgroud)

Views.py更新(12/02/2018)

def cart_update(request):
    # Based on the user who is making the request, grab the cart object
    cart_obj, new_obj = Cart.objects.new_or_get(request)
    # Get entries in the cart
    my_carts_current_entries = Entry.objects.filter(cart=cart_obj)
    # Get a list of your products
    products = Product.objects.all()

    if request.POST:
        # Get the product's ID from the POST request.
        product_id = request.POST.get('product_id')
        # Get the quantity of the product desired.
        product_quantity = request.POST.get('product_quantity')
        # Create the new Entry...this will update the cart on creation
        Entry.objects.create(cart=cart_obj, product=product_id, quantity=product_quantity)
        return HttpResponse('carts/carts.html')

    return render(request, 'carts/carts.html', {'cart_obj': cart_obj, 'my_carts_current_entries': my_carts_current_entries,
                                              'products': products})
Run Code Online (Sandbox Code Playgroud)

另外,我还有一个单独的购物车模型管理器,用于创建新购物车或为用户分配一个购物车,如下所示:

class CartManager(models.Manager):
    def new_or_get(self, request):
        cart_id = request.session.get("cart_id", None)
        qs = self.get_queryset().filter(id=cart_id)
        if qs.count() == 1:
            new_obj = False
            cart_obj = qs.first()
            if request.user.is_authenticated() and cart_obj.user is None:
                cart_obj.user = request.user
                cart_obj.save()
        else:
            cart_obj = Cart.objects.new(user=request.user)
            new_obj = True
            request.session['cart_id'] = cart_obj.id
        return cart_obj, new_obj


    def new(self, user=None):
        user_obj = None
        if user is not None:
            if user.is_authenticated():
                user_obj = user
        return self.model.objects.create(user=user_obj)
Run Code Online (Sandbox Code Playgroud)

调试日志中的错误在这里可用:

http://dpaste.com/1NX02JW

提前致谢

更新2:

这就是我的模板文件目前的读取方式。

{% for product in cat_appetizers %}
<table>

<tr>   
<td><h5>{{ product.name }}</h5>
<td><p><strong>£ {{ product.price }}</strong></p></td>

<td>
    <form class='form-product-ajax' method="POST" action='{% url "cart:update" %}' data-endpoint='{% url "cart:update" %}' class="form"> {% csrf_token %}
        <input type="hidden" name='product_id' value='{{ product.id }}'>
        <span class='submit-span'>
        {% if product in cart.products.all %}
            <button>Remove</button>
        {% else %}
            <button>Add to Basket</button>
        </span>
        {% endif %}
    </form>
</td>
</tr>
</table>
{% endfor %} 
Run Code Online (Sandbox Code Playgroud)

wra*_*bit 5

我们可以通过在模型中使用保存后的信号来更新Cart模型。每当创建条目时,以下保存后的接收器都会更新购物车模型。

models.py

from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.datetime_safe import datetime


class Product(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=64, unique=True)
    description = models.TextField(default='')
    cost = models.DecimalField(default=0.00, max_digits=10, decimal_places=2)


class Cart(models.Model):
    user = models.ForeignKey(User, null=True, blank=True, on_delete='CASCADE')
    count = models.PositiveIntegerField(default=0)
    total = models.DecimalField(default=0.00, max_digits=10, decimal_places=2)
    updated = models.DateTimeField(auto_now=True)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "User: {} has {} items in their cart. Their total is ${}".format(self.user, self.count, self.total)


class Entry(models.Model):
    product = models.ForeignKey(Product, null=True, on_delete='CASCADE')
    cart = models.ForeignKey(Cart, null=True, on_delete='CASCADE')
    quantity = models.PositiveIntegerField()

    def __str__(self):
        return "This entry contains {} {}(s).".format(self.quantity, self.product.name)


@receiver(post_save, sender=Entry)
def update_cart(sender, instance, **kwargs):
    line_cost = instance.quantity * instance.product.cost
    instance.cart.total += line_cost
    instance.cart.count += instance.quantity
    instance.cart.updated = datetime.now()
Run Code Online (Sandbox Code Playgroud)

示例功能

def test_my_cart():
    apple, created = Product.objects.get_or_create(name='apple', cost=0.25)
    my_cart, created = Cart.objects.get_or_create(user=None)

    print(my_cart)
    # STDOUT --> User: None has 0 items in their cart. Their total is $0.00
    entry1 = Entry.objects.create(product=apple, cart=my_cart, quantity=3)

    print(entry1)
    # STDOUT --> This entry contains 3 apple(s)
    print(my_cart)
    # STDOUT --> User: None has 3 items in their cart. Their total is $0.75
Run Code Online (Sandbox Code Playgroud)

如果您想稍后再从购物车中删除该行条目,则Django中还会有一个后删除信号。

祝你好运


编辑#1

要在管理面板中使用此功能,请尝试以下操作

# admin.py
from django.contrib import admin
from django.utils.datetime_safe import datetime

from app.models import Product, Cart, Entry


class EntryAdmin(admin.ModelAdmin):
    # Overide of the save model
    def save_model(self, request, obj, form, change):
        obj.cart.total += obj.quantity * obj.product.cost
        obj.cart.count += obj.quantity
        obj.cart.updated = datetime.now()
        obj.cart.save()
        super().save_model(request, obj, form, change)

# Register your models here.
admin.site.register(Product)
admin.site.register(Cart)
admin.site.register(Entry, EntryAdmin)
Run Code Online (Sandbox Code Playgroud)

我还想指出的是,由于存在“多种方法来给猫换皮”,我们可以在模型中覆盖save方法,而不使用信号。我认为这取决于应用程序和个人喜好。


编辑#2

这是一个示例视图,它将:

  1. 获取用户的购物车
  2. 从该购物车中获取条目列表
  3. 在这些条目中获取产品的所有唯一名称的列表

example_view.py

from django.shortcuts import render
from scratchwork.models import Cart, Entry
from django.contrib.auth.models import User


def test_view(request):
    """ This view displays what is in a user's cart. """
    # Based on the user who is making the request, grab the cart object
    my_cart = Cart.objects.get_or_create(user=User)
    # Get a queryset of entries that correspond to "my_cart"
    list_of_entries = Entry.objects.filter(cart=my_cart)
    # Make a list of the product's names
    list_of_products = list(list_of_entries.values_list('product__name', flat=True))
    # Remove redundant product names
    list_of_products = list(set(list_of_products))
    return render(request, 'something.html', {'list_of_products': list_of_products})
Run Code Online (Sandbox Code Playgroud)

编辑#3

在讨论代码之前,我将进行快速比较,因此我们在同一页上讨论了模型类。

假设您在亚马逊购物。您作为亚马逊客户拥有 购物车。购物车将显示您在网站上购物时添加到其中的所有条目

当您浏览亚马逊奇妙的商品时,偶然发现了一双想要购买的鞋子。这些鞋子是产品,并有名称,价格和描述。

您决定购买这些鞋子,因此单击“添加到购物车”。此时,Amazon Web服务会生成一个链接到购物车条目,其中 包含有关产品的信息。

实作

因此,您单击一个按钮将POST数据发送回视图。假设您正在使用表单或AJAX数据来获取信息,这就是设计视图的方式。

from django.http import HttpResponse
from django.shortcuts import render
from scratchwork.models import Cart, Entry, Product
from django.contrib.auth.models import User


def test_view(request):
    # Based on the user who is making the request, grab the cart object
    my_cart = Cart.objects.get_or_create(user=User)
    # Get entries in the cart
    my_carts_current_entries = Entry.objects.filter(cart=my_cart)
    # Get a list of your products
    products = Product.objects.all()

    if request.POST:
        # Get the product's ID from the POST request.
        product_id = request.POST.get('product_id')
        # Get the object using our unique primary key
        product_obj = Product.objects.get(id=product_id)
        # Get the quantity of the product desired.
        product_quantity = request.POST.get('product_quantity')
        # Create the new Entry...this will update the cart on creation
        Entry.objects.create(cart=my_cart, product=product_obj, quantity=product_quantity)
        return HttpResponse('somewhereelse.html')

    return render(request, 'something.html', {'my_cart': my_cart, 'my_carts_current_entries': my_carts_current_entries,
                                              'products': products})
Run Code Online (Sandbox Code Playgroud)