将来自响应的zip文件添加到Django的FileField中。
将来自响应的zip文件添加到Django的FileField中。
目前我正在调用一个API,它会返回一个zip文件。当使用requests
库时,\n
res = requests.post('http://url/to/api', files={'file_pro': *my_file*})
\n我可以得到一个成功的响应,其中包含以字符串形式返回的zip文件。\n当我检查res.contents的内容时,我得到的是:\n
PK\x03\x04\x14\x00\x00\x00\x08\x00\x0c\x83HH\xba\xd2\xf1\t\xa1\x00\x00\x00\x04\x01\x00\x00....05\x06\x00\x00\x00\x00\x08\x00\x08\x00\x1e\x02\x00\x00$\x04\x00\x00\x00\x00
\n看起来它返回的是一个字符串形式的zip文件。我参考了这个问题here,试图将这个字符串转换回原始的zip文件。具体来说,我写了以下代码:\n
my_file = UploadedFile(file=File(zipfile.ZipFile(StringIO.StringIO(res.content)),'r')) my_file.save()
\n在尝试保存时,我得到了以下错误:\n
KeyError: 'There is no item named 65536 in the archive'
\n我的最终目标是将这个zip文件绑定到一个UploadedFile
类上:\n
class UploadedFile(BaseModel): file = models.FileField(upload_to='/path', max_length=255)
\n如果我使用HTML表单来访问这个API,请求成功后我的浏览器会自动下载这个zip文件。有没有办法解决这个问题?
问题的原因是作者试图将从API响应中获取的zip文件添加到Django的FileField中,但是作者使用了错误的方法和对象来实现这一目标。
解决方法是使用SimpleUploadedFile
对象将API响应的内容转换为可用于Django的文件,并将其保存到FileField中。另外,还提供了使用File(BytesIO(res.content))
和ContentFile
的替代方法。
以下是解决方法的代码示例:
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.base import File from django.core.files.base import ContentFile from io import BytesIO import zipfile # res.content is the bytes of your API response res = request.post('http://url/to/api', files={'file_pro': *myfile*}) # Option 1: Using SimpleUploadedFile my_file = SimpleUploadedFile('temp.zip', res.content) # Verify the zip file assert zipfile.is_zipfile(my_file) # Finally save the file uploaded_file = UploadedFile(file=my_file) uploaded_file.save() # Play around with the zipfile with zipfile.ZipFile(uploaded_file.file) as my_zip_file: print(my_zip_file.infolist()) # Option 2: Using File(BytesIO()) my_file = File(BytesIO(res.content)) # Verify the zip file assert zipfile.is_zipfile(my_file) # Finally save the file uploaded_file = UploadedFile(file=my_file) uploaded_file.save() # Play around with the zipfile with zipfile.ZipFile(uploaded_file.file) as my_zip_file: print(my_zip_file.infolist()) # Option 3: Using ContentFile my_file = ContentFile(res.content, 'temp.zip') # Verify the zip file assert zipfile.is_zipfile(my_file) # Finally save the file uploaded_file = UploadedFile(file=my_file) uploaded_file.save() # Play around with the zipfile with zipfile.ZipFile(uploaded_file.file) as my_zip_file: print(my_zip_file.infolist())
需要注意的是,zipfile.ZipFile
接受文件名或类似文件的对象作为参数。在问题中,作者直接传递了一个字符串/字节。
此外,还建议将UploadedFile
模型的名称更改为其他名称,因为Django已经在django.core.files.uploadedfile.UploadedFile
中内置了一个模型。
SimpleUploadedFile
是Django中File
的子类,其实现使用了Python的BytesIO
。如果不想使用SimpleUploadedFile
,可以通过File(BytesIO(res.content))
实现相同的效果。
作者尝试使用ContentFile
,也得到了成功的结果。