Как разрешить нулевое значение в сериализаторе, если поле в модели является обязательным?
Заданы следующие payload
, models.py
и serializers.py
в 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
Проблема, с которой я столкнулся, заключается в том, что при попытке POST полезной нагрузки DRF пожаловался, что поле foo
в FooChild
является обязательным, что вполне понятно, проблема в том, что id
в Foo
существует только после того, как я создал экземпляр foo
(в строке 21). Я пытался сказать DRF игнорировать требование предоставить foo
при создании FooChild
, но безрезультатно (см. строки 2, 9, 10 выше). Как решить эту проблему?
Вообще-то у меня есть идея установить null=True
в модель FooChild
, но FooChild
не может существовать без Foo
, поэтому я решил, что в этом нет никакого смысла. Спасибо за помощь
Чтобы разрешить нулевое значение для поля foo
в сериализаторе FooChild
и при этом сохранить поле как необходимое в модели, вы можете изменить свой код следующим образом:
- В
FooChildSerializer
удалите объявление поляfoo
.
class FooChildSerializer(serializers.ModelSerializer):
class Meta:
model = FooChild
fields = ["id", "quantity", "price_estimation", ...]
- В
FooSerializer
обновите полеfoo_details
для обработки созданияFooChild
экземпляров после сохраненияFoo
экземпляра.
class FooSerializer(serializers.ModelSerializer):
foo_details = FooChildSerializer(many=True, required=False)
class Meta:
model = Foo
fields = ["id", "created_by", "brand", "foo_details", ...]
def create(self, validated_data):
foo_details_data = validated_data.pop("foo_details", None)
foo = Foo.objects.create(**validated_data)
if foo_details_data:
for foo_detail_data in foo_details_data:
FooChild.objects.create(foo=foo, **foo_detail_data)
return foo
Установив required=False
для поля foo_details
в сериализаторе, мы позволяем полю быть необязательным в полезной нагрузке. В методе create
мы извлекаем данные foo_details
из validated_data
с помощью pop
, сохраняя их None
, если они отсутствуют.
После создания экземпляра foo
мы проверяем, существует ли foo_details_data
. Если существует, мы перебираем данные и создаем экземпляры FooChild
, связывая их с экземпляром foo
.
Таким образом, вы можете создать экземпляр Foo
с указанием или без указания foo_details
в полезной нагрузке. Если foo_details
предоставлены, они будут ассоциированы с экземпляром Foo
после его создания.