with update instalar framework fileuploadparser create json django rest django-rest-framework multipartform-data

json - update - fileuploadparser



Usando Django Rest Framework, ¿cómo puedo cargar un archivo Y enviar una carga JSON? (4)

Envío JSON y una imagen para crear / actualizar un objeto de producto. A continuación se muestra una vista de creación que funciona para mí.

Serializador

class ProductCreateSerializer(serializers.ModelSerializer): class Meta: model = Product fields = [ "id", "product_name", "product_description", "product_price", ] def create(self,validated_data): return Product.objects.create(**validated_data)

Ver

from rest_framework import generics,status from rest_framework.parsers import FormParser,MultiPartParser class ProductCreateAPIView(generics.CreateAPIView): queryset = Product.objects.all() serializer_class = ProductCreateSerializer permission_classes = [IsAdminOrIsSelf,] parser_classes = (MultiPartParser,FormParser,) def perform_create(self,serializer,format=None): owner = self.request.user if self.request.data.get(''image'') is not None: product_image = self.request.data.get(''image'') serializer.save(owner=owner,product_image=product_image) else: serializer.save(owner=owner)

Ejemplo de prueba:

def test_product_creation_with_image(self): url = reverse(''products_create_api'') self.client.login(username=''testaccount'',password=''testaccount'') data = { "product_name" : "Potatoes", "product_description" : "Amazing Potatoes", "image" : open("local-filename.jpg","rb") } response = self.client.post(url,data) self.assertEqual(response.status_code,status.HTTP_201_CREATED)

Estoy tratando de escribir un controlador de la API de Django Rest Framework que pueda recibir un archivo así como una carga JSON. He establecido el MultiPartParser como el analizador de controlador.

Sin embargo, parece que no puedo hacer ambas cosas. Si envío la carga útil con el archivo como una solicitud de varias partes, la carga de JSON está disponible de forma modificada en el request.data (primera parte de texto hasta los primeros dos puntos como la clave, el resto son los datos). Puedo enviar los parámetros en parámetros de formulario estándar muy bien, pero el resto de mi API acepta las cargas JSON y quería ser coherente. El request.body no se puede leer a medida que aumenta *** RawPostDataException: You cannot access body after reading from request''s data stream

Por ejemplo, un archivo y esta carga útil en el cuerpo de la solicitud:
{"title":"Document Title", "description":"Doc Description"}
Se convierte en
<QueryDict: {u''fileUpload'': [<InMemoryUploadedFile: 20150504_115355.jpg (image/jpeg)>, <InMemoryUploadedFile: Front end lead.doc (application/msword)>], u''{%22title%22'': [u''"Document Title", "description":"Doc Description"}'']}>

¿Hay alguna forma de hacer esto? ¿Puedo comer mi pastel, conservarlo y no subir de peso?

Edit: Se sugirió que esto podría ser una copia de la imagen de carga de Django REST Framework: "Los datos enviados no eran un archivo" . No lo es. La carga y la solicitud se realizan en varias partes, y tenga en cuenta que el archivo y la carga están bien. Incluso puedo completar la solicitud con variables de formulario estándar. Pero quiero ver si puedo obtener una carga JSON allí.


Para alguien que necesita cargar un archivo y enviar algunos datos, no existe una manera directa de hacerlo funcionar. Hay un problema abierto en las especificaciones de json api para esto. Una posibilidad que he visto es usar multipart/related como se muestra here , pero creo que es muy difícil implementarlo en drf.

Finalmente, lo que había implementado fue enviar la solicitud como formdata . Enviaría cada archivo como archivo y todos los demás datos como texto. Ahora, para enviar los datos como texto, puede tener una sola clave llamada datos y enviar todo el json como cadena en valor.

Modelos.py

class Posts(models.Model): id = models.UUIDField(default=uuid.uuid4, primary_key=True, editable=False) caption = models.TextField(max_length=1000) media = models.ImageField(blank=True, default="", upload_to="posts/") tags = models.ManyToManyField(''Tags'', related_name=''posts'')

serializers.py -> no se necesitan cambios especiales, no se muestra mi serializador aquí porque es demasiado largo debido a la implementación de campo ManyToMany Field que se puede escribir.

vistas.py

class PostsViewset(viewsets.ModelViewSet): serializer_class = PostsSerializer parser_classes = (MultipartJsonParser, parsers.JSONParser) queryset = Posts.objects.all() lookup_field = ''id''

Necesitará un analizador personalizado como se muestra a continuación para analizar json.

utils.py

from django.http import QueryDict import json from rest_framework import parsers class MultipartJsonParser(parsers.MultiPartParser): def parse(self, stream, media_type=None, parser_context=None): result = super().parse( stream, media_type=media_type, parser_context=parser_context ) data = {} # find the data field and parse it data = json.loads(result.data["data"]) qdict = QueryDict('''', mutable=True) qdict.update(data) return parsers.DataAndFiles(qdict, result.files)

El ejemplo de solicitud en cartero


Sé que este es un hilo viejo, pero acabo de encontrar esto. Tuve que usar MultiPartParser para obtener mi archivo y datos adicionales para encontrarlos juntos. Así es como se ve mi código:

# views.py class FileUploadView(views.APIView): parser_classes = (MultiPartParser,) def put(self, request, filename, format=None): file_obj = request.data[''file''] ftype = request.data[''ftype''] caption = request.data[''caption''] # ... # do some stuff with uploaded file # ... return Response(status=204)

Mi código AngularJS usando ng-file-upload es:

file.upload = Upload.upload({ url: "/api/picture/upload/" + file.name, data: { file: file, ftype: ''final'', caption: ''This is an image caption'' } });


Tengo un problema similar, aquí está mi solución:

Primero agregue esto a su configuración ( settings.py ):

''DEFAULT_PARSER_CLASSES'': ( ''rest_framework.parsers.JSONParser'', ''rest_framework.parsers.MultiPartParser'', ''rest_framework.parsers.FileUploadParser'', ),

Luego en su Serializador (ej: ''archivo''):

file = serializers.FileField()

Y en su vista agregue:

parser_classes = (FileUploadParser, JSONParser)

Con esto podría publicar un archivo y varios campos, pero debe especificar:

  • el formato de la publicación como ''multiparte''
  • y este encabezado http:

HTTP_CONTENT_DISPOSITION = "archivo adjunto; nombre_archivo = su_nombre_archivo.jpg"