2013-12-09 146 views
41

我正在使用Django Rest Framework和AngularJs上傳文件。我的觀點文件看起來像這樣:Django Rest Framework文件上傳

class ProductList(APIView): 
    authentication_classes = (authentication.TokenAuthentication,) 
    def get(self,request): 
     if request.user.is_authenticated(): 
      userCompanyId = request.user.get_profile().companyId 
      products = Product.objects.filter(company = userCompanyId) 
      serializer = ProductSerializer(products,many=True) 
      return Response(serializer.data) 

    def post(self,request): 
     serializer = ProductSerializer(data=request.DATA, files=request.FILES) 
     if serializer.is_valid(): 
      serializer.save() 
      return Response(data=request.DATA) 

由於POST方法的最後一行應該返回所有的數據,我有幾個問題:

  • 如何檢查是否有在request.FILES什麼?
  • 如何序列化文件字段?
  • 我該如何使用解析器?

回答

31

使用FileUploadParser,這一切都在請求。 使用put方法來代替,你會發現在文檔:)

class FileUploadView(views.APIView): 
    parser_classes = (FileUploadParser,) 

    def put(self, request, filename, format=None): 
     file_obj = request.FILES['file'] 
     # do some stuff with uploaded file 
     return Response(status=204) 
+0

哎,你知道我怎麼能解決http://stackoverflow.com/questions/26673572/django-rest-framework-upload-file-to-a-method? – psychok7

+2

@pleasedontbelong爲什麼使用PUT方法而不是POST? – RTan

+0

@Rego check this http://stackoverflow.com/a/14402607/361427 :) – pleasedontbelong

45

我使用的是相同的堆棧和實例也一直在尋找文件上傳的例子,但因爲我我的情況比較簡單使用ModelViewSet而不是APIView。關鍵原來是pre_save鉤子。我最終將它與angular-file-upload模塊一起使用,如下所示:

# Django 
class ExperimentViewSet(ModelViewSet): 
    queryset = Experiment.objects.all() 
    serializer_class = ExperimentSerializer 

    def pre_save(self, obj): 
     obj.samplesheet = self.request.FILES.get('file') 

class Experiment(Model): 
    notes = TextField(blank=True) 
    samplesheet = FileField(blank=True, default='') 
    user = ForeignKey(User, related_name='experiments') 

class ExperimentSerializer(ModelSerializer): 
    class Meta: 
     model = Experiment 
     fields = ('id', 'notes', 'samplesheet', 'user') 

// AngularJS 
controller('UploadExperimentCtrl', function($scope, $upload) { 
    $scope.submit = function(files, exp) { 
     $upload.upload({ 
      url: '/api/experiments/' + exp.id + '/', 
      method: 'PUT', 
      data: {user: exp.user.id}, 
      file: files[0] 
     }); 
    }; 
}); 
+1

謝謝!一個很好的(而且非常完整的)參考! – WhyNotHugo

+3

pre_save在drf 3.x中已棄用 –

18

最後,我可以使用Django上傳圖像。這是我工作的代碼

views.py

class FileUploadView(APIView): 
    parser_classes = (FileUploadParser,) 

    def post(self, request, format='jpg'): 
     up_file = request.FILES['file'] 
     destination = open('/Users/Username/' + up_file.name, 'wb+') 
     for chunk in up_file.chunks(): 
      destination.write(chunk) 
      destination.close() 

     # ... 
     # do some stuff with uploaded file 
     # ... 
     return Response(up_file.name, status.HTTP_201_CREATED) 

urls.py上傳

curl -X POST -S -H -u "admin:password" -F "[email protected];type=image/jpg" 127.0.0.1:8000/resourceurl/imageUpload 
+11

爲什麼destination.close()放置在for循環的內部? – makerj

+4

似乎最好使用'open('/ Users/Username /'+ up_file.name,'wb +')作爲目標:'並完全關閉 –

2

我解決了這個問題,ModelViewSet和ModelSerializer

urlpatterns = patterns('', 
url(r'^imageUpload', views.FileUploadView.as_view()) 

捲曲請求。希望這會幫助社區。

我也試圖在序列化程序本身而不是視圖中進行驗證和Object-> JSON(反之亦然)登錄。

讓我們通過實例來了解它。

說,我想創建FileUploader API。它將在數據庫中存儲諸如id,file_path,file_name,size,owner等字段。請參見下面示例模型:

class FileUploader(models.Model): 
    file = models.FileField() 
    name = models.CharField(max_length=100) #name is filename without extension 
    version = models.IntegerField(default=0) 
    upload_date = models.DateTimeField(auto_now=True, db_index=True) 
    owner = models.ForeignKey('auth.User', related_name='uploaded_files') 
    size = models.IntegerField(default=0) 

現在,對於API的,這是我想要的東西:

  1. GET: 當我火GET終點,我想每一個上傳文件的所有上述領域。

  2. POST: 但是,對於用戶創建/上傳文件,爲什麼她必須擔心通過所有這些領域。她可以上傳文件,然後,我想,序列化程序可以從上傳的文件中獲得剩餘的字段。

Searilizer: 問題:我下面串行創建爲我的目的。但不確定是否有正確的實施方式。

class FileUploaderSerializer(serializers.ModelSerializer): 
    #overwrite = serializers.BooleanField() 
    class Meta: 
     model = FileUploader 
     fields = ('file','name','version','upload_date', 'size') 
     read_only_fields = ('name','version','owner','upload_date', 'size') 

    def validate(self, validated_data): 
      validated_data['owner'] = self.context['request'].user 
      validated_data['name'] =  os.path.splitext(validated_data['file'].name)[0] 
      validated_data['size'] = validated_data['file'].size 
      #other validation logic 
     return validated_data 

    def create(self, validated_data): 
     return FileUploader.objects.create(**validated_data) 

視圖集以供參考:

class FileUploaderViewSet(viewsets.ModelViewSet): 
    serializer_class = FileUploaderSerializer 
    parser_classes = (MultiPartParser, FormParser,) 

    # overriding default query set 
    queryset = LayerFile.objects.all() 

    def get_queryset(self, *args, **kwargs): 
     qs = super(FileUploaderViewSet, self).get_queryset(*args, **kwargs) 
     qs = qs.filter(owner=self.request.user) 
     return qs 
0

在Django靜止框架請求數據由Parsers解析。
http://www.django-rest-framework.org/api-guide/parsers/

默認情況下,django-rest-framework需要解析器類JSONParser。它會將數據解析爲json。所以,文件將不會被解析。
如果我們想要將文件與其他數據一起解析,我們應該使用下面的解析器類之一。

FormParser 
MultiPartParser 
FileUploadParser