1

I have an addproduct api in which frontend is sending a multipart/formdata in a post axios call. multipart/form-data is used because there is an image field that needs to be sent in arrays.

But I got the following error.

Category field is required

The data is sent like this

name: Soap
category[0]: 7
category[1]: 23
brand: 7
collection: 11
availability: in_stock
warranty: no_warranty
service: cash_on_delivery
rating: 3
best_seller: true
top_rated: true
featured: true
main_product_image: (binary)
merchant: 2
variants[0][product_id]: fgfdg
variants[0][price]: 127
variants[0][quantity]: 1
variants[0][color]: red
variants[0][size]: M
variants[0][variant_availability]: not_available
variants[0][variant_image]: (binary)
variants[1][product_id]: fgfdg
variants[1][price]: 127
variants[1][quantity]: 1
variants[1][color]: red
variants[1][size]: M
variants[1][variant_availability]: not_available
variants[1][variant_image]: (binary)

The same issue is with the variants.

My models:

class Variants(models.Model):
    product_id = models.CharField(max_length=70, default='OAXWRTZ_12C',blank=True)
    price = models.DecimalField(decimal_places=2, max_digits=20,default=500)
    size = models.CharField(max_length=50, choices=SIZE, default='not applicable',blank=True,null=True)
    color = models.CharField(max_length=70, default="not applicable",blank=True,null=True)
    variant_image = models.ImageField(upload_to="products/images", blank=True,null=True)
    thumbnail = ImageSpecField(source='variant_image',
                               processors=[ResizeToFill(100, 50)],
                               format='JPEG',
                               options={'quality': 60})
    quantity = models.IntegerField(default=10,blank=True,null=True)  # available quantity of given product
    variant_availability = models.CharField(max_length=70, choices=AVAILABILITY, default='available')

    class Meta:
        verbose_name_plural = "Variants"

    def __str__(self):
        return self.product_id

#Product Model

class Product(models.Model):
   
    merchant = models.ForeignKey(Seller,on_delete=models.CASCADE,blank=True,null=True)
    category = models.ManyToManyField(Category, blank=False)
    sub_category = models.ForeignKey(Subcategory, on_delete=models.CASCADE,blank=True,null=True)
    brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
    collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
    featured = models.BooleanField(default=False)  # is product featured?
    best_seller = models.BooleanField(default=False)
    top_rated = models.BooleanField(default=False)
    tags = TaggableManager(blank=True)  # tags mechanism
    name = models.CharField(max_length=150,unique=True)
    main_product_image = models.ImageField(upload_to="products/images", null=True, blank=True)
    thumbnail = ImageSpecField(source='main_product_image',
                               processors=[ResizeToFill(100, 50)],
                               format='JPEG',
                               options={'quality': 60})
    slug = models.SlugField(max_length=200,blank=True)       
    description = RichTextField(blank=True)
    #picture = models.ImageField(upload_to="products/images", null=True, blank=True)
    picture = models.ManyToManyField(ImageBucket,null=True,blank=True,verbose_name="Add extra 3 images")
    rating = models.IntegerField(choices=((1, 1),
                                               (2, 2),
                                               (3, 3),
                                               (4, 4),
                                               (5, 5))
                                      )
    availability = models.CharField(max_length=70, choices=AVAILABILITY, default='in_stock')
    warranty = models.CharField(max_length=100, choices=WARRANTY, default='no_warranty')
    services = models.CharField(max_length=100, choices=SERVICES, default='cash_on_delivery')
    variants = models.ManyToManyField(Variants,related_name='products')

My view:

class ProductAddAPIView(CreateAPIView):
    permission_classes = [IsAuthenticated]
    parser_classes = [MultiPartParser,JSONParser,FormParser]
    # queryset = Product.objects.all()
    serializer_class = AddProductSerializer

Here I have used parser class just in case if it works.

Updated Code:

class  AddProductSerializer(serializers.ModelSerializer):
    id = serializers.PrimaryKeyRelatedField(read_only=True)
    variants = VariantSerializer(many=True)
    slug = serializers.SlugField(read_only=True)
    
    class Meta:
        model = Product
        fields = ['id','merchant','featured', 'top_rated','category','brand','collection','sub_category',
                  'name','slug','description', 'main_product_image','best_seller','picture',
                  'rating','availability','warranty','services','variants']
        #depth = 1

    def create(self, validated_data):
         #user = self.context['request'].user

         picture_data = validated_data.get('picture')

         merchant = validated_data.get('merchant')

         category_data = validated_data.get('category')

         featured = validated_data.get('featured')

         top_rated = validated_data.get('top_rated')
         brand = validated_data.get('brand')
         collection = validated_data.get('collection')
         sub_category = validated_data.get('sub_category')
         name = validated_data.get('name')
         description = validated_data.get('description')
         main_product_image = validated_data.get('main_product_image')
         best_seller = validated_data.get('best_seller')
         rating = validated_data.get('rating')
         availability = validated_data.get('availability')
         warranty = validated_data.get('warranty')
         services = validated_data.get('services')

        #variants_logic


         variants_data = validated_data.get('variants')
         #breakpoint()
         print(variants_data)


         # from pudb import set_trace;set_trace()

         #products-logic

         product = Product.objects.create(featured=featured,top_rated=top_rated,
                                          brand=brand,collection=collection,sub_category=sub_category,
                                          name=name,description=description,
                                          main_product_image=main_product_image,
                                          best_seller=best_seller,rating=rating,
                                          availability=availability,warranty=warranty,
                                          services=services,merchant=merchant)
         product.save()


         product.category.set(category_data)             

         # product.variants.set(variants_data)
         product.save()
         for variants_data in variants_data:
             abc = Variants.objects.create(**variants_data)
             product.variants.add(abc)

         product.save()
         return product
6
  • Add please full code of the AddProductSerializer serializer. Commented Jun 16, 2021 at 19:41
  • I have updated the code @monio Please have a look at it Commented Jun 17, 2021 at 6:20
  • Try to remove brackets index in form data eg. category[]: 7, category[]: 23. Anywany when you use js FormData object, you should append values to category key. ` let data = new FormData() data.append('category', 7) data.append('category', 23) ` Commented Jun 17, 2021 at 17:21
  • @monio thanks for reply, i really appreciate it. but is there anyway it can be handled from backend?? seems like you are trying it from the frontend side Commented Jun 17, 2021 at 18:07
  • 1
    That solution would be harder because you need to make your own version of parser class in that case. Commented Jun 18, 2021 at 9:46

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.