Here I am trying to create an add-products API. The product model is related to Category,Brand, Collection, Picture, and Variants models.
Here Category, Picture, and Variants are M2M relationships with the Product model. From the frontend, all the chunks of data are sent at once to create a product object. I have added categories and pictures using .set()
method.
But for variants, I have to create variants objects first and then add them to product. How to do this. I tried but I got this error.
TypeError: 'Variants' object is not iterable
I am sending raw data like this.
My models:
class Variants(models.Model):
SIZE = (
('not applicable', 'not applicable',),
('S', 'Small',),
('M', 'Medium',),
('L', 'Large',),
('XL', 'Extra Large',),
)
AVAILABILITY = (
('available', 'Available',),
('not_available', 'Not Available',),
)
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)
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
class Product(models.Model):
merchant = models.ForeignKey(Seller,on_delete=models.CASCADE,blank=True,null=True)
category = models.ManyToManyField(Category, blank=False)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
featured = models.BooleanField(default=False) # is product featured?
variants = models.ManyToManyField(Variants,related_name='products')
My views:
class ProductAddAPIView(CreateAPIView):
permission_classes = [AllowAny]
queryset = Product.objects.all()
serializer_class = AddProductSerializer
My serializers:
class AddProductSerializer(serializers.ModelSerializer):
variants = VariantSerializer(many=True)
class Meta:
model = Product
fields = ['merchant','featured', 'top_rated','category','brand','collection',
'name','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')
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')
for variants_data in variants_data:
abc = Variants.objects.create(**variants_data)
#products-logic
product = Product.objects.create(featured=featured,top_rated=top_rated,
brand=brand,collection=collection,
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()
#category_data = Category.objects.filter(category__in=category_data)
product.category.set(category_data)
product.picture.set(picture_data)
product.variants.set(abc)
return product
My URLs:
path('api/addproducts', views.ProductAddAPIView.as_view(), name='api-addproducts'),
The issue is shown on the line product.variants.set(abc)
I used .add method inside the loop instead of .set() and it worked. Learnt a great thing today.
My working serializer is:
class AddProductSerializer(serializers.ModelSerializer):
variants = VariantSerializer(many=True)
class Meta:
model = Product
fields = ['merchant','featured', 'top_rated','category','brand','collection',
'name','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')
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')
#products-logic
product = Product.objects.create(featured=featured,top_rated=top_rated,
brand=brand,collection=collection,
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()
#category_data = Category.objects.filter(category__in=category_data)
product.category.set(category_data)
product.picture.set(picture_data)
for variants_data in variants_data:
abc = Variants.objects.create(**variants_data)
product.variants.add(abc)
return product