这是我的models.py
我想我需要在Cart方法中添加另一个字段。我可以在不改变模型的情况下完成。如果不是那么我应该如何改进我的模型
models.py
from decimal import Decimal
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models.signals import pre_save, post_save, post_delete
from products.models import Variation
# Create your models here.
class CartItem(models.Model):
cart = models.ForeignKey("Cart")
item = models.ForeignKey(Variation)
quantity = models.PositiveIntegerField(default=1)
line_item_total = models.DecimalField(max_digits=10, decimal_places=2)
def __unicode__(self):
return self.item.title
def remove(self):
return self.item.remove_from_cart()
def cart_item_pre_save_receiver(sender, instance, *args, **kwargs):
qty = instance.quantity
if qty >= 1:
price = instance.item.get_price()
line_item_total = Decimal(qty) * Decimal(price)
instance.line_item_total = line_item_total
pre_save.connect(cart_item_pre_save_receiver, sender=CartItem)
def cart_item_post_save_receiver(sender, instance, *args, **kwargs):
instance.cart.update_subtotal()
post_save.connect(cart_item_post_save_receiver, sender=CartItem)
post_delete.connect(cart_item_post_save_receiver, sender=CartItem)
class Cart(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
items = models.ManyToManyField(Variation, through=CartItem)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
subtotal = models.DecimalField(max_digits=50, decimal_places=2, default=25.00)
tax_percentage = models.DecimalField(max_digits=10, decimal_places=5, default=0.145)
tax_total = models.DecimalField(max_digits=50, decimal_places=2, default=25.00)
total = models.DecimalField(max_digits=50, decimal_places=2, default=25.00)
def __unicode__(self):
return str(self.id)
def update_subtotal(self):
print "updating..."
subtotal = 0
items = self.cartitem_set.all()
for item in items:
subtotal += item.line_item_total
self.subtotal = "%.2f" %(subtotal)
self.save()
def do_tax_and_total_receiver(sender, instance , *args, **kwargs):
subtotal = Decimal(instance.subtotal)
tax_total = round(subtotal * Decimal(instance.tax_percentage), 2)
total = round(subtotal + Decimal(tax_total), 2)
instance.tax_total = "%.2f" %tax_total
instance.total = "%.2f" %(total)
pre_save.connect(do_tax_and_total_receiver, sender=Cart)
我目前正在收到所有物品,但没有数量 的 HTML
{% extends "base.html" %}
{% block content %}
{% for object in object_list %}
<li>
{{ object.id }}
{{ object.cart.items.all }}
</li>
{% endfor %}
{% endblock %}
购物车应用views.py
from django.contrib.auth.forms import AuthenticationForm
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, Http404, JsonResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic.base import View
from django.views.generic.detail import SingleObjectMixin, DetailView
from django.views.generic.edit import FormMixin
# Create your views here.
from orders.forms import GuestCheckoutForm
from orders.mixins import CartOrderMixin
from orders.models import UserCheckout, Order
from products.models import Variation
from .models import Cart, CartItem
class ItemCountView(View):
def get(self, request, *args, **kwargs):
if request.is_ajax():
cart_id = self.request.session.get("cart_id")
if cart_id == None:
count = 0
else:
cart = Cart.objects.get(id=cart_id)
count = cart.items.count()
request.session["cart_item_count"] = count
return JsonResponse({"count": count})
else:
raise Http404
class CartView(SingleObjectMixin, View):
model = Cart
template_name = "carts/view.html"
def get_object(self, *args, **kwargs):
self.request.session.set_expiry(0) #5 minutes
cart_id = self.request.session.get("cart_id")
if cart_id == None:
cart = Cart()
cart.save()
cart_id = cart.id
self.request.session["cart_id"] = cart_id
cart = Cart.objects.get(id=cart_id)
if self.request.user.is_authenticated():
cart.user = self.request.user
cart.save()
return cart
def get(self, request, *args, **kwargs):
cart = self.get_object()
item_id = request.GET.get("item")
delete_item = request.GET.get("delete", False)
item_added = False
if item_id:
item_instance = get_object_or_404(Variation, id=item_id)
qty = request.GET.get("qty", 1)
try:
if int(qty) < 1:
delete_item = True
except:
raise Http404
cart_item, created = CartItem.objects.get_or_create(cart=cart, item=item_instance)
if created:
item_added = True
if delete_item:
cart_item.delete()
else:
cart_item.quantity = qty
cart_item.save()
if not request.is_ajax():
return HttpResponseRedirect(reverse("cart"))
#return cart_item.cart.get_absolute_url()
if request.is_ajax():
try:
total = cart_item.line_item_total
except:
total = None
try:
subtotal = cart_item.cart.subtotal
except:
subtotal = None
try:
cart_total = cart_item.cart.total
except:
cart_total = None
try:
tax_total = cart_item.cart.tax_total
except:
tax_total = None
try:
total_items = cart_item.cart.items.count()
except:
total_items = 0
data = {
"deleted": delete_item,
"item_added": item_added,
"line_total": total,
"subtotal": subtotal,
"cart_total": cart_total,
"tax_total": tax_total,
"total_items": total_items
}
return JsonResponse(data)
context = {
"object": self.get_object()
}
template = self.template_name
return render(request, template, context)
class CheckoutView(CartOrderMixin, FormMixin, DetailView):
model = Cart
template_name = "carts/checkout_view.html"
form_class = GuestCheckoutForm
#def get_order(self, *args, **kwargs):
# cart = self.get_object()
# new_order_id = self.request.session.get("order_id")
# if new_order_id is None:
# new_order = Order.objects.create(cart=cart)
# self.request.session["order_id"] = new_order.id
# else:
# new_order = Order.objects.get(id=new_order_id)
# return new_order
def get_object(self, *args, **kwargs):
cart = self.get_cart()
if cart == None:
return None
return cart
def get_context_data(self, *args, **kwargs):
context = super(CheckoutView, self).get_context_data(*args, **kwargs)
user_can_continue = False
user_check_id = self.request.session.get("user_checkout_id")
#if not self.request.user.is_authenticated() or user_check_id == None:# or if request.use,is_guest
#elif self.request.user.is_authenticated() or user_check_id != None: #or if request.user.is_guest()
# user_can_continue = True
# else:
# pass
if self.request.user.is_authenticated():
user_can_continue = True
user_checkout, created = UserCheckout.objects.get_or_create(email=self.request.user.email)
user_checkout.user = self.request.user
user_checkout.save()
self.request.session["user_checkout_id"] = user_checkout.id
elif not self.request.user.is_authenticated() and user_check_id == None:
context["login_form"] = AuthenticationForm()
context["next_url"] = self.request.build_absolute_uri()
else:
pass
if user_check_id != None:
user_can_continue = True
#if self.get_cart() is not None:
context["order"] = self.get_order()
context["user_can_continue"] = user_can_continue
context["form"] = self.get_form()
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
email = form.cleaned_data.get("email")
user_checkout, created = UserCheckout.objects.get_or_create(email=email)
request.session["user_checkout_id"] = user_checkout.id
return self.form_valid(form)
else:
return self.form_invalid(form)
def get_success_url(self):
return reverse("checkout")
def get(self, request, *args, **kwargs):
get_data = super(CheckoutView, self).get(request, *args, **kwargs)
cart = self.get_object()
if cart == None:
return redirect("cart")
new_order = self.get_order()
user_checkout_id = request.session.get("user_checkout_id")
if user_checkout_id != None:
user_checkout = UserCheckout.objects.get(id=user_checkout_id)
new_order.user = user_checkout
new_order.save()
return get_data
class CheckoutFinalView(CartOrderMixin, View):
def post(self, request, *args, **kwargs):
order = self.get_order()
if request.POST.get("payment_token"):
order.mark_completed()
del request.session["cart_id"]
del request.session["order_id"]
return redirect("checkout")
def get(self, request, *args, **kwargs):
return redirect("checkout")
models.py for product app
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models.signals import post_save
from django.utils.text import slugify
# Create your models here.
class ProductQuerySet(models.query.QuerySet):
def active(self):
return self.filter(active=True)
class ProductManager(models.Manager):
def get_queryset(self):
return ProductQuerySet(self.model, using=self._db)
def all(self, *args, **kwargs):
return self.get_queryset().active()
class Product(models.Model):
title = models.CharField(max_length=120)
description = models.TextField(blank=True, null=True)
price = models.DecimalField(decimal_places=2, max_digits=20)
active = models.BooleanField(default=True)
#slug
#inventory?
objects = ProductManager()
def __unicode__(self): #def __str__(self):
return self.title
class Variation(models.Model):
product = models.ForeignKey(Product)
title = models.CharField(max_length=120)
price = models.DecimalField(decimal_places=2, max_digits=20)
sale_price = models.DecimalField(decimal_places=2, max_digits=20, null=True, blank=True)
active = models.BooleanField(default=True)
inventory = models.IntegerField(null=True, blank=True) #refer none == unlimited amount
def __unicode__(self):
return self.title
def get_price(self):
if self.sale_price is not None:
return self.sale_price
else:
return self.price
def add_to_cart(self):
return "%s?item=%s&qty=1" %(reverse("cart"), self.id)
def remove_from_cart(self):
return "%s?item=%s&qty=1&delete=True" %(reverse("cart"), self.id)
def get_title(self):
return "%s - %s" %(self.product.title, self.title)
def product_post_saved_receiver(sender, instance, created, *args, **kwargs):
product = instance
variations = product.variation_set.all()
if variations.count() == 0:
new_var = Variation()
new_var.product = product
new_var.title = "Default"
new_var.price = product.price
new_var.save()
post_save.connect(product_post_saved_receiver, sender=Product)
def image_upload_to(instance, filename):
title = instance.product.title
slug = slugify(title)
basename, file_extension = filename.split(".")
new_filename = "%s-%s.%s" %(slug, instance.id, file_extension)
return "products/%s/%s" %(slug, new_filename)
class ProductImage(models.Model):
product = models.ForeignKey(Product)
image = models.ImageField(upload_to=image_upload_to)
def __unicode__(self):
return self.product.title
“预计输出”:我应该收到订单中的产品(我已经收到)也需要这些产品的数量