将文件(不在MEDIA_ROOT中)从fastapi UploadFile保存到Django FileField

sd2nnvve  于 2023-08-08  发布在  Go
关注(0)|答案(1)|浏览(118)

我需要将fastapi UploadFile对象直接保存到下面定义的Django模型中:

class MyFile(models):
    file = models.FileField(upload_to="files/")

字符串
在API中,我设法使用readwrite方法从SpooledTemporaryFile中获取文件对象,如下面的代码块所示:

async def file_upload(file: UploadFile = File(...)):
    async with aiofiles.open(f"path/{file.filename}", "wb") as media:
        cont = await file.read()
        await media.write(cont)


然后我尝试在Django中将新文件转换为FieldFile类型,以便能够将其保存在MyFile.file字段中,但它一直返回TypeError和描述:write()参数必须是str,而不是generator

from django.core.files import File as DjangoFile

async def file_upload(file: UploadFile = File(...)):
    ...

    async with aiofiles.open(f"path/{file.filename}") as media:
        d_file = DjangoFile(media)

        file_model = MyFile()
        file_model.file.save(file.filename, d_file)
        file_model.save()

    return {"ok": True}


堆栈跟踪显示file_model.file.save(file.filename, d_file)是违规行。

>>> type(file.filename)
str

>>> type(d_file)
<class 'django.core.files.base.File'>


你能给我指个方向吗?

hmtdttj4

hmtdttj41#

因此,从this开始,我决定通过model方法保存MyFile,该方法主要检查dir中的最新文件,并在从upload_file API代码中调用时将其保存在file字段中,如图所示:

async def file_upload(file: UploadFile = File(...)):
    async with aiofiles.open(f"path/{file.filename}", "wb") as media:
        cont = await file.read()
        await media.write(cont)
    
    # usage: implemented in MyFile.save
    d_file = MyFile()
    await d_file.asave()

字符串
然后在模型中,我重构了保存()方法如下:

class MyFile(models):
    file = models.FileField(upload_to="files/")

    def save(self, *args, **kwargs):
        filename = self.generate_file()

        with open(filename, "rb") as f:
            self.file.save(filename, f, save=False)  # False to avoid recurssion error
        return super(File, self).save(*args, **kwargs)

    async def asave(
        self, force_insert=False, force_update=False, using=None, update_fields=None
    ):
        return await sync_to_async(self.save)(
            force_insert=force_insert,
            force_update=force_update,
            using=using,
            update_fields=update_fields,
        )

    @staticmethod
    def generate_file():
        import glob
        import os

        files = glob.glob("path/*")  # * means all, if specific format needed then *.csv
        latest = max(files, key=os.path.getctime)
        return latest

相关问题