Learning Django with Tutorial.
In the end of lesson I have error:
AttributeError: 'Order' object has no attribute 'shipping'.
I can't understand what's wrong.
Error in PyCharm Terminal
I understand that Order must have shipping attribute, but cant find where exactly looking that.
Sorry for bad english.
My project files:
checkout.html
from django.db import models
from django.contrib.auth.models import User
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, null=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField()
digital = models.BooleanField(default=False, null=True, blank=False)
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.SET_NULL, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
def __str__(self):
return str(self.id)
#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_addet = 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)
zipcode = models.CharField(max_length=200, null=False)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.address
views.py
from django.shortcuts import render
from django.http import JsonResponse
import json
import datetime
from .models import *
def store(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:
items = []
order = {'get_cart_total':0, 'get_cart_items':0, 'shipping':False}
cartItems = order['get_cart_items']
products = Product.objects.all()
context = {'products':products, 'cartItems':cartItems}
return render(request, 'store/store.html', context)
def cart(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:
items = []
order = {'get_cart_total':0, 'get_cart_items':0, 'shipping':False}
cartItems = order['get_cart_items']
context = {'items':items, 'order':order, 'cartItems':cartItems}
return render(request, 'store/cart.html', context)
def checkout(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:
items = []
order = {'get_cart_total':0, 'get_cart_items':0, 'shipping':False}
cartItems = order['get_cart_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('productId', 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)
total = float(data['form']['total'])
order.transaction_id = transaction_id
if total == float(order.get_cart_total):
order.complete = True
order.save()
if order.shipping == True:
ShippingAddress.objects.create(
customer=customer,
order=order,
address=data['shipping']['address'], #порядок как в models
city=data['shipping']['city'],
state=data['shipping']['state'],
zipcode=data['shipping']['zipcode'],
)
else:
print('User is not logged in...')
return JsonResponse('Payment complete!', safe=False)
models.py
from django.db import models
from django.contrib.auth.models import User
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, null=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField()
digital = models.BooleanField(default=False, null=True, blank=False)
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.SET_NULL, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
def __str__(self):
return str(self.id)
#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_addet = 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)
zipcode = models.CharField(max_length=200, null=False)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.address
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.store, name="store"),
path('cart/', views.cart, name="cart"),
path('checkout/', views.checkout, name="checkout"),
path('update_item/', views.updateItem, name="update_item"),
path('process_order/', views.processOrder, name="process_order"),
]
I reviewed the lesson several times, code seems to be without mistakes.
Server side error
The error is because you didn't declared shipping variable in your Orders model.
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
shipping = models.CharField(max_length=200, null=True)
def __str__(self):
return str(self.id)
#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
Go to models file and update the Order class with above code.
client side
While making API request set the header Content-Type to text/html.
Because the API is responding HTML file not json.
That's why you have an error in browser.
in Order model there should be a field named shipping which is require in the processorder view.
just add below field in Order model
shipping = models.BooleanField(default=False)
since you want ot hide it , then a property need to be added not the db field
so your model should look like this
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
date_ordered = models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
#property
def shipping(self):
shipping = False
# add shipping logic here
return shipping
def __str__(self):
return str(self.id)
#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
follow the tutorial a little more, you will be able to grasp the solution.
I'm getting __ str __ returned non-string (type Product) when I try to add OrderItem in my Django project
models.py:
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
date_ordered = models.DateField(auto_now_add=True, blank=True, null=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
def __str__(self):
return self.transaction_id
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
order = models.ForeignKey(Order, on_delete=models.CASCADE)
def __str__(self):
return self.product
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField()
image = models.ImageField(null=True, blank=True)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return str(self.name)
#property
def imageUrl(self):
try:
url = self.image.url
except:
url =''
return url
admin.py:
admin.site.register(Customer)
admin.site.register(Product)
admin.site.register(Order)
admin.site.register(Tag)
admin.site.register(OrderItem)
I get the same error when I try this:
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField()
image = models.ImageField(null=True, blank=True)
tag = models.ForeignKey(Tag, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return 'test'
Sometimes I get this error when I try to add/delete items (in Orders, OrderItems, Products)
The problem is not the __str__ method of the Product class, but the __str__ method of the OrderItem class. self.product is not a string, but a Product object, so you can not return this in the __str__ method. You can for example return the str(…) of the product:
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
order = models.ForeignKey(Order, on_delete=models.CASCADE)
def __str__(self):
return str(self.product)
I want to find the difference between quantity of Product class and sold_quantity of Stock class. How do I do that
models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=100)
slug = models.CharField(max_length=100)
price = models.DecimalField(max_digits=6, decimal_places=2)
quantity = models.IntegerField(null=True, blank=True)
category = models.ForeignKey(
Category, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return self.name
class Stock(models.Model):
sold_quantity = models.IntegerField(null=True, blank=True)
product = models.ForeignKey(Product, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.product.name
For one instance you can do this by:
Example: id=1
product_instance = Product.objects.get(id=1)
quantity_difference = product_instance.quantity - product_instance.stock.sold_quantity
Note: This assumes the relationship is coupled between models.
I want to get each product's total price in all orders which I mean how much each product sold in all orders. What Query should I write in views.py to display this matter in html?
this is my models.py:
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField(null=True)
description = models.CharField(max_length=200, null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return self.name
class Order(models.Model):
STATUS = (
('Pending', 'Pending'),
('Shipping', 'Shipping'),
('Delivered', 'Delivered'),
)
# order will remain after customer deleted
customer = models.ForeignKey(Customer, null=True, on_delete=models.SET_NULL)
product = models.ForeignKey(Product, null=True, on_delete=models.SET_NULL)
date_created = models.DateTimeField(auto_now_add=True, null=True)
status = models.CharField(max_length=200, null=True, choices=STATUS)
note = models.CharField(max_length=200, null=True)
def __str__(self):
return self.product.name
and this is my views.py:
def home(request):
products = Product.objects.all()
orders = Order.objects.all()
total_order_prices = Order.objects.aggregate(Sum('price'))
orders.products = Product.objects.all().aggregate(Sum('price'))
context = {'orders':orders, 'products':products,'total_order_prices': total_order_prices }
return render(request, 'account/home.html', context)
Morez!
What I recommend is defining a foreign key to Order() in the Product(). Doing so would allow you to get related objects much more easily, as shown here.
All you would have to do is products = order.product_set.
Hope it helps!
I'm trying to create a shopping cart model, I've created the Order Model, OrderItem model and Also the Item model. Although I find it difficult to link the order it model to the order in the API view.
here's the Model
class Pizza(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=60)
desc = models.CharField(max_length=150)
price = models.IntegerField()
url = models.CharField(max_length=250)
def __str__(self):
return self.name
class OrderItem(models.Model):
id = models.AutoField(primary_key=True)
product = models.ForeignKey("Pizza", on_delete=models.CASCADE, null=True)
date_added = models.DateTimeField(auto_now=True)
date_ordered = models.DateTimeField(null=True)
amount = models.IntegerField(null=True)
def __str__(self):
return self.product.name
class Order(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=60)
email = models.CharField(max_length=150)
address = models.CharField(max_length=150)
total = models.IntegerField()
created_at = models.DateTimeField(default=timezone.now)
items = models.ManyToManyField(OrderItem)
def __str__(self):
return self.name
//The viewset
class OrderViewSet(viewsets.HyperlinkedModelSerializer):
# permission_classes = [IsPostOrIsAuthenticated,]
serializer_class = OrderSerializer
queryset = Order.objects.all().order_by('-created_at')
Currently, I cant display the amount attribute of the order item in my API, It just shows the id and Also the link to the individual orderitem in an order
I think for cart you can use external fields on relations between Order and Pizza. Documentation about this here
Your models looks like:
class Pizza(models.Model):
name = models.CharField(max_length=60)
desc = models.CharField(max_length=150)
price = models.IntegerField()
url = models.CharField(max_length=250)
def __str__(self):
return self.name
class Order(models.Model):
name = models.CharField(max_length=60)
email = models.CharField(max_length=150)
address = models.CharField(max_length=150)
total = models.IntegerField()
created_at = models.DateTimeField(auto_now=True)
items = models.ManyToManyField(Pizza, through='OrderItem')
def __str__(self):
return self.name
class OrderItem(models.Model):
product = models.ForeignKey('Pizza', on_delete=models.CASCADE, null=True)
order = models.ForeignKey('Order', on_delete=models.CASCADE, null=True)
date_added = models.DateTimeField(auto_now=True)
date_ordered = models.DateTimeField(null=True)
amount = models.IntegerField(null=True)
def __str__(self):
return self.product.name
Example, how you can get dict of items amount in order:
order = Order.objects.filter('-created_at').first() // get last order
cart = {item.pk: item.amount for item in order.items}