我有一个应用程序,当前允许用户上传文件,它将文件保存在Web服务器上.我的客户现在决定使用第三方云托管服务来满足他们的文件存储需求.该公司有自己的API用于在其服务器上进行CRUD操作,因此我编写了一个脚本来测试他们的API,并将一个文件作为base64编码的JSON有效负载发送到API.该脚本工作正常但现在我仍然坚持我应该如何将这个功能实现到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())
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
重申一下,当用户上传文件时,我不想将文件存储在Web服务器的某个地方,而是希望对文件进行base64编码,以便将文件作为JSON有效负载发送.关于什么是最好的方法来解决这个问题的任何想法?
我能说的最简单的方法是,我想避免将文件完全保存到Web服务器.我只想对文件进行编码,将其作为有效负载发送,如果可能的话,将其丢弃.
来自django文档:
上传处理程序
当用户上传文件时,Django将文件数据传递给上传处理程序 - 一个在上传时处理文件数据的小类.上传处理程序最初在FILE_UPLOAD_HANDLERS设置中定义,默认为:
["django.core.files.uploadhandler.MemoryFileUploadHandler","django.core.files.uploadhandler.TemporaryFileUploadHandler"]
MemoryFileUploadHandler和TemporaryFileUploadHandler一起提供Django的默认文件上传行为,即将小文件读入内存,将大文件读入磁盘.
您可以编写自定义处理程序来自定义Django处理文件的方式.例如,您可以使用自定义处理程序来强制执行用户级配额,动态压缩数据,渲染进度条,甚至直接将数据发送到另一个存储位置,而无需在本地存储. 有关如何自定义或完全替换上载行为的详细信息,请参阅编写自定义上载处理程序.
相反的想法:
我认为你应该考虑坚持使用默认的文件上传处理程序,因为它们会阻止某人上传一个会压倒服务器内存的文件.
在保存上传的文件之前,需要将数据存储在某处.
默认情况下,如果上传的文件小于2.5兆字节,Django会将上传的全部内容保存在内存中.这意味着保存文件只涉及从内存中读取和写入磁盘,因此非常快.
但是,如果上传的文件太大,Django会将上传的文件写入存储在系统临时目录中的临时文件中.在类似Unix的平台上,这意味着你可以期待Django生成一个名为/tmp/tmpzfp6I6.upload的文件.如果上传足够大,您可以观看此文件的大小增长,因为Django将数据流式传输到磁盘上.
这些细节 - 2.5兆字节; 的/ tmp; - 只是"合理的默认值",可以按照下一节中的描述进行自定义.
Run Code Online (Sandbox Code Playgroud)#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并且
<form>发布请求的具有该属性 ,则request.FILES将仅包含数据enctype="multipart/form-data".否则,request.FILES将为空.
包含所有上传文件的类字典对象.FILES中的每个键都是来自的名称
<input type="file" name="" />.FILES中的每个值都是UploadedFile.
当用户上传文件时,Django将文件数据传递给上传处理程序 - 一个在上传时处理文件数据的小类.上传处理程序最初在FILE_UPLOAD_HANDLERS设置中定义,默认为:
["django.core.files.uploadhandler.MemoryFileUploadHandler","django.core.files.uploadhandler.TemporaryFileUploadHandler"]
该源代码用于TemporaryFileUploadHandler包含此:
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
Run Code Online (Sandbox Code Playgroud)
和源代码的TemporaryUploadedFile包含此:
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
Run Code Online (Sandbox Code Playgroud)
python tempfile文档说这个:
tempfile.NamedTemporaryFile(....,delete = True)
...
如果delete为true(默认值),则文件一关闭就会被删除.
同样,两个默认文件上载处理程序中的另一个MemoryFileUploadHandler,创建一个BytesIO类型的文件:
使用内存中字节缓冲区的流实现.它继承了BufferedIOBase.调用close()方法时,将丢弃缓冲区.
因此,您所要做的就是request.FILES[“field_name”]擦除文件(无论文件内容是存储在内存中还是存储在/ tmp文件目录中的磁盘上),例如:
uploaded_file = request.FILES[“json_file”]
file_contents = uploaded_file.read()
#Send file_contents to other server here.
uploaded_file.close() #erases file
Run Code Online (Sandbox Code Playgroud)
如果由于某种原因你根本不想让django写入服务器的/tmp目录,那么你需要编写一个自定义文件上传处理程序来拒绝过大的上传文件.
| 归档时间: |
|
| 查看次数: |
2454 次 |
| 最近记录: |