From post man, I'm trying to make POST request to an order API created using django restframework but I'm getting the following error:
product = Product.objects.get(id=i['product'])
TypeError: string indices must be integers
The specific point where the error is located is specified in the error but I find difficulty constructing VALID json for the request body. Here is how I'm making the request on postman:
{
"orderItems":{
"product": {"name":"abc", "brand":"def", "image"www.example.com/img", "description":"xyz", "price":"50"},
"qty":"2",
"price":"200"
},
"shippingAddress": {
"address":"abc", "city":"B", "postalCode":"12345",
},
"paymentMethod":"monify",
"itemPrice":"100"
}
Here is the program:
class Product(models.Model):
category = models.CharField(max_length=50, choices=Categories.choices, default=Categories.medications)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="user_product", null=True)
name = models.CharField(max_length=150)
brand = models.CharField(max_length=255, default="brand")
productClass = models.CharField(max_length=50, null=True, blank=True)
image = models.ImageField(upload_to="images/products/")
label = models.CharField(max_length=254, default='', blank=True, null=True)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
stock = models.IntegerField(null=True, blank=True, default=0)
dateCreated = models.DateTimeField(auto_now_add=True)
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="user_order", null=True)
paymentMethod = models.CharField(max_length=200, null=True, blank=True)
dateCreated = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.dateCreated)
models.py
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
image = models.CharField(max_length=200, null=True, blank=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=200, null=True, blank=True)
qty = models.IntegerField(null=True, blank=True, default=0)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
def __str__(self):
return str(self.name)
The view I', trying to test is shown below:
def addOrderItems(request):
user = request.user
data = request.data
orderItems = data['orderItems']
if orderItems and len(orderItems) == 0:
return Response({'detail': 'Order item was not provided'}, status=status.HTTP_400_BAD_REQUEST)
else:
# Step 1: Create order
order = Order.objects.create(
user=user,
paymentMethod=data['paymentMethod'],
)
#Step 2: Create shipping address
shipping = ShippingAddress.objects.create(
order=order,
address=data['shippingAddress']['address'],
)
# Step 3: Create order items, then set order to orderItem relationship
for i in orderItems:
product = Product.objects.get(id=i['product'])
item = OrderItem.objects.create(
product=product,
order=order,
name=product.name,
qty=i['qty'],
price=i['price'],
image=product.image.url,
)
# Step 4: Update stock
product.countInStock -= item.qty
product.save()
serializer = OrderSerializer(order, many=False)
return Response(serializer.data)
Any hint on this is well appreciated
CodePudding user response:
Your JSON is invalid (the "image" key in "orderItems" was messed up). To check this, you can use an online tool like https://jsonformatter.curiousconcept.com/.
Moreover, from the way you are iterating over it, orderItems should contain a list.
Here is the corrected JSON:
{
"orderItems": [{
"product": {"name":"abc", "brand":"def", "image": "www.example.com/img", "description":"xyz", "price":"50"},
"qty":"2",
"price":"200"
}],
"shippingAddress": {
"address":"abc", "city":"B", "postalCode":"12345",
},
"paymentMethod":"monify",
"itemPrice":"100"
}
In your Product model, you should also add an ID as PrimaryKey to be able to retrieve it later in your view:
import uuid
class Product(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# ... (all your other attributes)
The JSON will then include this product ID:
{
"orderItems": [{
"product": {"id": "9b84820b-1b4f-43a2-b576-14c3e1635906", "name":"abc", "brand":"def", "image": "www.example.com/img", "description":"xyz", "price":"50"},
"qty":"2",
"price":"200"
}],
"shippingAddress": {
"address":"abc", "city":"B", "postalCode":"12345",
},
"paymentMethod":"monify",
"itemPrice":"100"
}
Then the line product = Product.objects.get(id=i['product'])
should be replaced with:
product = Product.objects.get(id=i['product']['id'])
CodePudding user response:
I think the payload is not correct. Now the whole product data is uploaded, but it should be changed into the product_id
. Because in the view, it is being considered as the id field like Product.objects.get(id=i['product'])
.
So the solution is like the following. First, the payload should be changed.
{
"orderItems":{
"product_id": 3, // here I changed
"qty":"2",
"price":"200"
},
"shippingAddress": {
"address":"abc", "city":"B", "postalCode":"12345",
},
"paymentMethod":"monify",
"itemPrice":"100"
}
And in the addOrderItems
function,
def addOrderItems(request):
...
if orderItems and len(orderItems) == 0:
...
else:
...
# Step 3: Create order items, then set order to orderItem relationship
for i in orderItems:
product = Product.objects.get(id=i['product_id'])
...