2015-05-11 14 views
10

Sto provando a scrivere un gestore di API di Django Rest Framework che può ricevere un file e un carico utile JSON. Ho impostato il MultiPartParser come parser del gestore.Utilizzando Django Rest Framework, come posso caricare un file E inviare un carico utile JSON?

Tuttavia, sembra che non sia possibile fare entrambe le cose. Se invio il payload con il file come richiesta multiparte, il carico utile JSON è disponibile in modo distorto nel request.data (prima parte del testo fino ai primi due punti come chiave, il resto è i dati). Posso inviare i parametri nei parametri del modulo standard, ma il resto della mia API accetta i payload JSON e volevo essere coerente. Il request.body non può essere letto in quanto solleva *** RawPostDataException: You cannot access body after reading from request's data stream

Ad esempio, un file e questo payload nel corpo della richiesta:
{"title":"Document Title", "description":"Doc Description"}
diventa:
<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"}']}>

C'è un modo per fare questo? Posso mangiare la mia torta, tenerla e non guadagnare peso?

Modifica: È stato suggerito che questa potrebbe essere una copia di Django REST Framework upload image: "The submitted data was not a file". Non è. Il caricamento e la richiesta vengono eseguiti in multipart, e tieni presente il file e il caricamento di esso va bene. Posso persino completare la richiesta con variabili di forma standard. Ma voglio vedere se riesco a ottenere un carico utile JSON in là invece.

+0

possibile duplicato del [Django REST quadro l'immagine di upload: "I dati presentati non era un file"] (http: //stackoverflow.com/questions/28036404/django-rest-framework-upload-image-the-submitted-data-was-not-a-file) –

+0

No, non è così. domanda modificata per spiegare perché, anche se non vedo nemmeno la somiglianza tra le due domande oltre al bit di upload del file. – Harel

+1

È importante notare che _'application/json' non è lo stesso di 'multipart/form-data'_, non possono essere usati insieme. E JSON non supporta il caricamento dei file per impostazione predefinita, è necessario utilizzare un campo file personalizzato (e codificare Base64) per ottenere il supporto per il caricamento dei file (che è il punto in cui arriva l'altra domanda). Non è possibile inviare JSON con dati multipart, poiché multipart non può analizzare JSON affatto e JSON non può analizzare multipart. –

risposta

-1

Ho un problema simile, qui è la mia soluzione:

Prima aggiungere questo alla tua configurazione (settings.py):

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

Poi, nel tuo Serializer (es: 'file'):

file = serializers.FileField() 

E nel tuo Blog:

parser_classes = (FileUploadParser, JSONParser) 

Con questo ho potuto inviare un file e vari campi, ma è necessario specificare:

  • il formato carica di 'multipart'
  • e questa intestazione http:

HTTP_CONTENT_DISPOSITION = "allegato; filename = your_file_name.jpg"

+11

Forse un esempio di intero metodo sarebbe meglio. – teejay

1

mando JSON e un'immagine di creare/aggiornare un oggetto prodotto. Di seguito è riportato un creare APIView che funziona per me.

Serializer

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) 

View

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) 

prova Esempio:

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) 
+0

Puoi mostrare anche il tuo serializzatore? Che campo usi per la chiave immagine? – FariaC

+0

@FariaC Controllare le modifiche del serializzatore. – sarc360

+3

Tuttavia, questo non sta mandando JSON. – tungd

2

So che questo è un thread vecchio, ma ho appena trovato questo.Ho dovuto usare MultiPartParser per ottenere il mio file e dati extra da incontrare insieme. Ecco ciò che il mio codice è simile:

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

Il mio codice AngularJS utilizzando ng-file-upload è:

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