如何在模型字段必需时允许序列化器的空值?
给定以下的 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
我现在遇到的问题是,当我尝试发送这个 payload
时,DRF 报错说 FooChild
里的 foo
字段是必填的,这个我能理解。问题是,Foo
的 id
只有在我创建了 foo
实例之后才会存在(在第 21 行)。我尝试告诉 DRF 在创建 FooChild
时可以忽略提供 foo
的要求,但没有成功(见上面的第 2、9、10 行)。我该怎么解决这个问题呢?
其实我有个想法,就是在 FooChild
模型里设置 null=True
,但 FooChild
没有 Foo
是不可能存在的,所以我觉得这样做没有意义。谢谢你的帮助。
1 个回答
0
为了在 FooChild
的序列化器中允许 foo
字段为 null,同时在模型中保持这个字段为必填,你可以按照以下步骤修改代码:
- 在
FooChildSerializer
中,去掉foo
字段的声明。
class FooChildSerializer(serializers.ModelSerializer):
class Meta:
model = FooChild
fields = ["id", "quantity", "price_estimation", ...]
- 在
FooSerializer
中,更新foo_details
字段,以便在保存Foo
实例后处理FooChild
实例的创建。
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
通过在序列化器中将 foo_details
字段设置为 required=False
,这个字段就变成了可选的。在 create
方法中,我们使用 pop
从 validated_data
中提取 foo_details
数据,如果没有提供,就保持为 None
。
在创建 foo
实例后,我们检查 foo_details_data
是否存在。如果存在,我们会遍历这些数据并创建 FooChild
实例,将它们与 foo
实例关联起来。
这样,你就可以在创建 Foo
实例时选择是否提供 foo_details
。如果提供了 foo_details
,它们会在 Foo
实例创建后与之关联。