2016-05-15 32 views
11

Ho riscontrato un problema con l'aggiornamento di un oggetto nidificato.Django-Rest-Framework. Aggiornamento dell'oggetto nidificato

Così ho un modello che struttura è simile a questo:

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') 

Ho bisogno di creare oggetti figlio dal padre, e quello che voglio dire con questo, è quello di creare InvoiceItems direttamente durante la creazione di un oggetto Invoice . A tal fine, ho scritto il seguente: serializzatori

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 

Fino ad ora, i metodi di creazione/lettura/cancellazione funzionano perfettamente, ad eccezione del update. Penso che la logica sottostante dovrebbe essere corretta, ma manca qualcosa.

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 

Qualsiasi aiuto sarebbe molto apprezzato.

+1

Probabilmente dovrete passare il pk come parte del carico utile. – dkarchmer

+0

Sto passando, ma non è presente in 'validated_data' – dimmg

+0

Puoi mostrare il tuo carico utile? – dkarchmer

risposta

11

Questo è il modo in cui ho completato l'operazione:

Ho aggiunto un campo id allo InvoiceItemSerializer

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

E il metodo di aggiornamento per il 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 

Anche nel metodo create sto schioccare la id se è passato.

+0

Grazie per il campione. Ma gli utenti per favore non si dimenticano di catturare l'eccezione 'DoesNotExist' che può essere chiamata' inv_item = InvoiceItem.objects.get (id = item_id, fattoice = instance) '. – Merka

2

Mi sono imbattuto nello stesso problema di recente. Il modo in cui ho affrontato è stato quello di costringere il id ad essere un campo obbligatorio:

class MySerializer(serializers.ModelSerializer): 

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

In questo modo sono stato in grado di recuperare l'istanza corretta e aggiornarlo

+2

e cosa succede nel caso di un metodo 'create' dove' id' è ridondante? – dimmg

0

Prova

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