django how to know if new items are added to manytomanyfield - django

I am adding items to m2m using add() method but after adding items, how can I know whether any new items added or not, for better understanding have a look at my code
def new_or_get(self, request):
user = request.user
cart_id = request.session.get("cart_id", None)
kart = get_or_none(Cart,id=cart_id)
if kart:
new_obj = False
cart_obj = kart
if user.is_authenticated and cart_obj.user is None:
try:
cart = self.get(user=user)
cart.products.add(*cart_obj.products.all())
cart.messages = 'A'
cart.save()
cart_obj.delete()
cart_obj = cart
except:
cart_obj.user = user
cart_obj.save()
else:
cart_obj = kart
what I want is cart.messages = 'A' will only execute when new items added to cart, is there any builtin method for this, if not then how can I do this.

Related

Object of type Cart is not JSON serializable

I have a products model and a cart model. There is a ManyToMany relation that I put in cart model.
I am trying to return the object of cart model along with the context dictionary but it is giving this error "Object of type Cart is not JSON serializable".
I am using Django version '3.0.7'.
I am following Justing Michael's Tutorial,He is using lower Django version and its working on that.
Did Django change this thing?
class CartManager(models.Manager):
def new_or_get(self,request):
cart_id = request.session.get('cart_id')
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_cart(user = request.user)
new_obj = True
request.session['cart_id'] = cart_obj
return cart_obj,new_obj
def new_cart(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)
and the model actually is:
class Cart(models.Model):
user = models.ForeignKey(User,on_delete = models.CASCADE,null=True,blank=True)
products = models.ManyToManyField(Product,blank=True)
#more fields
and views.py is:
def cart_home(request):
cart_obj,new_obj = Cart.objects.new_or_get(request)
context={'cart':cart_obj}
return render(request,'carts/cart_home.html',context)
You can't send a Python class instance (such as a Model class instance) as a render data, you must send a json like object (a dict in Python).
So what you need is to convert cart_obj to a dict so it can be sent to the frontend through a render. The easiest way to do it with Django is to use a serializer (In your case, the best option is a ModelSerializer).
def cart_home(request):
cart_obj,new_obj = Cart.objects.new_or_get(request)
cart_obj_dict = CartSerializer(cart_obj).data
context={'cart':cart_obj_dict}
return render(request,'carts/cart_home.html',context)
I am sorry to disturb you guys,I had made an idiotic mistake:
request.session['cart_id'] = cart_obj
I was trying to assign cart object to session variable which was a typo ,instead in reality I should have done this:
request.session['cart_id'] = cart_obj.id
Credits: minglyu

Django sessions save only one object

I am building online store and want to use sessions to allow anonymous users to add items to carts before logging in .
trying to save the added items in session as a list but it saves only last object added to list
def cart(request):
user_id = request.user.id
cart_items =Cart.objects.all().filter(user_id=user_id, is_ordered=False)
ids = request.session.get('cart_id')
if ids:
for cart_id in ids:
if request.user.is_authenticated:
cart = Cart.objects.get(id=cart_id)
if cart:
cart.user = request.user
cart.save()
# get total prices
prices = []
for item in cart_items:
prices.append(item.item.price * item.qty)
total_price = sum(prices)
context = {
'items': cart_items,
'total_price': total_price
}
request.session['prices'] = prices
return render(request, 'cart.html', context)
def add_to_cart(request):
if request.user.is_authenticated:
item = Item.objects.get(pk=request.POST['item_id'])
cart = Cart.objects.filter(
user=request.user, item=item, is_ordered=False).first()
if cart:
cart.qty += 1
cart.save()
messages.success(request, 'item added to cart!')
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
else:
cart = Cart(user=request.user, item=item)
cart.save()
messages.success(request, 'item added to cart!')
else:
carts_ids = []
session_cart = request.session.get('cart_id')
item = Item.objects.get(pk=request.POST['item_id'])
if session_cart :
for cart in session_cart:
carts = Cart.objects.all().filter(id=cart, item=item)
if carts:
cart = carts.filter(item=item)[0]
print(cart.qty)
cart.qty += 1
cart.save()
else:
print('new cart')
new_cart = Cart(item=item)
new_cart.save()
carts_ids.append(new_cart.id)
request.session['cart_id'] = carts_ids
else:
print('new session')
new_cart = Cart(item=item)
new_cart.save()
carts_ids.append(new_cart.id)
request.session['cart_id'] = carts_ids
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
here are my models.py
and the full code on github i am only working now on these to views (cart and add_to_cart)
appriciate any help to get over this and to simplify my code :)
The idea would be that you save the whole cart in sessions so that you can reload it when the same user comes back to your website. So your code should look like this:
prices = []
itemlist=[]
for item in cart_items:
prices.append(item.item.price * item.qty)
itemlist.append(item.item, item.qty)
total_price = sum(prices)
context = {
'items': cart_items,
'total_price': total_price
}
request.session['items'] = itemlist
End then you also will need to read out this list.

Django: Cart matching query does not exist

