2016-04-18 29 views
17

Ho creato un modello semplice con un ImageField e voglio fare una vista api con django-rest-framework + django-rest-swagger, che è documentato ed è in grado di caricare il file .Django REST Framework + Django REST Swagger + ImageField

Ecco cosa ho ottenuto:

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()), 
) 

Per me questo dovrebbe essere abbastanza semplice. Tuttavia, non riesco a far funzionare il caricamento. Ho sempre trovato questa risposta errore: enter image description here

Ho letto questa parte della documentazione da 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.

Tuttavia l'intestazione viene superato da django-riposo-spavalderia nella Richiesta Payload proprietà (dalla console cromata).

Se sono necessarie ulteriori informazioni, fatecelo sapere.

Sto usando Django==1.8.8, djangorestframework==3.3.2 e django-rest-swagger==0.3.4.

+0

Avete installato Pillow? Credo che django rest serva per elaborare i file di immagine https://pypi.python.org/pypi/Pillow –

+0

Grazie Charles .. ma sì, ho installato il cuscino. – jarussi

risposta

3

Questa è la soluzione finale mi si avvicinò con:

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) 

Tutto quello che dovevo fare era cambiare i parser da FileUploadParser-(FormParser, MultiPartParser)

+0

Cosa devi fare per ottenere DRF o DRF-Swagger per raccogliere quel file? Ho impostato una docstring del genere, ma viene semplicemente visualizzata come Markdown in "Note di implementazione" –

+0

Non ho molto nelle mie impostazioni. Sono praticamente la base dei documenti di django-rest-swagger. Comunque, sto usando la versione '0.3.7' di django-rest-swagger. – jarussi

7

Ho ottenuto questo lavorando apportando un paio di modifiche al codice.

Innanzitutto, in models.py, modificare il ImageField nome in file e utilizzare il percorso relativo per caricare la cartella. Quando carichi il file come stream binario, è disponibile nel dizionario request.data sotto il codice file (request.data.get('file')), quindi l'opzione più pulita è mapparla al campo modello con lo stesso nome.

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) 

In serializer.py, rinominare campo di origine di file:

class MyModelSerializer(serializers.ModelSerializer): 

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

In views.py, non chiamare super, ma chiamare creare():

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) 

ho usato estensione Postman Chrome per testare questo.Ho caricato immagini come file binari e ho impostato manualmente due intestazioni:

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

Ho provato le modifiche suggerite, ma ora sto riscontrando un errore diverso: 'Carica un'immagine valida. Il file che hai caricato non era un'immagine o un'immagine corrotta' – jarussi

3

E 'stata la mia esperienza che le FileUploadParser opere con questo formato di una richiesta:

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

Il request.data['file'] nella vostra la vista avrà il file.

Forse se provi l'intestazione Content-Type:multipart/form-data, avrai fortuna.

+0

Grazie a zemekeneng, ma ottengo ancora ed errore: '{" file ": [" Il file inviato è vuoto. "]}'. Quello non ha funzionato. – jarussi

+0

Forse prova a chiamarlo con 'curl' e assicurati che il nome del file sia all'interno di' {} ', in modo che assomigli a' file = @ {percorso/a/file} ', se funziona, il problema potrebbe essere il client -lato. In bocca al lupo! – zemekeneng

Problemi correlati