Reputation: 589
I have some models and they are nested each others. I want to make a bulk create for 2 serializers , both have relations with other models. I looked at documentation on DRF but could not implement it in my code.
I send my json data like this:
{
'status':true,
'products':[
{
'painting':{'amount':10},
'product':{'id':12, }
},
{
'painting':{'amount':10},
'product':{'id':12, }
}
],
'customer':{ 'name':'Adnan',
'address':{'country':'Turkey'}
},
'total':111
}
#models.py
class Address():
...
class Customer():
address = models.ForeignKey(Address, ...)
class Painting():
...
class Product():
...
class Selling():
customer = models.ForeignKey(Customer, ...)
products = models.ManyToManyField(Product, through='SellingProduct')
class SellingProduct():
selling = models.ForeignKey(Selling, ...)
product = models.ForeignKey(Product, ...)
painting = models.ForeignKey(Painting, ...)
Here is my serializers.py
class AddressSerializer():
...
class CustomerSerializer():
address = AddressSerializer()
...
class PaintingSerializer():
...
class ProductSerializer():
...
class SellingProductSerializer():
painting = PaintingSerializer()
product = ProductSerializer()
class SellingSerializer():
customer = CustomerSerializer()
products = SellingProductSerializer(many=True)
...
def create(self, validated_data):
...
If I write this:
class SellingSerializer():
...
def create(self, validated_data):
customer_data = validated_data.pop('customer')
products_data = validated_data.pop('products')
selling = Selling.objects.create(**validated_data) #i didn't pass customer here
for product_data in products_data:
SellingProducts.objects.create(selling=selling, **product_data)
return selling
I'm getting this error:
django.db.utils.IntegrityError: (1048, "Column 'customer_id' cannot be null")
If I write this:
class SellingSerializer():
...
def create(self, validated_data):
selling = Selling.objects.create(**validated_data) #i didn't pass customer here
return selling
I'm getting this error:
ValueError: Cannot assign "OrderedDict...
..Selling.customer must be a "Customer" instance
Thank you all in advance for any help!
Upvotes: 0
Views: 998
Reputation: 1361
SellingSerializer is related with CustomerSerializerh, ProductSerializer
Before creating Selling object, we can validate each serializer and create
update validated data
the process many to many
You would not be just creating customer object product object.Data has to be validated and can use CustomerSerializer and ProductSerializer. Before creating them serialize your data with CustomerSerializer and ProductSerializer, then is valid create object else raise exception.
class SellingSerializer():
...
def create(self, validated_data):
# First Let's handle Customer data
customer_data = validated_data.pop('customer')
customer_serializer = CustomerSerializer(data=customer_data)
customer_serializer.is_valid(raise_exception=True)
customer = customer_serializer.save()
validated_data.update({'customer':customer}) ## update our validated data with customer instance
# Create Selling object
selling = Selling.objects.create(**validated_data) # will receive customer instance as well
# Handle Products related Data
products_data = validated_data.pop('products')
for product_data in products_data:
product_serializer = ProductSerializer(data=product_data)
product_serializer.is_valid(raise_exception=True)
product = product_serializer.save()
SellingProducts.objects.create(selling=selling, product=product)
return selling
Upvotes: 0
Reputation: 887
You need to use your CustomerSerializer
to create a customer object and database row before you can create a Selling
object with a foreign key to it. You are trying either not passing anything or are passing the JSON (that turns into the OrderedDict
in your error message).
class SellingSerializer():
...
def create(self, validated_data):
customer_data = validated_data.pop('customer')
products_data = validated_data.pop('products')
customer = CustomerSerializer.save(**customer_data)
selling = Selling.objects.create(customer=customer, **validated_data)
for product_data in products_data:
SellingProducts.objects.create(selling=selling, **product_data)
return selling
Maybe reread the documentation on this issue.
Upvotes: 0
Reputation: 5492
Your first approach should work, if you make a few modifications. Your Selling model is dependent on on a Customer, so you first need to create a Customer. Then, your SellingProduct model is dependent on a Product and Painting, so you first need to create a Product and Painting, then create a SellingProduct with instances of those, like this:
class SellingSerializer():
...
def create(self, validated_data):
customer_data = validated_data.pop('customer')
selling_products_data = validated_data.pop('products')
customer = Customer.objects.create(**customer_data)
selling = Selling.objects.create(customer=customer, **validated_data)
for selling_product_data in selling_products_data :
product_data = selling_product_data.pop('product')
product = Product.objects.create(**product_data)
painting_data = selling_product_data.pop('painting')
painting = Painting.objects.create(**painting_data)
SellingProducts.objects.create(selling=selling, product=product, painting=painting)
return selling
Of course, this approach creates a new Customer, Products and Paintings for each request. Is this really what you want? If you do not want to create new Product and Painting instances for each request, but use references to existing instances, you can define them as PrimaryKeyRelatedField fields in the SellingSerializer and SellingProductSerializer. Then, you can change your create function to this:
def create(self, validated_data):
customer = validated_data.pop('customer')
selling_products_data = validated_data.pop('products')
selling = Selling.objects.create(customer=customer, **validated_data)
for selling_product_data in selling_products_data :
SellingProducts.objects.create(selling=selling, **selling_product_data )
return selling
Upvotes: 1