I've a form that creates a Cart with the text "Random" in a character field, if there is not a Cart object created. This is only to get this recently object's id if it is not already created.
cart = Cart.objects.get(id=cart_id)
I get an error saying that this query generates an error, however I can see the value of cart_id as a cookie so the Query should execute without problem. But it doesn't according to the error message.
Exception Type: DoesNotExist
Exception Value: Cart matching query does not exist.
As you can see in my view, I'm using this:
cart_id = self.request.COOKIES.get('cart_id')
if not cart_id:
cart = Cart.objects.create(cart_id="Random")
cart_id = cart.id
cart = Cart.objects.get(id=cart_id)
To get the cookie cart_id if it does not exist I created a Cart object with the Random text, only to get it's ID.
Why I'm getting the error?
View.py:
class StepOneView(FormView):
form_class = StepOneForm
template_name = 'shop/medidas-cantidades.html'
success_url = 'subir-arte'
def get_initial(self):
# pre-populate form if someone goes back and forth between forms
initial = super(StepOneView, self).get_initial()
initial['size'] = self.request.session.get('size', None)
initial['quantity'] = self.request.session.get('quantity', None)
initial['product'] = Product.objects.get(
category__slug=self.kwargs['c_slug'],
slug=self.kwargs['product_slug']
)
return initial
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['product'] = Product.objects.get(
category__slug=self.kwargs['c_slug'],
slug=self.kwargs['product_slug']
)
return context
def form_invalid(self, form):
print('Step one: form is NOT valid')
def form_valid(self, form):
cart_id = self.request.COOKIES.get('cart_id')
if not cart_id:
cart = Cart.objects.create(cart_id="Random")
cart_id = cart.id
cart = Cart.objects.get(id=cart_id)
item = CartItem.objects.create(
size=form.cleaned_data.get('size'),
quantity=form.cleaned_data.get('quantity'),
product=Product.objects.get(
category__slug=self.kwargs['c_slug'],
slug=self.kwargs['product_slug']
),
cart=cart
)
response = HttpResponseRedirect(self.get_success_url())
response.set_cookie("cart_id", cart_id)
response.set_cookie("item_id", item.id)
return response
models.py:
class Cart(models.Model):
cart_id = models.CharField(max_length=100)
date_added = models.DateField(auto_now_add=True)
class Meta:
db_table = 'Cart'
ordering = ['date_added']
def __str__(self):
return str(self.id)
Try this:
def form_valid(self, form):
cart_id = self.request.COOKIES.get('cart_id')
if cart_id:
try:
cart = Cart.objects.get(id=cart_id)
except ObjectDoesNotExist:
# supplied ID doesn't match a Cart from your BD
cart = Cart.objects.create(cart_id="Random")
else:
cart = Cart.objects.create(cart_id="Random")
No need to create the Cart objects, just to get its ID and they hit the DB again to retrieve the same instance.
The idea is:
Do you have cart_id on session cookies? If so, try to get the Cart object based on it.
If that fails, it means that the supplied cart_id doesn't match an object from your DB
If no cart_id on session cookies, then simply create your new Cart object.

modifying request session in django

this code is from djagno 2 by example book
which is very helpful by the way. the question here is how we managed to modify the request session although we didn't modify it except in save method ((( and it's on the session of the cart which in the first line after init)))
what i see is that we have made a copy from the session dictionary at this line
self.session = request.session
class Cart(object):
def __init__(self, request):
self.session = request.session
cart = self.session.get(settings.CART_SESSION_ID)
if not cart:
cart = self.session[settings.CART_SESSION_ID] = {}
self.cart = cart
def add(self, product, quantity=1, update_quantity=False):
'''
Add a product to the cart or update it is quantity
'''
product_id = product.id
if not product_id in self.cart:
self.cart[product_id] = {'quantity': 0,
'price': str(product.price)}
if update_quantity:
self.cart[product_id]['quantity'] = quantity
else:
self.cart[product_id]['quantity'] += quantity
self.save()
def save(self):
self.session['modified'] = True
for more clarification you can find the whole code of the project here
code
i managed to see the user session as I passed it from the context to the template and it's already modified
This line does not make a copy:
self.session = request.session
The session in the Cart instance is the request session. self.cart is a dictionary in that session, so all changes to it are written directly to the session. Then when save is called the modified flag is set.

Django cart not updating quantity

