因为某些原因,不想使用 imagefield 字段,而是将上传的所有图片地址统一返回前端,但是今天前端的朋友给我反馈

Image

当时看见这个,我还不太相信,于是去测试了一番 api

Image

哇,生成这么多残缺的图片

Image

测试期间生成的图片实在有些多..

原版

save_path = pathlib.Path(settings.MEDIA_ROOT) / get_type / f'{uuid.uuid4().hex}{pathlib.Path(form)}'
    if not pathlib.Path(settings.MEDIA_ROOT).is_dir():
        pathlib.Path(settings.MEDIA_ROOT).mkdir(parents=True)
    for content in img.chunks():
        save_path.write_bytes(content)
        ready_save.append((pathlib.Path(settings.MEDIA_URL) / get_type /
                           f'{save_path.name}').as_posix())
        save_path = pathlib.Path(settings.MEDIA_ROOT) / get_type / f'{uuid.uuid4().hex}{pathlib.Path(form)}'

看源代码...就发现了问题 save_path 的重新赋值多余了...,可以看看之前的文章,每次的 for 已经赋值过了,我想为什么会存在,可能是我之前从 os 改为 pathlib 时,没有改完全吧。

还有为什么出了这么多的 uri,我们看返回的关键字典 ready_save,原来这里的 ready_save 在 for 里有问题,为什么有问题呢? 这也是我在这里讲的为什么是大容量图片优化版!!!,对于上次的文章代码来说,出了 save_path 赋值重复这个小问题,ready_save 在哪都没有问题

我们首先得print(content)看看,再增加个区分符 Image

这样我们就能发现问题,大容量的图片,content 分两次出来了,每次都只是部分图片信息,所以保存的图片才是残缺的,而小容量的图片 for 就只有一次,所以 content 根本不需要拼接!!!所以我才说在哪都一样。

这里放出优化版的

insert_content = b''
for content in img.chunks():
  insert_content += content
save_path.write_bytes(insert_content)
ready_save.append((pathlib.Path(settings.MEDIA_URL) / get_type /
                                   f'{save_path.name}').as_posix())

注意图片信息已经写入的是二进制,所以我们得赋值个二进制编码!!! 然后我们人为的来拼接,再去读取写入

到这里,可能会有人问,chunks()是什么啊

我看到有对这个的阐述

class UploadedFile

在文件上传的期间,实际的文件数据被存储在 request.FILES。在这个字典中的每一项都是一个 UploadedFile 对象或者是子类的对象。这是一个对已经上传文件的简单封装,你可以通过以下方法进行访问上传的内容。

方法:

read()

从该文件中读取整块上传的数据,使用这个方法必须小心,如果该上传的文件特别大,它将使得你的系统崩溃,相反你可以使用 chunks()方法来一小块小块的读取到内存中。

multiple_chunks(chunk_size=None)

如果上传的文件足够大需要在多个块(chunks)中进行读取,将会返回 True。默认情况下,这将会是任何大于 2.5 MB 的文件,但是这个是可以配置的。

chunks()

这个一个返回文件 chunks 的生成器。如果 multiple_chunks()为 True,你应该在循环中使用这个方法而不是 read()。

实际上,经常最简单的使用方法是总是使用 chunks()。然后循环这个 chunks()方法而不是使用 read(),这样确保大文件不会过分占用你的系统内存。

引用https://www.cnblogs.com/baishoujing/p/7209886.html

看完了这些,你应该就知道 chunks()的作用了!