16

can someone help me how to upload file with POST method in django rest api, for example when I launch

curl -X POST 127.0.0.1:8000/api/v1/assets/ -d '{"name" = "my image   ","source"="/root/images/my_image2.jpg"}' -H "Content-Type: application/json"

I want to upload my_image2.jpg

serializers.py:

from django.forms import widgets
from rest_framework import serializers
from .models import Asset

class AssetSerializer(serializers.ModelSerializer):
    class Meta:
        model = Asset

views.py:

from .serializers import AssetSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from rest_framework import status
from rest_framework.decorators import api_view


class AssetAdd(APIView):


    def post(self, request, format=None):
        serializer = AssetSerializer(data=request.DATA)
        print serializer.data

        if serializer.is_valid():

            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

models.py

class Asset(models.Model):

    key = models.CharField(max_length=8, unique=True, editable=False)
    name = models.CharField(_('name'), max_length=200)
    source = models.FileField(_('file'), upload_to=upload_to, storage=default_storage)

    ext = models.CharField(max_length=15, editable=False)
    type = models.PositiveIntegerField(choices=ASSET_TYPE, max_length=15, editable=False)
    size = models.PositiveIntegerField(max_length=32, default=0, editable=False)

    _file_meta = models.TextField(editable=False, null=True, blank=True)

    public = models.BooleanField(default=False)
    position = models.PositiveIntegerField(default=1)

    object_id = models.PositiveIntegerField(default=1)
    content_type = models.ForeignKey(ContentType, blank=True, null=True)
    content_object = generic.GenericForeignKey('content_type', 'object_id')

    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now_add=True, auto_now=True)

I'm newbie in Django REST API , I read documentation http://www.django-rest-framework.org/api-guide/parsers.html#fileuploadparser , but still don't undestand how to do it

Fiver
  • 9,909
  • 9
  • 43
  • 63
blaz1988
  • 346
  • 1
  • 7
  • 15
  • Possible duplicate of [Django Rest Framework File Upload](http://stackoverflow.com/questions/20473572/django-rest-framework-file-upload) – Dhia Mar 03 '16 at 07:29

2 Answers2

25

First of all you need to define a parser in your view. This is because the API needs to know which headers to look for. Browsers transfer files as form-data, so you need to use the MultiPartParser and FormParser together. You can also use the FileUploadParser but you need to make sure your client is sending the correct HTTP headers.

from rest_framework.parsers import MultiPartParser, FormParser

class AssetAdd(APIView):
    parser_classes = (MultiPartParser, FormParser,)

Then, in the post method, your file will be present in the FILES QueryDict:

def post(self, request, format=None):
    my_file = request.FILES['file_field_name']
    filename = '/tmp/myfile'
    with open(filename, 'wb+') as temp_file:
        for chunk in my_file.chunks():
            temp_file.write(chunk)

    my_saved_file = open(filename) #there you go
JJD
  • 50,076
  • 60
  • 203
  • 339
fixmycode
  • 8,220
  • 2
  • 28
  • 43
  • please can you explain me in more details, – blaz1988 Jun 26 '14 at 14:18
  • I added class AssetAdd(APIView): parser_classes = (MultiPartParser, FormParser,) def post(self, request, format=None): my_file = request.FILES['file_field_name'] print my_file – blaz1988 Jun 26 '14 at 14:20
  • 1
    when I tried to execute {"name": "San Francisco Bridge", "source": "assets/34/3492/3492AA/3492AA/source.jpg"} , but get error { "detail": "Multipart form parse error - Invalid boundary in multipart: None" } – blaz1988 Jun 26 '14 at 14:25
  • I tried curl -X POST http://127.0.0.1:8000/api/v1/assets/ -d '{"name": "San Francisco Bridge", "source": "assets/34/3492/3492AA/3492AA/source.jpg"}' -H "Content-Type: multipart/form-data" but get error { "detail": "Multipart form parse error - Invalid boundary in multipart: None" } ??? – blaz1988 Jun 26 '14 at 16:59
  • Yeah... uhm, file uploads and curl don't work that way, you can't send the file route in your computer and expect the system to know it has to retrieve the file. Also, what you're sending is not multi-part because it doesn't have a file attached. Take a look at this: https://ariejan.net/2010/06/07/uploading-files-with-curl/ – fixmycode Jun 27 '14 at 17:36
  • Where can I import the MultiPartParser and FormParser from? – LondonAppDev Nov 21 '14 at 17:00
  • 1
    @MarkWinterbottom `from rest_framework.parsers import MultiPartParser, FormParser` – fixmycode Nov 21 '14 at 17:18
  • @fixmycode Can you help me with question http://stackoverflow.com/questions/27833413/django-rest-upload-file-and-invalid-email – tmquang6805 Jan 08 '15 at 06:34
0

Write your models like this:

from django.db import models
class PicModel(models.Model):
    file_to_be_uploaded = models.FileField(upload_to='/directory/where/you/what/to/upload/to')

if you uploading images then ImageField but install pillow by pip install pillow.

In you serializers.py assuming you are using rest_framework:

from rest_framework import serializers
from app_name.models import PicModel

class PicSerializer(serializers.ModelSerializer):
    class Meta:
        model = PicModel
        fields = '__all__' #or any way you may like to display you fields

In you views.py include assuming you are to using class-base views:

from app_name.models import PicModel
from app_name.serializers import PicModelSerializer
#other necessary imports

class PicList(APIView):
    def post(self, request, format=None):#or format can be json or api
        serializer = PicModelSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            ............more code

To test in json data write like:

{
    "file_to_be_uploaded":"//path//to//file//on//local//machine"
}
Aula
  • 121
  • 1
  • 3