2016-03-15 180 views
1

我正在编写一个API,允许客户端发布文件链接,然后我想下载该文件并将其作为FileField存储在我的某个模型上。这里是我的代码至今:Django Rest Framework - 下载服务器上的文件

串行:

from rest_framework import serializers 
from django.core.files import File 
from rest_framework.serializers import ValidationError 

class MySerializer(serializers.ModelSerializer): 

    class Meta: 
     model = MyModel 
     fields = ('url') 

    def to_internal_value(self, data): 
     validated = dict() 

     url = data.get('url') 

     # do url validation here 

     # download the file to local disk 

     validated['file'] = File(open('path/to/downloaded/file')) 
     validated['url'] = url 

     return validated 

型号:

from django.db import models 


class MyModel(models.Model): 
    url = models.CharField(max_length=255) 
    file = models.FileField(upload_to='files/') 

对于视图,我用一个通用的ListCreateAPIView

有两个主要的问题,第一个是在我目前的实现中,我最终得到了两个副本的文件,因为我先下载到磁盘上的某个位置,然后当FileField存储到数据库中时将文件再次复制到files/文件夹。有没有办法避免这种情况?其次,我怎样才能异步下载文件,但仍可以在下载完成后在模型上添加FileField属性?

回答

4

做同样的事情将是一个更好的方式来创建自己的serializer field

from django.core.validators import URLValidator 
from django.core.files.base import ContentFile 

from rest_framework import serializers 

from urllib.request import urlretrieve 

class FileUrlField(serializers.FileField): 
    def to_internal_value(self, data): 
     try: 
      URLValidator()(data) 
     except ValidationError as e: 
      raise ValidationError('Invalid Url') 

     # download the contents from the URL 
     file, http_message = urlretrieve(data) 
     file = File(open(file, 'rb')) 
     return super(FileUrlField, self).to_internal_value(ContentFile(file.read(), name=file.name)) 

,然后用它在你的serializer

但是我没有测试,但应该工作。