Home > database >  Error in making POST request to django API
Error in making POST request to django API

Time:06-15

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'])
            ...
  • Related