2015-01-07 11 views
12

Attualmente sto lavorando su Django con Django Rest Framwork.ModelViewSet - Aggiorna campo nidificato

Non riesco ad aggiornare l'oggetto nel campo dell'oggetto nidificato.


serializer.py

class OwnerSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Owner 
     fields = ('id', 'name') 

class CarSerializer(serializers.ModelSerializer): 
    owner = ownerSerializer(many=False, read_only=False) 
    class Meta: 
     model = Car 
     fields = ('id', 'name', 'owner') 

view.py

class OwnerViewSet(viewsets.ModelViewSet): 
    queryset = Owner.objects.all() 
    serializer_class = OwnerSerializer 

class CarViewSet(viewsets.ModelViewSet): 
    serializer_class = CarSerializer 
    queryset = Car.objects.all() 

    def create(self, request): 
     serialized = self.serializer_class(data=request.DATA) 
     if serialized.is_valid(): 
      serialized.save() 
      return Response(status=HTTP_202_ACCEPTED) 
     else: 
      return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 

Quando faccio questo:

Request URL:http://localhost:9000/api/v1/cars/1/?format=json 
Request Method:PUT 
Request Paylod : 
{ 
    "id":1, 
    "name": "TEST", 
    "ower": { 
     "id":1, 
     "name": "owner_test" 
    } 
} 

ottengo la seguente risposta:

The `.update()` method does not support writable nestedfields by default. 
Write an explicit `.update()` method for serializer `app.serializers.CarSerializer`, 
or set `read_only=True` on nested serializer fields. 

Knowing:

  • voglio mantenere la serializzazione proprietario al GET;
  • possiamo immaginare la macchina nidificato da un altro oggetto e ect ...

Come posso fare se voglio cambiare il proprietario quando aggiorno la macchina.

+2

possibile duplicato di [django-rest-framework 3.0 creare o aggiornare in serializzatore nidificato] (http://stackoverflow.com/questions/27434593/django-rest-framework-3-0-create-or-update -in-nested-serializer) –

+0

Serbatoi! Mi ripeto scusa, ma perché l'override è nel serializzatore e non nella vista, come: [Django-doc] (http://www.django-rest-framework.org/api-guide/viewsets/#marking- extra-azioni-per-routing), in questo modo può restituire lo stato ?? –

risposta

3

Solo nel caso qualcuno inciampa su questo

avevano lo stesso errore nel mio caso, ma l'impostazione read_only a True fissata per me.

owner = ownerSerializer(many=False, read_only=True) 

Si noti che questo campo non verrà visualizzato nel modulo durante la pubblicazione dei dati sull'api.

6

Un po 'in ritardo, ma, Prova questo,

class OwnerSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Owner 
     fields = ('id', 'name') 
     extra_kwargs = { 
      'id': { 
       'read_only': False, 
       'required': True 
      } 
     } #very important 

    def create(self, validated_data): 
     # As before. 
     ... 

    def update(self, instance, validated_data): 
     # Update the instance 
     instance.some_field = validated_data['some_field'] 
     instance.save() 

     # Delete any detail not included in the request 
     owner_ids = [item['owner_id'] for item in validated_data['owners']] 
     for owner in cars.owners.all(): 
      if owner.id not in owner_ids: 
       owner.delete() 

     # Create or update owner 
     for owner in validated_data['owners']: 
      ownerObj = Owner.objects.get(pk=item['id']) 
      if ownerObje: 
       ownerObj.some_field=item['some_field'] 
       ....fields... 
      else: 
       ownerObj = Owner.create(car=instance,**owner) 
      ownerObj.save() 

     return instance 
-2

La fonte di ModelSerializer.create() e ModelSerializer.update() non voglia questo comportamento:

raise_errors_on_nested_writes('create', self, validated_data) 

Se togliamo questa linea, l'azione può ottenere attraverso e le opere bene.

Significa, the doc dice:

Per utilizzare scrivibile serializzazione nidificato si vorrà dichiarare un campo nidificato sulla classe serializer, e scrivere la create() e/o update() metodi in modo esplicito.

Possiamo usare direttamente il codice ModelSerializer.save() e ModelSerializer.update() fonte a questo metodo "scrittura esplicita", con la linea raise_errors_on_nested_writes rimosso.

Quindi su tutto, possiamo definire una tale classe AllowNestedWriteMixin come di seguito:

import traceback 
from rest_framework.utils import model_meta 
from rest_framework.compat import set_many 

class AllowNestedWriteMixin: 
    def create(self, validated_data): 
     ModelClass = self.Meta.model 
     info = model_meta.get_field_info(ModelClass) 
     many_to_many = {} 
     for field_name, relation_info in info.relations.items(): 
      if relation_info.to_many and (field_name in validated_data): 
       many_to_many[field_name] = validated_data.pop(field_name) 

     try: 
      instance = ModelClass.objects.create(**validated_data) 
     except TypeError: 
      tb = traceback.format_exc() 
      msg = (
       'Got a `TypeError` when calling `%s.objects.create()`. ' 
       'This may be because you have a writable field on the ' 
       'serializer class that is not a valid argument to ' 
       '`%s.objects.create()`. You may need to make the field ' 
       'read-only, or override the %s.create() method to handle ' 
       'this correctly.\nOriginal exception was:\n %s' % 
       (
        ModelClass.__name__, 
        ModelClass.__name__, 
        self.__class__.__name__, 
        tb 
       ) 
      ) 
      raise TypeError(msg) 

     # Save many-to-many relationships after the instance is created. 
     if many_to_many: 
      for field_name, value in many_to_many.items(): 
       set_many(instance, field_name, value) 

     return instance 

    def update(self, instance, validated_data): 
     info = model_meta.get_field_info(instance) 

     for attr, value in validated_data.items(): 
      if attr in info.relations and info.relations[attr].to_many: 
       set_many(instance, attr, value) 
      else: 
       setattr(instance, attr, value) 
     instance.save() 

     return instance 

E se vogliamo che il comportamento, si eredita questa classe intermedia prima ModelSerializer, qualcosa di simile al di sotto sul tuo esempio:

class OwnerSerializer(AllowNestedWriteMixin, 
         serializers.ModelSerializer): 
    class Meta: 
     model = Owner 
     fields = ('id', 'name') 

class CarSerializer(AllowNestedWriteMixin, 
        serializers.ModelSerializer): 
    owner = ownerSerializer(many=False, read_only=False) 
    class Meta: 
     model = Car 
     fields = ('id', 'name', 'owner') 
+0

Puoi aggiungere le importazioni? Non riesco a vedere da dove proviene il metodo set_many. Grazie! – Lukas

+0

Utilizzando questo approccio ignori silenziosamente il problema, il campo 'owner' non verrebbe aggiornato –

Problemi correlati