Hello I am working on my ecommerce django tutorial and for some reason my simple cart count is not working. Everytime I add to the cart the {{cart_item_count}} in my cart.html is 0
Also in relation to this code the book has my carts.py as cart.py but since the app is cart for some reason is doesnt like this so I renames my cart.py "carts.py" and did this
from cart import carts as cart
Does Django not allow a py file the same name as the app???
To help with the code
carts.py has a function def cart_disinct_item_count(request) which returns the count which is called in my views.py to set the variable "cart_item_count " which is displayed in my cart.html page but currently no matter what my form has is returns 0.
I didnt post the entire project code but I think I got all the related information needed.
Thanks
cart.html
{% block content %}
<h1>Cart Page Here</h1>
Cart item count: {{cart_item_count }}
{% endblock %}
cart views.py
# Create your views here.
from django.shortcuts import render_to_response
from django.template import RequestContext
from cart import carts as cart
def show_cart(request, template_name="cart/cart.html"):
cart_item_count = cart.cart_disinct_item_count(request)
page_title = 'Shopping Cart'
return render_to_response("cart/cart.html", locals(),
context_instance = RequestContext(request))
cart item model
class CartItem(models.Model):
cart_id = models.CharField(max_length=50)
date_added = models.DateTimeField(auto_now_add = True)
quantity = models.IntegerField(default = 1)
product = models.ForeignKey('catalog.Product', unique = False)
class Meta:
app_label = ''
db_table = 'cart_items'
ordering = ['date_added']
def total(self):
return self.quantity * self.product.price
def name(self):
return self.product.name
def price(self):
return self.product.price
def get_absolute_url(self):
return self.product.get_absolute_url()
def augment_quantity(self, quantity):
""" called when a POST request comes in for a Product instance already in the shopping cart """
self.quantity = self.quantity + int(quantity)
self.save()
carts.py
def get_cart_items(request):
return CartItem.objects.filter(cart_id=_cart_id(request))
#add an item to the cart
def add_to_cart(request):
postdata = request.POST.copy()
#get product slug from post data, return blank if empty
product_slug = postdata.get('product_slug', '')
#get quantity added, return 1 if empty
quantity = postdata.get('quantity', 1)
#fetch the product or return a missing page error
p = get_object_or_404(Product, slug = product_slug)
#get products in cart
cart_products = get_cart_items(request)
product_in_cart = False
#check to see if item is already in cart
for cart_item in cart_products:
if cart_item.product.id == p.id:
#update the quantity if found
cart_item.augment_quantity(quantity)
product_in_cart = True
if not product_in_cart:
#create and save a new cart item
ci = CartItem()
ci.product = p
ci.quantity = quantity
ci.cart_id = _cart_id(request)
ci.save()
#returns the total number of items in the user's cart
def cart_disinct_item_count(request):
return get_cart_items(request).count()
forms.py:
class ProductAddToCartForm(forms.Form):
quantity = forms.IntegerField(widget=forms.TextInput(attrs={'size':'2',
'value':'1', 'class':'quantity'}),
error_messages={'invalid': 'Please enter a valid quantity'},
min_value = 1)
product_slug = forms.CharField(widget = forms.HiddenInput())
#override the default __init__ so we can set the request
def __init__(self, request = None, *args, **kwargs):
self.request = request
super(ProductAddToCartForm, self).__init__(*args, **kwargs)
*EDIT**
forgot to add the view that shows the product and calls add_to_cart:
#new product view, with POST vs GET detection
def show_product(request, product_slug, template_name = "catalog/product.html"):
p = get_object_or_404(Product, slug=product_slug)
categories = p.categories.all()
page_title = p.name
meta_keywords = p.meta_keywords
meta_description = p.meta_description
#need to evaluate the HTTP method
if request.method == 'POST':
#add to cart....create the bound form
postdata = request.POST.copy()
form = ProductAddToCartForm(request, postdata)
#check if posted data is valid
if form.is_valid():
#add to cart and redirect to cart page
cart.add_to_cart(request)
# if test cookie worked, get rid of it
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
url = urlresolvers.reverse('show_cart')
return HttpResponseRedirect(url)
else:
# it's a GET, create the unbound form. Note request as a kwarg
form = ProductAddToCartForm(request = request, label_suffix = ':')
#assign the hidden input the product slug
form.fields['product_slug'].widget.attrs['value'] = product_slug
#set the test cookie on our first GET request
request.session.set_test_cookie()
return render_to_response("catalog/product.html", locals(), context_instance=RequestContext(request))
Found the error :) Indentation issues (stupid python) j/k first one is mine and second one is the correct one. Gotta get use to this. Was easy to overlook to the untrained eye....
def add_to_cart(request):
postdata = request.POST.copy()
product_slug = postdata.get('product_slug', '')
quantity = postdata.get('quantity', 1)
p = get_object_or_404(Product, slug = product_slug)
cart_products = get_cart_items(request)
product_in_cart = False
for cart_item in cart_products:
if cart_item.product.id == p.id:
cart_item.augment_quantity(quantity)
product_in_cart = True
if not product_in_cart:
ci = CartItem()
ci.product = p
ci.quantity = quantity
ci.cart_id = _cart_id(request)
ci.save()
Here is the books and it works:
def add_to_cart(request):
postdata = request.POST.copy()
product_slug = postdata.get('product_slug','')
quantity = postdata.get('quantity',1)
p = get_object_or_404(Product, slug=product_slug)
cart_products = get_cart_items(request)
product_in_cart = False
for cart_item in cart_products:
if cart_item.product.id == p.id:
cart_item.augment_quantity(quantity)
product_in_cart = True
if not product_in_cart:
ci = CartItem()
ci.product = p
ci.quantity = quantity
ci.cart_id = _cart_id(request)
ci.save()