2016-04-18 19 views
17

Stworzyłem prosty Model z ImageField i chcę zrobić widok API z django-rest-framework + django-rest-swagger, który jest udokumentowany i jest w stanie wgrać plik .Django REST Framework + Django REST Swagger + ImageField

Oto co mam:

models.py

from django.utils import timezone 
from django.db import models 

class MyModel(models.Model): 

    source = models.ImageField(upload_to=u'/photos') 
    is_active = models.BooleanField(default=False) 
    created_at = models.DateTimeField(default=timezone.now) 

    def __unicode__(self): 
     return u"photo {0}".format(self.source.url) 

serializer.py

from .models import MyModel 

class MyModelSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = MyModel 
     fields = [ 
      'id', 
      'source', 
      'created_at', 
     ] 

views.py

from rest_framework import generics 
from .serializer import MyModelSerializer 

class MyModelView(generics.CreateAPIView): 
    serializer_class = MyModelSerializer 
    parser_classes = (FileUploadParser,) 

    def post(self, *args, **kwargs): 
     """ 
      Create a MyModel 
      --- 
      parameters: 
       - name: source 
        description: file 
        required: True 
        type: file 
      responseMessages: 
       - code: 201 
        message: Created 
     """ 
     return super(MyModelView, self).post(self, *args, **kwargs) 

urls.py

from weddings.api.views import MyModelView 

urlpatterns = patterns(
    '', 
    url(r'^/api/mymodel/$', MyModelView.as_view()), 
) 

Dla mnie to powinno być dość proste. Nie mogę jednak przesłać pracy. I zawsze uzyskać tę odpowiedź o błędzie: enter image description here

Czytałem tę część dokumentacji z django-rest-framework:

If the view used with FileUploadParser is called with a filename URL keyword argument, then that argument will be used as the filename. If it is called without a filename URL keyword argument, then the client must set the filename in the Content-Disposition HTTP header. For example Content-Disposition: attachment; filename=upload.jpg.

Jednak nagłówku jest przekazywana przez Django Rest-puszyć w żądaniu Payload Właściwość (z konsoli chrome).

Jeśli potrzebujesz więcej informacji, proszę dać mi znać.

Używam Django==1.8.8, i django-rest-swagger==0.3.4.

+0

Czy masz zainstalowany na poduszkę? Wierzę, że reszta django potrzebuje go do przetwarzania plików graficznych https://pypi.python.org/pypi/Pillow –

+0

Dziękuję Charles ... ale tak, mam zainstalowany Pillow. – jarussi

Odpowiedz

3

to ostateczne rozwiązanie wymyśliłem:

from rest_framework import generics 
from rest_framework.parsers import FormParser, MultiPartParser 
from .serializer import MyModelSerializer 

class MyModelView(generics.CreateAPIView): 
    serializer_class = MyModelSerializer 
    parser_classes = (FormParser, MultiPartParser) 

    def post(self, *args, **kwargs): 
     """ 
      Create a MyModel 
      --- 
      parameters: 
       - name: source 
        description: file 
        required: True 
        type: file 
      responseMessages: 
       - code: 201 
        message: Created 
     """ 
     return super(MyModelView, self).post(self, *args, **kwargs) 

Wszystko co musiałem zrobić, to zmienić parser z FileUploadParser do (FormParser, MultiPartParser)

+0

Co musisz zrobić, aby uzyskać DRF lub DRF-Swagger, aby odebrać ten Yl? Ustawiłem taki docstring, ale renderuje on tylko jako Markdown w "Notach implementacyjnych" –

+0

Nie mam zbyt wiele w moich ustawieniach. Zasadniczo nie jest to dokumentacja django-rest-swagger. Jednakże używam wersji '0.3.7' of django-rest-swagger. – jarussi

7

Mam to działa, wprowadzając kilka zmian w kodzie.

Po pierwsze, w models.py, zmień nazwę ImageField na file i użyj względnej ścieżki do przesłania folderu. Kiedy przesyłasz plik jako strumień binarny, jest on dostępny w słowniku request.data pod kluczem pliku (request.data.get('file')), więc najczystszą opcją jest mapowanie go do pola modelu o tej samej nazwie.

from django.utils import timezone 
from django.db import models 


class MyModel(models.Model): 

    file = models.ImageField(upload_to=u'photos') 
    is_active = models.BooleanField(default=False) 
    created_at = models.DateTimeField(default=timezone.now) 

    def __unicode__(self): 
     return u"photo {0}".format(self.file.url) 

W serializer.py, zmień pole źródłowego do pliku:

class MyModelSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = MyModel 
     fields = ('id', 'file', 'created_at') 

W views.py, nie wywołanie super, ale zadzwonić create():

from rest_framework import generics 
from rest_framework.parsers import FileUploadParser 

from .serializer import MyModelSerializer 


class MyModelView(generics.CreateAPIView): 
    serializer_class = MyModelSerializer 
    parser_classes = (FileUploadParser,) 

    def post(self, request, *args, **kwargs): 
     """ 
      Create a MyModel 
      --- 
      parameters: 
       - name: file 
        description: file 
        required: True 
        type: file 
      responseMessages: 
       - code: 201 
        message: Created 
     """ 
     return self.create(request, *args, **kwargs) 

mam używane rozszerzenie Chrome Postman do testowania tego.Mam przesłanych obrazów jako pliki binarne, a ja ręcznie ustawić dwa nagłówki:

Content-Disposition: attachment; filename=upload.jpg 
Content-Type: */* 
+0

Próbowałem zmian, które zasugerowałeś, ale teraz mam inny błąd: 'Prześlij prawidłowy obraz. Przesłany plik nie był obrazem ani uszkodzonym obrazem " – jarussi

3

To było moje doświadczenie, że FileUploadParser prace z tym formatem wniosku:

curl -X POST -H "Content-Type:multipart/form-data" \ 
       -F "[email protected]{filename};type=image/jpg" \ 
       https://endpoint.com/upload-uri/ 

request.data['file'] w swojej widok będzie miał plik.

Może jeśli spróbujesz nagłówka Content-Type:multipart/form-data, będziesz miał szczęście.

+0

Dziękuję zemekeneng, ale nadal otrzymuję komunikat o błędzie: ' {"file": ["Przesłany plik jest pusty."]} '. To nie zadziałało. – jarussi

+0

Może spróbuj wywołać go za pomocą 'curl' i upewnij się, że nazwa pliku znajduje się w' {} ', więc wygląda na to, że' file = @ {ścieżka/do/plik} ', jeśli to zadziała, może to być klient -bok. Powodzenia! – zemekeneng