2013-12-09 118 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