我有两种模型,一种与另一种具有外键关系。我希望能够同时创建或更新多个条目。我不会同时创建和更新。
我一直对人们的例子感到困惑。我希望有人不仅可以向我展示我需要做什么,而且还可以对每一步发生的事情进行一些解释。我特别不明白 validated_data.get()
方法在做什么,或者实例究竟是什么,以及它们正在做什么。
class ExtraFieldsSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField()
class Meta:
model = ExtraFields
fields = [
'id',
'job',
'custom_data',
]
class JobWriteSerializer(serializers.ModelSerializer):
extra_fields = ExtraFieldsSerializer(many=True)
class Meta:
model = Job
fields = [
"extra_fields",
"custom_data_fields",
]
# Make JobSerializer able to create custom fields.
def create(self, validated_data):
extra_fields = validated_data.pop("extra_fields")
user = User.objects.get(id=self.context['request'].user.id)
client = Client.objects.get(user=self.context['request'].user)
new_job = Job.objects.create(user=user, client=client, **validated_data)
new_job.save()
for field in extra_fields:
new_field = ExtraFields.objects.create(job=new_job, custom_data=field['custom_data'])
new_field.save()
return new_job
# Make JobSerializer able to update custom fields
def update(self, instance, validated_data):
pass
答案 0 :(得分:2)
首先,您可能可以使用 drf-writeable-nested,因为它几乎完全符合您的要求。
但了解正在发生的事情永远不会有什么坏处:
def create(self, validated_data):
extra_fields = validated_data.pop("extra_fields")
user = User.objects.get(id=self.context['request'].user.id)
client = Client.objects.get(user=self.context['request'].user)
new_job = Job.objects.create(user=user, client=client, **validated_data)
new_job.save()
for field in extra_fields:
new_field = ExtraFields.objects.create(job=new_job, custom_data=field['custom_data'])
new_field.save()
return new_job
由于 JobWriteSerializer
是父序列化器,我们将从它开始。
传递给您的 create 函数的 validated_data
参数包含,顾名思义,验证数据。这意味着,您可以假设您在序列化程序中定义的所有约束(必填字段、max_length、min_length 等)都成立,并且您不需要检查它们。
代码看起来不错,似乎您正在从序列化程序中弹出所有 extra_fields
并从中创建 ExtraField
对象。
您特别询问使用 validated_data.get
时发生了什么,但您使用的是 validated_data.pop
。不同之处在于,使用 get
时,检索到的数据保留在字典中,而 pop
将其删除。
这对于您还必须创建嵌套对象的情况特别方便,请考虑这一点(省略了一些不相关的内容):
class MyModel(models.Model):
text = models.CharField(max_length=10, related_name='children')
class MyChildModel(models.Model):
someVal = models.BooleanField()
model = models.ForeignKey(MyModel)
class MyChildSerializer(serializers.ModelSerializer):
someVal = serializers.BooleanField()
class MyModelSerializer(serializers.ModelSerializer):
text = serializers.TextField(...)
childen = ChildrenSerializer(many=True)
def create(self, validated_data):
children = validated_data.pop('children', []) #POP!
instance = super().create(validated_data)
for c in children:
MyChildSerializer.objects.create(model=instance, **c)
return instance
你可以自己测试,如果你在这里使用 get
而不是 pop
,你的序列化器会理所当然地抱怨 children
对象中有 validated_data
对象,并且drf 无法创建开箱即用的嵌套关系。当您 pop
它们时,序列化程序不再有这些字段并且可以工作。
请注意,这种方法对您的情况来说效率不高,因为您手动将数据传递给您无法通过的 Job
对象(如 user
和 client
)传递的数据,但来自您的请求。如果您愿意,您可以使用 get_serializer_context
来解决这个问题,但我们只能说这超出了问题范围。
关于您的更新方法,我建议使用类似的方法(未经测试,但您懂的):
def update(self, instance, validated_data):
extra_fields = validated_data.pop('extra_fields', []) # POP the extra fields
instance = super().update(instance, validated_data) # !!!!!
for extra in extra_fields:
#retrieve your extra fields and update them
myExtra = ExtraFields.objects.get(id=extra['id])
....
传递的参数 instance
实际上是您的 Job
模型的现有实例。这是您要更新的对象。请注意,我再次弹出 extra_fields
,正是为了执行我上面描述的操作:我使用 drf 本身来修改/更新对象,因为我只需要为子元素实现 update
。< /p>