2016-03-15 174 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

但是我沒有測試,但應該工作。