2015-05-11 6 views
10

Ich versuche, einen Django Rest Framework API-Handler zu schreiben, der sowohl eine Datei als auch eine JSON-Nutzlast empfangen kann. Ich habe den MultiPartParser als Handler Parser eingestellt.Wie kann ich mit Django Rest Framework eine Datei hochladen UND eine JSON-Nutzlast senden?

Allerdings scheint es, ich kann nicht beides. Wenn ich die Payload mit der Datei als Multi-Part-Request sende, ist die JSON-Payload in der request.data (der erste Textteil bis zum ersten Doppelpunkt als Schlüssel, der Rest sind die Daten) entstellt. Ich kann die Parameter in Standardform-Parametern gut senden - aber der Rest meiner API akzeptiert JSON-Nutzdaten und ich wollte konsistent sein. Die request.body kann nicht gelesen werden, da es *** RawPostDataException: You cannot access body after reading from request's data stream

Zum Beispiel wirft eine Datei und diese Nutzlast in der Anfrage Körper:
{"title":"Document Title", "description":"Doc Description"}
Becomes:
<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"}']}>

Gibt es eine Möglichkeit, dies zu tun? Kann ich meinen Kuchen essen, behalten und nicht an Gewicht zunehmen?

Bearbeiten: Es wurde vorgeschlagen, dass dies eine Kopie von Django REST Framework upload image: "The submitted data was not a file" sein könnte. Es ist nicht. Der Upload und die Anfrage erfolgen in mehreren Teilen, und beachten Sie, dass die Datei und der Upload in Ordnung sind. Ich kann die Anfrage sogar mit Standardformularvariablen abschließen. Aber ich möchte sehen, ob ich stattdessen eine JSON-Nutzlast bekommen kann.

+0

möglich Duplikat [Django REST-Framework-Upload-Bild: "Die vorgelegten Daten waren keine Datei"] (http: //stackoverflow.com/questions/28036404/django-rest-framework-upload-image-the-submitted-data-was-not-a-file) –

+0

Nein, es ist nicht. bearbeitete Frage, um zu erklären, warum, obwohl ich die Ähnlichkeit zwischen den zwei Fragen neben dem Dateiuploadbit nicht einmal sehe. – Harel

+1

Es ist wichtig zu beachten, dass _ 'application/json' nicht dasselbe ist wie 'multipart/form-data'_, sie können nicht zusammen verwendet werden. Und JSON unterstützt das Hochladen von Dateien standardmäßig nicht. Sie müssen ein benutzerdefiniertes Dateifeld (und base64-Enkodierung) verwenden, um Datei-Upload-Unterstützung zu erhalten (wo die andere Frage eingeht). Sie können JSON nicht mit mehrteiligen Daten senden, da multipart JSON überhaupt nicht analysieren kann und JSON Multipart nicht parsen kann. –

Antwort

-1

ich ein ähnliches Problem haben, hier ist meine Lösung:

Zuerst dies zu Ihrer Konfigurations hinzufügen (settings.py):

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

Dann in Ihrem Serializer (ex: 'Datei'):

file = serializers.FileField() 

Und in Ihrer Ansicht hinzufügen:

parser_classes = (FileUploadParser, JSONParser) 

Damit konnte ich sowohl eine Datei und verschiedene Felder veröffentlichen, aber Sie müssen angeben:

  • die Post-Format als 'Multipart'
  • und diese http-Header:

HTTP_CONTENT_DISPOSITION = "Anhang; filename = your_file_name.jpg“

+11

Vielleicht wäre ein Beispiel der ganzen Methode besser. – teejay

1

Ich sende JSON und ein Bild erstellen/aktualisieren Sie ein Objekt Produkt. Nachfolgend finden Sie eine APIView erstellen, die für mich funktioniert.

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) 

Ansicht

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) 

Beispiel Test:

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

Können Sie Ihren Serializer auch zeigen? Welches Feld verwenden Sie für den Bildschlüssel? – FariaC

+0

@FariaC Bitte überprüfen Sie meine Serializer-Bearbeitungen. – sarc360

+3

Dies sendet jedoch nicht JSON. – tungd

2

Ich weiß, das ist ein alter Thread, aber ich bin gerade auf dieses Thema gestoßen.Ich musste MultiPartParser verwenden, um meine Datei und zusätzliche Daten zusammen zu bekommen. Hier ist, was mein Code wie folgt aussieht:

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

Mein AngularJS Code ng-file-upload ist:

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