viewset update tutorial queryset framework create django django-rest-framework

update - ¿Cómo creo varias instancias de modelo con Django Rest Framework?



django rest framework viewset (7)

Me gustaría guardar y actualizar varias instancias usando el Django Rest Framework con una llamada API. Por ejemplo, digamos que tengo un modelo de "Aula" que puede tener varios "Maestros". Si quisiera crear varios maestros y luego actualizar todos sus números del aula, ¿cómo lo haría? ¿Tengo que hacer una llamada API para cada maestro?

Sé que actualmente no podemos guardar modelos anidados, pero me gustaría saber si podemos guardarlo en el nivel de profesor. ¡Gracias!


Aquí hay otra solución, no es necesario que anule el método __init__ serializadores. Simplemente anule el método ''create'' su vista (ModelViewSet). Observe many=isinstance(request.data,list) . Aquí many=True cuando envía una matriz de objetos para crear, y False cuando envía solo uno. ¡De esta manera, puedes guardar tanto un artículo como una lista!

from rest_framework import status from rest_framework.response import Response class ThingViewSet(viewsets.ModelViewSet): """This view snippet provides both list and item create functionality.""" #I took the liberty to change the model to queryset queryset = Thing.objects.all() serializer_class = ThingSerializer def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data, many=isinstance(request.data,list)) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)


Creo que lo mejor para respetar la arquitectura propuesta del framework será crear una mezcla como esta:

class CreateListModelMixin(object): def create(self, request, *args, **kwargs): """ Create a list of model instances if a list is provides or a single model instance otherwise. """ data = request.data if isinstance(data, list): serializer = self.get_serializer(data=request.data, many=True) else: serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

Entonces puede anular CreateModelMixin de ModelViewSet de esta manera:

class <MyModel>ViewSet(CreateListModelMixin, viewsets.ModelViewSet): ... ...

Ahora en el cliente puedes trabajar así:

var things = [ {''loads'':''foo'',''of'':''bar'',''fields'':''buzz''}, {''loads'':''fizz'',''of'':''bazz'',''fields'':''errrrm''} ] thingClientResource.post(things)

o

var thing = { ''loads'':''foo'',''of'':''bar'',''fields'':''buzz'' } thingClientResource.post(thing)

EDITAR:

Como sugiere Roger Collins en su respuesta, es más inteligente sobrescribir el método get_serializer que ''crear''.


La página de Vistas genéricas en la documentación de Django REST Framework indica que la vista genérica ListCreateAPIView se utiliza para que los puntos finales de lectura y escritura representen una colección de instancias modelo.

Ahí es donde empezaría a buscar (y lo voy a hacer en realidad, ya que también necesitaremos esta funcionalidad en nuestro proyecto pronto).

Tenga en cuenta también que los examples en la página Vistas genéricas usan ListCreateAPIView .


Llegué a una conclusión similar a la de Daniel Albarral, pero aquí hay una solución más sucinta:

class CreateListModelMixin(object): def get_serializer(self, *args, **kwargs): """ if an array is passed, set serializer to many """ if isinstance(kwargs.get(''data'', {}), list): kwargs[''many''] = True return super(CreateListModelMixin, self).get_serializer(*args, **kwargs)


No pude entender cómo obtener la solicitud. DATA para convertir de un diccionario a una matriz, lo cual era un límite en mi capacidad para que la solución de Tom Manterfield funcionara. Aquí está mi solución:

class ThingSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): many = kwargs.pop(''many'', True) super(ThingSerializer, self).__init__(many=many, *args, **kwargs) class Meta: model = Thing fields = (''loads'', ''of'', ''fields'', ) class ThingViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet ): queryset = myModels/ .Thing/ .objects/ .all() serializer_class = ThingSerializer def create(self, request, *args, **kwargs): self.user = request.user listOfThings = request.DATA[''things''] serializer = self.get_serializer(data=listOfThings, files=request.FILES, many=True) if serializer.is_valid(): serializer.save() headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

Y luego ejecuto el equivalente de esto en el cliente:

var things = { "things":[ {''loads'':''foo'',''of'':''bar'',''fields'':''buzz''}, {''loads'':''fizz'',''of'':''bazz'',''fields'':''errrrm''}] } thingClientResource.post(things)


Sé que esto fue preguntado hace un tiempo pero lo encontré al tratar de resolver esto yo mismo.

Resulta que si pasa many=True al crear una instancia de la clase de serializador para un modelo, puede aceptar múltiples objetos.

Esto se menciona here en los documentos de marco de descanso de django

Para mi caso, mi vista se veía así:

class ThingViewSet(viewsets.ModelViewSet): """This view provides list, detail, create, retrieve, update and destroy actions for Things.""" model = Thing serializer_class = ThingSerializer

Realmente no quería escribir una carga de repetición solo para tener control directo sobre la creación de instancias del serializador y pasar many=True , así que en mi clase de serializador __init__ el __init__ en __init__ lugar:

class ThingSerializer(serializers.ModelSerializer): def __init__(self, *args, **kwargs): many = kwargs.pop(''many'', True) super(ThingSerializer, self).__init__(many=many, *args, **kwargs) class Meta: model = Thing fields = (''loads'', ''of'', ''fields'', )

Publicar datos en la URL de la lista para esta vista en el formato:

[ {''loads'':''foo'',''of'':''bar'',''fields'':''buzz''}, {''loads'':''fizz'',''of'':''bazz'',''fields'':''errrrm''} ]

Creó dos recursos con esos detalles. Lo cual fue agradable


Simplemente puede sobreescribir el método get_serializer en su APIView y pasar many=True en get_serializer de la vista base así:

class SomeAPIView(CreateAPIView): queryset = SomeModel.objects.all() serializer_class = SomeSerializer def get_serializer(self, instance=None, data=None, many=False, partial=False): return super(SomeAPIView, self).get_serializer(instance=instance, data=data, many=True, partial=partial)