如何在Django Rest Framework中测试图片上传并清理不同目录下的临时测试图片
解决Django DRF测试中上传图片的自动清理问题
我明白你的困扰——测试时上传的图片散落在不同的media子目录里,手动清理太麻烦,自动删除又找不到正确的路径。这里有两个靠谱的方案,你可以根据需求选择:
方案一:记录测试生成的图片路径,在测试结束后删除
这个方法适合需要保留原有MEDIA配置的场景,核心是跟踪测试中创建的图片文件路径,然后在测试销毁阶段删除它们。
修改你的测试代码如下:
def temporary_image(): import tempfile from PIL import Image image = Image.new('RGB', (100, 100)) # 加上delete=False,避免文件提前被自动删除,确保Django能顺利复制 tmp_file = tempfile.NamedTemporaryFile(suffix='.jpg', prefix="test_img_", delete=False) image.save(tmp_file, 'jpeg') tmp_file.seek(0) return tmp_file class NoticiaTest(APITestCase): def setUp(self): # 先创建前置依赖的用户数据 self.usuario = Usuario.objects.create(...) # 替换成你的用户创建逻辑 self.client = APIClient() url = reverse('api:noticia-create') with temporary_image() as img_file: data = { 'usuario': self.usuario.pk, "titulo":"test", "subtitulo":"test", "descripcion":"test", "img": img_file } response = self.client.post(url, data, format="multipart") # 获取创建的Noticia对象,记录图片在media目录的实际路径 self.noticia = Noticia.objects.get(titulo="test") self.test_image_path = self.noticia.img.path # 保存临时源文件的路径,后续一起清理 self.tmp_source_path = img_file.name def tearDown(self): # 清理media目录里的测试图片 import os if os.path.exists(self.test_image_path): os.remove(self.test_image_path) # 清理系统临时目录里的源文件 if os.path.exists(self.tmp_source_path): os.remove(self.tmp_source_path)
关键点说明:
- 给
NamedTemporaryFile加上delete=False,防止PIL保存后文件被自动删除,确保Django能顺利复制它到media目录。 - 在
setUp里捕获创建的Noticia对象的img.path,这就是图片在media目录的实际存储路径。 tearDown方法会在每个测试用例执行完后自动运行,在这里完成文件清理,避免残留。
方案二:临时替换MEDIA_ROOT到临时目录(更推荐)
这个方法更干净,直接把测试期间的所有媒体文件都放到一个临时目录里,测试结束后整个目录自动销毁,不用关心单个文件的路径。
利用Django的override_settings装饰器和Python的tempfile.TemporaryDirectory来实现:
import tempfile from django.test import override_settings from PIL import Image def temporary_image(): image = Image.new('RGB', (100, 100)) tmp_file = tempfile.NamedTemporaryFile(suffix='.jpg', prefix="test_img_") image.save(tmp_file, 'jpeg') tmp_file.seek(0) return tmp_file # 临时替换MEDIA_ROOT到自动销毁的临时目录 @override_settings(MEDIA_ROOT=tempfile.TemporaryDirectory().name) class NoticiaTest(APITestCase): def setUp(self): self.usuario = Usuario.objects.create(...) self.client = APIClient() url = reverse('api:noticia-create') with temporary_image() as img_file: data = { 'usuario': self.usuario.pk, "titulo":"test", "subtitulo":"test", "descripcion":"test", "img": img_file } response = self.client.post(url, data, format="multipart") # 不需要额外写tearDown,临时目录会在测试结束后自动删除
关键点说明:
override_settings(MEDIA_ROOT=...)会临时替换Django的MEDIA配置,测试期间所有上传的图片都会放到这个临时目录里,完全不影响原有media目录。tempfile.TemporaryDirectory()创建的目录会在对象被垃圾回收时自动删除,测试结束后整个目录(包括里面的所有图片)都会被彻底清理。- 这个方案不需要跟踪单个文件路径,适合多模型、多测试用例的场景,彻底避免测试文件污染。
为什么你的原有代码没法自动删除图片?
你用的tempfile.NamedTemporaryFile默认会在文件关闭后自动删除,但Django在处理上传时,会把这个临时文件复制一份到模型upload_to指定的目录(也就是media/noticias),所以你删除的只是系统临时目录里的源文件,而media目录里的副本依然存在——这就是问题的核心所在。
内容的提问来源于stack exchange,提问作者Matias Coco
相关产品推荐
相关产品推荐

