2015-05-11 9 views
10

Próbuję napisać program obsługi Django Rest Framework API, który może odbierać plik, a także ładunek JSON. Ustawiłem MultiPartParser jako parser obsługi.Korzystanie z Django Rest Framework, jak mogę przesłać plik ORAZ wysłać ładunek JSON?

Jednak wydaje się, że nie mogę zrobić obu. Jeśli wysyłam ładunek z plikiem jako żądanie wieloczęściowe, ładunek JSON jest dostępny w zniekształconym formacie w request.data (pierwsza część tekstu do pierwszego dwukropka jako klucz, reszta to dane). Mogę przesłać parametry w standardowych parametrach formularza - ale reszta mojego API akceptuje ładunki JSON i chciałem być konsekwentny. Request.body nie mogą być odczytywane jako podnosi *** RawPostDataException: You cannot access body after reading from request's data stream

Na przykład, plik i ten ładunek w organizmie żądanie:
{"title":"Document Title", "description":"Doc Description"}
staje:
<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"}']}>

Czy istnieje sposób, aby to zrobić? Czy mogę zjeść moje ciasto, zachować je i nie przybrać na wadze?

Edytuj: Zasugerowano, że może to być kopia Django REST Framework upload image: "The submitted data was not a file". Nie jest. Przesyłanie i żądanie jest wykonywane wieloczęściowo i pamiętaj, że plik i przesłanie go jest w porządku. Mogę nawet wypełnić żądanie standardowymi zmiennymi formularza. Ale chcę sprawdzić, czy mogę zamiast tego uzyskać ładunek JSON.

+0

możliwe duplikat [Django REST ramowego przesyłania obrazu: "Przedstawione dane nie był plik"] (http: //stackoverflow.com/questions/28036404/django-rest-framework-upload-image-the-submitted-data-was-not-a-file) –

+0

Nie, nie jest. zredagowane pytanie wyjaśniające, dlaczego, chociaż nie widzę podobieństwa między tymi dwoma pytaniami oprócz bitu do przesyłania plików. – Harel

+1

Należy zauważyć, że _'application/json' nie jest tym samym co 'multipart/form-data'_, nie można ich używać razem. A JSON nie obsługuje domyślnie przesyłania plików, musisz użyć niestandardowego pola pliku (i kodowania base64), aby uzyskać wsparcie przesyłania plików (tutaj pojawia się inne pytanie). Nie można wysyłać JSON z wieloczęściowymi danymi, ponieważ wieloczęściowy nie może w ogóle analizować JSON i JSON nie może parsować wieloczęściowego. –

Odpowiedz

-1

mam podobny problem, tu jest moje rozwiązanie:

Pierwszy dodać do swojej config (settings.py):

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

Następnie w serializer (ex: 'Plik'):

file = serializers.FileField() 

I w widoku dodać:

parser_classes = (FileUploadParser, JSONParser) 

Dzięki temu mogłem pisać zarówno plik i różnych dziedzin, ale trzeba podać:

  • format postu jako 'multipart'
  • i tego nagłówka http:

HTTP_CONTENT_DISPOSITION = "załącznik; filename = your_file_name.jpg”

+11

Być może przykład całej metody byłby lepszy. – teejay

1

wyślę JSON i obraz, aby utworzyć/zaktualizować obiekt produktu. Poniżej znajduje się tworzyć APIView który pracuje dla mnie.

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) 

Zobacz

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) 

Przykład testowy:

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

Czy możesz również pokazać swój serializer? Jakiego pola używasz do klucza obrazu? – FariaC

+0

@FariaC Sprawdź moje modyfikatory serializera. – sarc360

+3

To nie wysyła jednak JSON. – tungd

2

Wiem, że to stara nitka, ale właśnie natknąłem się na to.Musiałem użyć MultiPartParser, aby zebrać razem plik i dodatkowe dane. Oto co mój kod wygląda następująco:

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

Mój kod angularjs użyciu ng-file-upload jest:

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