Reputation: 145
I am trying to make an e-commerce website where the "AnonymousUser" or Guest user can order and check out items without the need to login or make their accounts.
What I want to do is throw the name and email that was entered in check out form to the database. But it always returned blank in the Customer
Table. And after making the payment, there was an error that says AttributeError: 'tuple' object has no attribute 'name'
Here's the full traceback in Terminal:
Internal Server Error: /process_order/
Traceback (most recent call last):
File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\RolfShin025\Desktop\E-COMMERCE\WannaCome\store\views.py", line 82, in processOrder
customer.name = name
AttributeError: 'tuple' object has no attribute 'name'
I also have some error in the console that says: `POST http://127.0.0.1:8000/process_order/ 500 (Internal Server Error)` and `Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0`
Here's my models.py file:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=9, decimal_places=2)
digital = models.BooleanField(default=False, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
def __str__(self):
return self.name
@property
def imageURL(self):
try:
url = self.image.url
except:
url = ''
return url
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=20, null=True)
def __str__(self):
return str(self.id)
@property
def shipping(self):
shipping = False
orderitems = self.orderitem_set.all()
for i in orderitems:
if i.product.digital == False:
shipping = True
return shipping
@property
def get_cart_total(self):
orderitems = self.orderitem_set.all()
total = sum([item.get_total for item in orderitems])
return total
@property
def get_cart_items(self):
orderitems = self.orderitem_set.all()
total = sum([item.quantity for item in orderitems])
return total
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
@property
def get_total(self):
total = self.product.price * self.quantity
return total
class ShippingAddress(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
address = models.CharField(max_length=200, null=False)
city = models.CharField(max_length=200, null=False)
state = models.CharField(max_length=200, null=False)
zip = models.CharField(max_length=200, null=False)
date_added = models.DateTimeField(auto_now_add=True)
Here's my views.py:
from django.http import JsonResponse
from django.shortcuts import render
from .models import *
import json
import datetime
from .utils import cookieCart, cartData, guestOrder
def store(request):
data = cartData(request)
cartItems = data['cartItems']
products = Product.objects.all()
context = {'products':products, 'cartItems': cartItems}
return render(request, 'store/store.html', context)
def cart(request):
data = cartData(request)
cartItems = data['cartItems']
order = data['order']
items = data['items']
context = {'items':items, 'order':order, 'cartItems': cartItems}
return render(request, 'store/cart.html', context)
def checkout(request):
data = cartData(request)
cartItems = data['cartItems']
order = data['order']
items = data['items']
context = {'items':items, 'order':order, 'cartItems': cartItems}
return render(request, 'store/checkout.html', context)
def updateItem(request):
data = json.loads(request.body)
productId = data['productId']
action = data['action']
print('Action:', action)
print('Product:', productId)
customer = request.user.customer
product = Product.objects.get(id=productId)
order, created = Order.objects.get_or_create(customer=customer, complete=False)
orderItem, created = OrderItem.objects.get_or_create(order=order, product=product)
if action == 'add':
orderItem.quantity = (orderItem.quantity + 1)
elif action == 'remove':
orderItem.quantity = (orderItem.quantity - 1)
orderItem.save()
if orderItem.quantity <= 0:
orderItem.delete()
return JsonResponse('Item was added', safe=False)
def processOrder(request):
transaction_id = datetime.datetime.now().timestamp()
data = json.loads(request.body)
if request.user.is_authenticated:
customer = request.user.customer
order, created = Order.objects.get_or_create(customer=customer, complete=False)
else:
print('User is not logged in...')
print('COOKIES:', request.COOKIES)
name = data['form']['name']
email = data['form']['email']
cookieData = cookieCart(request)
items = cookieData['items']
customer = Customer.objects.get_or_create(
email=email,
)
customer.name = name
customer.save()
order = Order.objects.create(
customer=customer,
complete=False,
)
for item in items:
product=Product.objects.get(id=item['product']['id'])
orderItem = OrderItem.objects.create(
product=product,
order=order,
quantity=item['quantity']
)
total = float(data['form']['total'])
order.transaction_id = transaction_id
if total == order.get_cart_total:
order.complete = True
order.save()
if order.shipping == True:
ShippingAddress.objects.create(
customer=customer,
order=order,
address=data['shipping']['address'],
city=data['shipping']['city'],
state=data['shipping']['state'],
zip=data['shipping']['zip'],
)
return JsonResponse('Payment complete!', safe=False)
def __str__(self):
return self.address
Here's my utils.py file:
import json
from .models import *
def cookieCart(request):
try:
cart = json.loads(request.COOKIES['cart'])
except:
cart = {}
print('Cart:', cart)
items = []
order = {'get_cart_total':0, 'get_cart_items':0, 'shipping': False}
cartItems = order['get_cart_items']
for i in cart:
try:
cartItems += cart[i]["quantity"]
product = Product.objects.get(id=i)
total = (product.price * cart[i]['quantity'])
order['get_cart_total'] += total
order['get_cart_items'] += cart[i]['quantity']
item = {
'product':{
'id':product.id,
'name':product.name,
'price':product.price,
'imageURL':product.imageURL,
},
'quantity': cart[i]['quantity'],
'get_total': total,
}
items.append(item)
if product.digital == False:
order['shipping'] = True
except:
pass
return {'cartItems': cartItems, 'order': order, 'items': items}
def cartData(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created = Order.objects.get_or_create(customer=customer, complete=False)
items = order.orderitem_set.all()
cartItems = order.get_cart_items
else:
cookieData = cookieCart(request)
cartItems = cookieData['cartItems']
order = cookieData['order']
items = cookieData['items']
return {'cartItems': cartItems, 'order': order, 'items': items}
And here's my checkout.html file:
{% extends 'store/main.html' %}
{% load static %}
{% block content %}
<div class="row">
<div class="col-lg-6">
<div class="box-element" id="form-wrapper">
<form id="form">
<div id="user-info">
<div class="form-field">
<input required class="form-control" type="text" name="name" placeholder="Name..">
</div>
<div class="form-field">
<input required class="form-control" type="email" name="email" placeholder="Email..">
</div>
</div>
<div id="shipping-info">
<hr>
<p>Shipping Information:</p>
<hr>
<div class="form-field">
<input class="form-control" type="text" name="address" placeholder="Address..">
</div>
<div class="form-field">
<input class="form-control" type="text" name="city" placeholder="City..">
</div>
<div class="form-field">
<input class="form-control" type="text" name="state" placeholder="State..">
</div>
<div class="form-field">
<input class="form-control" type="text" name="zip" placeholder="zip code..">
</div>
</div>
<hr>
<input id="form-button" class="btn btn-success btn-block" type="submit" value="Continue">
</form>
</div>
<br>
<div class="box-element hidden" id="payment-info">
<small>Paypal Options</small>
<button id="make-payment">Make Payment</button>
</div>
</div>
<div class="col-lg-6">
<div class="box-element">
<a class="btn btn-outline-dark" href="{% url 'cart' %}">← Back to Cart</a>
<hr>
<h3>Order Summary</h3>
<hr>
{% for item in items %}
<div class="cart-row">
<div style="flex:2"><img class="row-image" src="{{item.product.imageURL}}"></div>
<div style="flex:2"><p>{{item.product.name}}</p></div>
<div style="flex:1"><p>₱{{item.product.price|floatformat:2}}</p></div>
<div style="flex:1"><p>x{{item.quantity}}</p></div>
</div>
{% endfor %}
<h5>Items: {{order.get_cart_items}}</h5>
<h5>Total: ₱{{order.get_cart_total|floatformat:2}}</h5>
</div>
</div>
</div>
<script type="text/javascript">
var shipping = '{{order.shipping}}'
var user = '{{request.user.is_authenticated}}'
var total = '{{order.get_cart_total|floatformat:2}}'
if(shipping == 'False'){
document.getElementById('shipping-info').innerHTML = ''
}
if (user == "True"){
document.getElementById('user-info').innerHTML = ''
}
if (shipping == 'False' && user == "True"){
//Hide entire form if user is logged in and shipping is false
document.getElementById('form-wrapper').classList.add('hidden');
//Show payment if logged in user wants to buy an item that does not require shipping
document.getElementById('payment-info').classList.remove('hidden');
}
var form = document.getElementById('form')
form.addEventListener('submit', function(e){
e.preventDefault()
console.log('Form Submitted...')
document.getElementById('form-button').classList.add("hidden");
document.getElementById('payment-info').classList.remove("hidden");
})
document.getElementById('make-payment').addEventListener('click', function(e){
submitFormData()
})
function submitFormData(){
console.log('Payment button clicked')
var userFormData = {
'name':null,
'email':null,
'total':total,
}
var shippingInfo = {
'address':null,
'city':null,
'state':null,
'zip':null,
}
if (shipping != 'False'){
shippingInfo.address = form.address.value
shippingInfo.city = form.city.value
shippingInfo.state = form.state.value
shippingInfo.zip = form.zip.value
}
if (user == 'False'){
userFormData.name = form.name.value
userFormData.email = form.email.value
}
var url = '/process_order/'
fetch(url,{
method:'POST',
headers:{
'Content-Type':'application/json',
'X-CSRFToken':csrftoken,
},
body:JSON.stringify({'form':userFormData, 'shipping':shippingInfo})
})
.then((response) => response.json())
.then((data) => {
console.log('Success:', data);
alert('Transaction Completed');
cart ={}
document.cookie = 'cart=' + JSON.stringify(cart) + ";domain=;path=/"
window.location.href = "{% url 'store' %}"
})
}
</script>
{% endblock content %}
Upvotes: 2
Views: 2885
Reputation: 2573
Note that get_or_create() return a tuple:the instance and a boolean that indicates whether the object has been created or not
.
here what i did is that i check if the customer has been created or not.if it is not then i add name and save it.That's it
customer,created = Customer.objects.get_or_create(
email=email,
)
if not created:
customer.name = name
customer.save()
Upvotes: 4