2016-06-20 7 views
2

현재 사용자가 파일을 업로드 할 수있는 앱이 있으며 웹 서버에 파일을 저장합니다. 고객은 이제 파일 저장 요구에 제 3 자 클라우드 호스팅 서비스를 사용하기로 결정했습니다. 회사는 자신의 서버에서 CRUD 작업을 수행하기 위해 자체 API를 가지고 있으므로 API를 테스트하는 스크립트를 작성하고 파일을 base64로 인코딩 된 JSON 페이로드로 API에 보냅니다. 스크립트는 정상적으로 작동하지만 지금은 어떻게이 기능을 장고에 구현해야하는지 정확히 파악하고 있습니다.서버에 업로드하는 대신 JSON을 통해 파일 보내기 Django

json_testing.py

import base64 
import json 
import requests 
import magic 

filename = 'test.txt' 

# Open file and read file and encode it as a base64 string 
with open(filename, "rb") as test_file: 
    encoded_string = base64.b64encode(test_file.read()) 

# Get MIME type using magic module 
mime = magic.Magic(mime=True) 
mime_type = mime.from_file(filename) 

# Concatenate MIME type and encoded string with string data 
# Use .decode() on byte data for mime_type and encoded string 
file_string = 'data:%s;base64,%s' % (mime_type.decode(), encoded_string.decode()) 
payload = { 
    "client_id": 1, 
    "file": file_string 
} 
headers = { 
    "token": "AuthTokenGoesHere", 
    "content-type": "application/json", 
} 
request = requests.post('https://api.website.com/api/files/', json=payload, headers=headers) 
print(request.json()) 

models.py

def upload_location(instance, filename): 
    return '%s/documents/%s' % (instance.user.username, filename) 

class Document(models.Model): 
    user = models.ForeignKey(settings.AUTH_USER_MODEL) 
    category = models.ForeignKey(Category, on_delete=models.CASCADE) 
    file = models.FileField(upload_to=upload_location) 

    def __str__(self): 
     return self.filename() 

    def filename(self): 
     return os.path.basename(self.file.name) 
이 사용자 대신 웹 서버에 어딘가에 파일을 저장하는, 파일을 업로드 할 때, 반복하는, 내가 base64로 원하는

파일을 인코딩하여 JSON 페이로드로 파일을 보낼 수 있습니다. 이것에 접근하는 가장 좋은 방법은 무엇이 될지에 대한 아이디어가 있습니까?

+0

나는 이해할 수 없다. 이미 적절한 요청을하는 법을 알고 있습니다. 문제가 어디에 있습니까? – freakish

+0

@freakish. 물리적으로 웹 서버에 파일을 저장하는 대신 파일을 인코딩하고 페이로드로 보내고 파일을 삭제하기 만하면됩니다. 파일을 업로드 한 다음 인코딩을 수행하고 JSON 페이로드로 보낸 다음 파일을 삭제해야합니까? 웹 서버에 파일을 저장하지 않고 메모리에 파일을 인코딩 할 수있는 방법이 있는지 궁금합니다. – nastyn8

+0

그냥 dhango app에서 스크립트를 호출하는 대신 u를 사용하는 대신 스크립트를 사용합니다. .. –

답변

4

내가 넣을 수있는 가장 간단한 방법은 웹 서버에 파일을 완전히 저장하지 않으려는 것입니다. 난 그냥 파일을 인코딩하려면 페이로드로 보내고, 가능하다면 그것을 버리고 싶습니다. django docs에서

: - 그것으로 파일 데이터를 처리하는 작은 클래스

업로드 핸들러 사용자가 파일을 업로드

는 장고는 업로드 핸들러에 파일 데이터를 전달 가 업로드됩니다.

[ "django.core.files.uploadhandler.MemoryFileUploadHandler" "django.core.files.uploadhandler.TemporaryFileUploadHandler"] 함께

: 업로드 핸들러는 처음 FILE_UPLOAD_HANDLERS 설정, 기본값에 정의되어 있습니다 MemoryFileUploadHandler 및 TemporaryFileUploadHandler가 작은 파일을 작은 메모리에서 메모리로 읽고 큰 파일을 디스크에 저장하는 기본 파일 업로드 동작을 제공합니다.

당신은 장고 파일을 처리하는 방법을 사용자 정의 핸들러를 작성할 수 있습니다. 당신은, 예를 들어, 진행률 표시 줄을 렌더링, 실시간으로 데이터를 압축, 사용자 레벨 할당량을 적용 할 을 사용자 정의 핸들러를 사용하고도 직접 로컬을 저장하지 않고 다른 저장 위치에 데이터를 보낼 수 있습니다. 수있는 방법에 대한 자세한 내용은 See Writing custom upload handlers을 업로드하거나 업로드 동작을 완전히 대체하십시오.

반대로 생각 :

나는 그들이 서버의 메모리를 압도하는 파일을 업로드 누군가를 유지하기 때문에 기본 파일 업로드 핸들러 고수 고려해야한다고 생각합니다.

