Given the following payload, models.py, and serializers.py in Django (DRF):
payload
{
"created_by": 6,
"brand": 1,
"foo_details": [
{
"quantity": 123,
"price_estimation": 456
},
{
"quantity": 789,
"price_estimation": 1011
}
]
}
models.py
class Foo(models.Model):
created_by = models.ForeignKey(CustomUser, on_delete=models.PROTECT)
brand = models.ForeignKey(Brand, on_delete=models.SET_NULL, null=True)
# OTHER FIELDS HERE
class FooChild(models.Model):
foo = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name="foo_details")
quantity = models.PositiveIntegerField(default=0)
price_estimation = models.PositiveIntegerField(default=0)
# OTHER FIELDS HERE
serializers.py
class FooChildSerializer(serializers.ModelSerializer):
# foo = serializers.PrimaryKeyRelatedField(read_only=True, required=False) -> LINE 2
class Meta:
model = FooChild
fields = ["id", "foo", "quantity", "price_estimation", ...]
class FooSerializer(serializers.ModelSerializer):
# foo_details = FooChildSerializer(many=True) -> LINE 9
# foo_details = serializers.DictField(child=serializers.CharField(), many=True) -> LINE 10
class Meta:
model = Foo
fields = ["id", "created_by", "brand", "foo_details", ...]
def create(self, validated_data):
# I want to save the payload to `Foo` and `FooChild` inside this function at the same time, below is my unsuccessful attempt
# print(validated_data)
# validated_data.pop("foo_details")
# foo = Foo.objects.create(**validated_data) -> LINE 21
# foo_child = FooChild.objects.create(foo=foo)
# return foo
The problem I'm having right now is, when I tried to POST the payload, DRF complained that foo field in FooChild is required, which is understandable, the problem is, the id of the Foo exists only after I created the foo instance (on line 21). I tried to tell DRF to ignore the requirement to provide foo when creating FooChild to no avail (see line 2, 9, 10 above). How do I solve this problem?
Actually I have an idea to set null=True in the FooChild model, but the FooChild can't exist without Foo, so I figured this doesn't make any sense. Thx for the help
To allow a null value on the
foofield in theFooChildserializer while keeping the field as required in the model, you can modify your code as follows:FooChildSerializer, remove thefoofield declaration.FooSerializer, update thefoo_detailsfield to handle the creation ofFooChildinstances after saving theFooinstance.By setting
required=Falsefor thefoo_detailsfield in the serializer, it allows the field to be optional in the payload. In thecreatemethod, we extract thefoo_detailsdata fromvalidated_datausingpop, keeping itNoneif not present.After creating the
fooinstance, we check iffoo_details_dataexists. If it does, we iterate over the data and createFooChildinstances, associating them with thefooinstance.This way, you can create a
Fooinstance with or without providingfoo_detailsin the payload. Iffoo_detailsare provided, they will be associated with theFooinstance after it is created.