我有一个像这样的序列化器:
class PutAwayProductsPositionSerializer(serializers.ModelSerializer):
class Meta:
model = PutAwayProductsPosition
fields = "__all__"
class PutAwaySerializer(serializers.ModelSerializer):
products_position = PutAwayProductsPositionSerializer(many=True)
class Meta:
model = PutAway
fields = "__all__"
def create(self, validated_data):
items_objects = validated_data.pop('products_position', [])
prdcts = []
for item in items_objects:
i = PutAwayProductsPosition.objects.create(**item)
prdcts.append(i)
instance = PutAway.objects.create(**validated_data)
print("prdcts", prdcts)
instance.products_position.set(prdcts)
return instance
def update(self, instance, validated_data):
items_objects = validated_data.pop('products_position', [])
print("items_objects in update", items_objects)
prdcts = []
for item in items_objects:
kp_instance, created = PutAwayProductsPosition.objects.update_or_create(pk=item.get('id'), defaults=item)
prdcts.append(kp_instance.pk)
instance.products_position.set(prdcts)
instance = super(PutAwaySerializer, self).update(instance, validated_data)
return instance
当我尝试编辑一个特定的对象时,这个update_or_create总是创建一个新条目。我通过打印经过验证的数据来检查错误,尽管序列化器的模型被设置为">all,但序列化器似乎没有验证id
字段。";如何解决这个问题?
我从serliazer得到的数据如下:
{
"id": 13,
"products_position": [
{
"id": 297,
"put_position": "F.G.H.I.J",
"is_put": true,
"products": 312
},
{
"id": 298,
"put_position": "F.G.H.I.J",
"is_put": true,
"products": 310
},
{
"id": 299,
"put_position": "F.G.H.I.J",
"is_put": false,
"products": 310
},
{
"id": 300,
"put_position": "F.G.H.I.J",
"is_put": false,
"products": 310
},
{
"id": 301,
"put_position": "F.G.H.I.J",
"is_put": false,
"products": 310
},
{
"id": 302,
"put_position": "F.G.H.I.J",
"is_put": false,
"products": 310
},
{
"id": 303,
"put_position": "A.B.C.D.E",
"is_put": false,
"products": 311
},
{
"id": 304,
"put_position": "A.B.C.D.E",
"is_put": false,
"products": 311
},
{
"id": 305,
"put_position": "A.B.C.D.E",
"is_put": false,
"products": 309
},
{
"id": 306,
"put_position": "A.B.C.D.E",
"is_put": false,
"products": 309
},
{
"id": 307,
"put_position": "A.B.C.D.E",
"is_put": false,
"products": 309
}
],
"putaway_id": 0,
"completely_executed": false,
"partially_executed": false,
"created": "2023-04-04T10:33:11.701963Z",
"scheduled_datetime": "2023-04-04T10:33:11.702064Z",
"warehouse": 60,
"grn": 520,
"employee_assigned": 111,
"owner": 93
}
items_objects in Validated Data:
[OrderedDict([('put_position', 'F.G.H.I.J'), ('is_put', False), ('products', <Product: Product object (312)>)]), OrderedDict([('put_position', 'F.G.H.I.J'), ('is_put', False), ('products', <Product: Product object (310)>)]), OrderedDict([('put_position', 'F.G.H.I.J'), ('is_put', True), ('products', <Product: Product object (310)>)]), OrderedDict([('put_position', 'F.G.H.I.J'), ('is_put', False), ('products', <Product: Product object (310)>)]), OrderedDict([('put_position', 'F.G.H.I.J'), ('is_put', False), ('products', <Product: Product object (310)>)]), OrderedDict([('put_position', 'F.G.H.I.J'), ('is_put', False), ('products', <Product: Product object (310)>)]), OrderedDict([('put_position', 'A.B.C.D.E'), ('is_put', False), ('products', <Product: Product object (311)>)]), OrderedDict([('put_position', 'A.B.C.D.E'), ('is_put', False), ('products', <Product: Product object (311)>)]), OrderedDict([('put_position', 'A.B.C.D.E'), ('is_put', False), ('products', <Product: Product object (309)>)]), OrderedDict([('put_position', 'A.B.C.D.E'), ('is_put', False), ('products', <Product: Product object (309)>)]), OrderedDict([('put_position', 'A.B.C.D.E'), ('is_put', False), ('products', <Product: Product object (309)>)])]
模型:
class PutAwayProductsPosition(models.Model):
products = models.ForeignKey(Product, on_delete=models.CASCADE)
put_position = models.CharField(max_length=50, default=0)
is_put = models.BooleanField(default=False)
class PutAway(models.Model):
warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
grn = models.ForeignKey("grn.GRN", on_delete=models.CASCADE)
employee_assigned = models.ForeignKey(Employee, on_delete=models.CASCADE)
putaway_id = models.IntegerField(default=0)
products_position = models.ManyToManyField(PutAwayProductsPosition)
completely_executed = models.BooleanField(default=False)
partially_executed = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
scheduled_datetime = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
只读字段没有在内部传递给validated_data,这是drf故意的行为,详细信息可以在此票据中找到。
尝试在PutAwayProductsPositionSerializer
中的Meta
中添加extra_kwargs,将id
字段的read_only
属性设置为False
class PutAwayProductsPositionSerializer(serializers.ModelSerializer):
class Meta:
model = PutAwayProductsPosition
fields = "__all__"
extra_kwargs = {'id': {'read_only': False},}
在我给你一个解决方案之前,我必须说端点有点奇怪。通常在嵌套关系中,您会希望使用extra action
编码另一个端点,这将使您的代码更有组织并改进嵌套对象的管理,例如:
http://localhost:8000/putaway/{pk}/products_position
与您的问题相关,正如您所指出的,问题是您在validated_data
中没有得到id
,因为它是None
,那么它将创建一个新对象。现在我不能给你一个具体的答案为什么(可能是因为.update
不支持修改嵌套对象)
一个解决方案是使用request.data
对象,并通过覆盖ViewSet
上的.update
方法将其作为extra context
传递给序列化器:
views.py
class PutAwayViewSet(viewsets.ModelViewSet):
queryset = PutAway.objects.all()
serializer_class = PutAwaySerializer
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
products_position = request.data.get('products_position', None)
serializer = self.get_serializer(
instance,
data=request.data,
partial=partial,
context={'products_position': products_position}
)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)
serializers.py
class PutAwaySerializer(serializers.ModelSerializer):
products_position = PutAwayProductsPositionSerializer(many=True)
class Meta:
model = PutAway
fields = "__all__"
def create(self, validated_data):
...
def update(self, instance, validated_data):
items_data = self.context.get('products_position')
item_objects = instance.products_position.all()
if items_data:
for obj in items_data:
obj['products'] = Product.objects.get(pk=obj['products'])
pp_instance, created = PutAwayProductsPosition.objects.update_or_create(pk=obj['id'], defaults=obj)
if not item_objects.filter(id=pp_instance.id).exists():
instance.products_position.add(pp_instance)
return instance
如果你正在使用这种方法,我建议对.create
使用相同的过程。