Skip to content

Instantly share code, notes, and snippets.

@MilanRgm
Last active June 30, 2018 04:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MilanRgm/02b71d10da642788c06b088032446904 to your computer and use it in GitHub Desktop.
Save MilanRgm/02b71d10da642788c06b088032446904 to your computer and use it in GitHub Desktop.
import pdb
import datetime
from carts.models import Cart, CartItem
from products.models import Variation
CART_ID = 'cart-id'
class Cart(object):
def __init__(self, request):
"""
Initialize the cart
"""
self.session = request.session
# get the current session from request.session.get(CART_ID)
cart = self.session.get(CART_ID)
if not cart: # cart is not present in the session
# save an empty cart in the session
# but we expect our cart dictionary to use product ids as keys
# and a dictionary with quantity and price as value for each key
# by that we can gurantee same product is not added twice
cart = self.session[CART_ID] = {}
else:
try:
cart = CartItem.objects.get(id=cart)
except CartItem.DoesNotExist:
cart = self.session[CART_ID] = {}
self.cart = cart
def __iter__(self):
"""
Iterate over the items in the cart and get the products from the database
"""
product_ids = self.cart.keys()
# get the product objects and add them to the cart
products = Variation.objects.filter(id__in=product_ids)
for product in products:
self.cart[str(product.id)]['product'] = product
for item in self.cart.values():
item['price'] = Decimal(item['price'])
item['total_price'] = item['price'] * item['quantity']
yield item
def __len__(self):
"""
Count all the items in the cart
"""
return sum(item['quantity'] for item in self.cart.values())
def get_total_price(self):
return sum(Decimal(item['price']) * item['quantity'] for item in self.cart.values())
def clear(self):
# empty cart
self.session[CART_ID] = {}
self.session.modified = True
def new(self, request):
cart = Cart(timestamp=datetime.datetime.now())
cart.save()
request.session[CART_ID] = cart.id
return cart
def add(self, product, quantity=1, update_quantity=False):
"""
Add a product to the cart or update its quantity for True
or the new quantity needs to be added to the existing quantity
if it is False. We use the product id as a key and convert it to string
because django uses JSON to serialize session data.
"""
product_id = str(product.id)
try:
product = Variation.objects.get(id=product.id)
except Variation.DoesNotExist:
raise ValidationError("Variation does not exist")
if product_id not in self.cart:
# cart_item = CartItem.objects.create()
self.cart[product_id] = {
'quantity': 0,
'price': str(product.price)
}
if update_quantity:
cart_item = CartItem.objects.create(
cart=self.cart,
items=product,
quantity=quantity)
self.cart[product_id]['quantity'] = quantity
else:
cart_item = CartItem.objects.get(cart=self.cart)
cart_item.quantity += quantity
self.cart[product_id]['quantity'] += quantity
self.save()
def save(self):
# update the session cart
self.session[CART_ID] = self.cart
# mark the session as modified to make sure it is saved
self.session.modified = True
def remove(self, product):
"""
Remove a product from the cart
"""
product_id = str(product.id)
if product_id in self.cart:
del self.cart[product_id]
self.save()
class Cart(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.CASCADE)
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=0.00)
class CartItem(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
item = models.ForeignKey(Variation, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
line_item_total = models.DecimalField(max_digits=10, decimal_places=2)
class CartSerializer(serializers.ModelSerializer):
item = VariationSerializer(many=True, read_only=True)
class Meta:
model = Cart
fields = ('item', 'user', 'timestamp', 'updated', 'subtotal', 'total', 'active',)
class CartItemSerializer(serializers.ModelSerializer):
class Meta:
model = CartItem
fields = '__all__'
class CartAPI(APIView):
serializer_class = serializers.CartItemSerializer
def get(self, request, format=None):
reply = {}
try:
carts = CartItem.objects.all()
reply['data'] = self.serializer_class(carts, many=True).data
except CartItem.DoesNotExist:
reply['data'] = []
return Response(reply, status.HTTP_200_OK)
def post(self, request, format=None):
'''
{
"product": 3,
"quantity": 4
}
'''
reply = {}
cart = Cart(request)
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
pdb.set_trace()
data = serializer.data
product_instance = data.get('product')
quantity = data.get('quantity')
cart_data = cart.add(product_instance, quantity)
reply['data'] = cart_data
return Response(reply, status.HTTP_200_OK)
return Response(serializer.errors)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment