2016-05-15 106 views
11

我遇到了更新嵌套对象的问题。Django-Rest-Framework。更新嵌套对象

所以我有一个模型,它的结构是类似这样的:

class Invoice(models.Model): 
    nr = models.CharField(max_length=100) 
    title = models.CharField(max_length=100) 

class InvoiceItem(models.Model): 
    name = models.CharField(max_length=100) 
    price = models.FloatField() 
    invoice = models.ForeignKey(Invoice, related_name='items') 

我需要创建子从父对象,我的意思是,是直接创建InvoiceItems创建Invoice对象时。 为此,我写了下面的序列化:

class InvoiceItemSerializer(serializers.ModelSerializer): 
    invoice = serializers.PrimaryKeyRelatedField(queryset=Invoice.objects.all(), required=False) 
    class Meta: 
     model = InvoiceItem 


class InvoiceSerializer(serializers.ModelSerializer): 
    items = InvoiceItemSerializer(many=True) 

    class Meta: 
     model = Invoice 

    def create(self, validated_data): 
     items = validated_data.pop('items', None) 
     invoice = Invoice(**validated_data) 
     invoice.save() 
     for item in items: 
      InvoiceItem.objects.create(invoice=invoice, **item) 
     return invoice 

截至目前,创建/读取/删除方法很好地工作,除了update。 我认为下面的逻辑应该是正确的,但它错过了一些东西。

def update(self, instance, validated_data): 
    instance.nr = validated_data.get('nr', instance.nr) 
    instance.title = validated_data.get('title', instance.title) 
    instance.save() 

    # up till here everything is updating, however the problem appears here. 
    # I don't know how to get the right InvoiceItem object, because in the validated 
    # data I get the items queryset, but without an id. 

    items = validated_data.get('items') 
    for item in items: 
     inv_item = InvoiceItem.objects.get(id=?????, invoice=instance) 
     inv_item.name = item.get('name', inv_item.name) 
     inv_item.price = item.get('price', inv_item.price) 
     inv_item.save() 

    return instance 

任何帮助将非常感激。

+1

您可能将不得不通过pk作为有效负载的一部分。 – dkarchmer

+0

我正在通过,但它不存在于'validated_data'中 – dimmg

+0

您可以显示您的有效负载吗? – dkarchmer

回答

11

这是我已完成任务的方式:

我已将id字段添加到InvoiceItemSerializer

class InvoiceItemSerializer(serializers.ModelSerializer): 
    ... 
    id = serializers.IntegerField(required=False) 
    ... 

而对于InvoiceSerializer

def update(self, instance, validated_data): 
    instance.nr = validated_data.get('nr', instance.nr) 
    instance.title = validated_data.get('title', instance.title) 
    instance.save() 

    items = validated_data.get('items') 

    if items: 
     for item in items: 
      item_id = item.get('id', None) 
      if item_id: 
       inv_item = InvoiceItem.objects.get(id=item_id, invoice=instance) 
       inv_item.name = item.get('name', inv_item.name) 
       inv_item.price = item.get('price', inv_item.price) 
       inv_item.save() 
      else: 
       InvoiceItem.objects.create(account=instance, **item) 

    return instance 

更新方法同样在create方法我大跌眼镜的id如果通过。

+0

感谢您的示例。但是用户请不要忘记赶上'inv_item = InvoiceItem.objects.get(id = item_id,invoice = instance)'可能引发的'DoesNotExist'异常。 – Merka

2

最近我遇到了同样的问题。我解决的办法是迫使id是一个必填字段:

class MySerializer(serializers.ModelSerializer): 

    class Meta: 
     model = MyModel 
     fields = ('id', 'name', 'url',) 
     extra_kwargs = {'id': {'read_only': False, 'required': True}} 

这样我就能够获取正确的实例,并更新

+2

以及'id'是多余的'create'方法会发生什么? – dimmg

0

尝试

def update(self, instance, validated_data): 
    instance.nr = validated_data.get('nr', instance.nr) 
    instance.title = validated_data.get('title', instance.title) 
    instance.save() 


    items = validated_data.get('items') 
    for item in items: 
     inv_item = InvoiceItem.objects.get(invoice=instance, pk=item.pk) 
     inv_item.name = item.get('name', inv_item.name) 
     inv_item.price = item.get('price', inv_item.price) 
     inv_item.invoice = instance 
     inv_item.save() 

    instance.save() 
    return instance