You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 16:44:08