Reputation: 994
Sorry for the length (Thought the info was relevant), and thank you for helping understand how this works. I'm trying to use sessions and Django templates to add items to shopping cart. I'm fairly new to learning Django and have painstakingly read through a bunch of documentation and Stack Overflow problems that were similar. My data is saved to MySQL database(subject to change) like this:
sql_entry = {
'model': 'App.Product',
'pk': 1, # unique for each item
'fields': {
'Name': 'name',
'Price': 1.0,
'Quantity': 1
}
and my Model:
class Product(models.Model):
Name = models.CharField(max_length=200, default='')
Price = models.FloatField()
Quantity = models.IntegerField()
def __str__(self):
return self.Name
class Meta:
ordering = ['Name']
Because the actual products will change daily, I want to avoid hardcoding categories, and thought it would be better to only have data pertaining to what products are available. So I use Django's template to create a basic table view of each product with a button that would add it to the cart. I want to avoid any type of login for now. I read that sessions was the best way for unique customers to add items to the cart and save there data to my database. I believe my "add to cart" button needs to temporarily save their entry to my database somehow corresponding with their session ID. This is where I'm having a lot of trouble. In the following blocks of code, I am attempting to add an item to a sessions cart which should be unique to each browser. When I click the button, it redirects to the cart but nothing happens. If you could let me know how bad I have my settings configured that would be awesome. Here are views, cart template, and url patterns:
Sessions settings in views.py
def index(request):
response = render_to_response('buylist/Home.html')
visits = int(request.COOKIES.get('visits', '0'))
if 'last_visit' in request.COOKIES:
last_visit = request.COOKIES['last_visit']
last_visit_time = datetime.strptime(last_visit[:-7], "%Y-%m-%d %H:%M:%S")
if (datetime.now() - last_visit_time).days > 0:
response.set_cookie('visits', visits + 1)
response.set_cookie('last_visit', datetime.now())
else:
response.set_cookie('last_visit', datetime.now())
return response
add to cart function in views.py
# add Product to cart after button click
def add_to_cart(request, product_id):
cart = request.session.get('cart', {})
product = Product.objects.get(id=product_id)
cart[product_id] = product
request.session['cart'] = cart
return HttpResponseRedirect(reverse("cart"))
# Cart View
def get_cart(request):
cart = request.session.get('cart',{})
return render(request, 'buylist/cart.html', cart)
and here is the template and url patterns I have:
basic.html #Product product page that has button
{% for item in file %}
<tbody>
<tr>
<td>{{item.fields.Name}}</td>
<td>${{item.fields.Price}}</td>
<td>{{item.fields.Quantity}}</td>
<td>
<a href="http://127.0.0.1:8000/cart/{{item.id}}"><button>Add</button></a>
</td>
</tr>
</tbody>
{% endfor %}
Url Patterns in App.urls
path('cart/<int:product_id>/', views.add_to_cart, name='add'),
path('cart/', views.get_cart, name='cart'),
cart.html
<table>
<tr>
<center><h2>Shopping Cart</h2></center>
<th>Product|</th>
<th>Quantity|</th>
<th>Total Price</th>
</tr>
{% for item in cart %}
<tr>
<td>{{item}}</td>
</tr>
{% endfor %}
</table>
Upvotes: 2
Views: 2729
Reputation: 317
To update your cart do it like this. It will remove the product if added and add the product if not present in cart. BOTH FUNCTIONS. The product_id is coming from HTML form given in the end. It is that product which you want to add in your cart.
def cart_update(request):
p = request.POST.get("product_id")
if p is not None:
product_obj = Product.objects.get(id =p)
c,n = Cart.objects.get_or_new(request)
if product_obj not in c.products.all():
c.products.add(product_obj)
else:
c.products.remove(product_obj)
print("to be added")
return redirect("cart:home")
Cart model is
class Cart(models.Model):
user = models.ForeignKey(User, null = True, blank = True)
products = models.ManyToManyField(Product, blank= True)
subtotal = models.DecimalField(default = 0.00, max_digits= 12, decimal_places=2)
total = models.DecimalField(default = 0.00, max_digits= 12, 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 CartManager(models.Manager):
def get_or_new(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:
new_obj = True
cart_obj = Cart.objects.new_cart(user = request.user)
request.session['cart_id'] = cart_obj.id
return cart_obj, new_obj
Your HTML form
<h1>Your Cart</h1>
{% for a in cart.products.all %}
<form action="{% url "cart:update" %}" method="POST">{% csrf_token %}
<input type="hidden" name="product_id" value='{{a.id}}' placeholder="
{{a.id}}"/>
<h4>Your Product: <a href= '{{ a.get_absolute_url}}'>{{a.title}}</a><small>
<br><button type="submit">Remove?</button></small></h4>
<p>Price :
{{a.price}}</p>
</form>
{% endfor %}
<b>Subtotal: {{cart.subtotal}}</b><br>
Total: {{cart.total}}
<a href="{% url "cart:checkout" %}"> Checkout</a>
This is all you have to do. Read the code to understand it fully. It is a little trickier one. I have used the manager to make a new cart object if the user is new. Product model is your model in which you can add a lot of different products.
Upvotes: 1