Having issue in handling multipart form data in django rest framework
Asked Answered
M

0

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
Multiracial answered 16/6, 2021 at 12:32 Comment(6)
Add please full code of the AddProductSerializer serializer.Essieessinger
I have updated the code @monio Please have a look at itMultiracial
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) `Essieessinger
@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 sideMultiracial
That solution would be harder because you need to make your own version of parser class in that case.Essieessinger
How did you solve it. I have a similar question #74193126Crittenden

© 2022 - 2024 — McMap. All rights reserved.