Where uploaded data is stored

당신이 업로드 된 파일을 저장하기 전에

는, 데이터가 어딘가에 저장해야합니다.

기본적으로 업로드 된 파일이 2.5MB보다 작 으면 Django 은 업로드의 전체 내용을 메모리에 보관합니다. 즉, 파일을 저장하는 은 메모리에서 읽기와 디스크 에 쓰기 만하므로 매우 빠릅니다.

그러나 업로드 된 파일이 너무 크면 장고는 디렉토리에 저장된 임시 파일에 업로드 파일을 씁니다. 유닉스와 같은 플랫폼에서 이것은 장고가 에 /tmp/tmpzfp6I6.upload와 같은 파일을 생성 할 것을 기대할 수 있음을 의미합니다. 업로드가 충분히 큰 경우 Django 이 디스크로 데이터를 스트리밍하므로이 파일의 크기가 커지는 것을 볼 수 있습니다.

이러한 세부 사항 - 2.5 메가 바이트;/tmp; 등등 - 다음 섹션에서 설명하는대로 사용자 정의 할 수있는 "합리적인 기본값"입니다.


request.FILES info :

#forms.py: 

from django import forms 

class UploadFileForm(forms.Form): 
    title = forms.CharField(max_length=50) 
    json_file = forms.FileField() 

, request.FILES 각 및 FileField위한 키를 포함하는 사전이다 (또는 ImageField이 파일 데이터를 수신 할 양식 운반보기 , 또는 다른 FileField 서브 클래스)를 양식에 추가하십시오. 따라서 위의 양식 의 데이터는 request.FILES [ 'json_file']로 액세스 할 수 있습니다.

요청 방법 가 POST 인 경우 request.FILES는 데이터가 포함됩니다 참고하고 요청을 게시 <form>는 속성 enctype="multipart/form-data" 있습니다. 그렇지 않으면 request.FILES가 비어 있습니다.


HttpRequest.FILES

모든 업로드 된 파일을 포함하는 사전 같은 객체

. FILES의 각 키는 <input type="file" name="" />의 이름입니다. FILES의 각 값 은 UploadedFile입니다. 이 업로드수록 파일 데이터를 처리하는 작은 클래스 -

Upload Handlers

사용자가 파일을 업로드


는 장고는 업로드 핸들러에 파일 데이터를 전달합니다.

[ "django.core.files.uploadhandler.MemoryFileUploadHandler" "django.core.files.uploadhandler : 업로드 핸들러는 초기에 기본값으로 FILE_UPLOAD_HANDLERS 설정에 정의되어 있습니다.

: tempfile docs이 말을

class TemporaryUploadedFile(UploadedFile): 
    """ 
    A file uploaded to a temporary location (i.e. stream-to-disk). 
    """ 
    def __init__(self, name, content_type, size, charset, content_type_extra=None): 
     ... 
     file = tempfile.NamedTemporaryFile(suffix='.upload') #<***HERE 

그리고 파이썬 :

lass TemporaryFileUploadHandler(FileUploadHandler): 
    """ 
    Upload handler that streams data into a temporary file. 
    """ 
     ... 
     ... 
     def new_file(self, *args, **kwargs): 
     """ 
     Create the file object to append to as data is coming in. 
     """ 
     ... 
     self.file = TemporaryUploadedFile(....) #<***HERE 

그리고 TemporaryUploadedFile에 대한 source code이 포함 TemporaryFileUploadHandler "]

TemporaryFileUploadHandlersource code이 포함

tempfile.NamedTemporaryFile
...
삭제하는 경우는 true (디폴트), 파일을 즉시 닫을으로 삭제됩니다 (..., = TRUE 삭제). 메모리 내 버퍼 바이트 사용

스트림 구현 :

마찬가지로, 두 개의 기본 파일 업로드 핸들러 MemoryFileUploadHandler의 다른 유형 BytesIO의 파일을 생성한다. 그것은 BufferedIOBase를 상속받습니다. close() 메소드가 이라면 버퍼가 삭제됩니다.

uploaded_file = request.FILES[“json_file”] 
file_contents = uploaded_file.read() 

#Send file_contents to other server here. 

uploaded_file.close() #erases file 

경우 :

따라서, 당신이 할 일은 (파일 내용이 메모리 또는/tmp 파일 디렉토리의 디스크에 저장되어 있는지) 파일을 삭제하는 가까운 request.FILES[“field_name”] 예입니다 django가 서버의 /tmp 디렉토리에 쓰기를 원하지 않는 어떤 이유로 든 너무 큰 업로드 된 파일을 거부하는 사용자 정의 파일 업로드 처리기를 작성해야합니다.

+1

@ nastyn8, 이것에 대해 좀 더 생각해 보았습니다. 기본 파일 업로드 처리기는 잘 고려되어 있으므로 원하는 작업을 수행하기 위해 사용자 정의 업로드 처리기를 만들 필요가 없습니다. 내 답변 하단에 추가 설명을 참조하십시오. – 7stud

관련 문제