如何以编程方式将本地文件上传为 Django 模型字段?

How to programmatically upload local file as Django model field?

我在尝试将文件从本地路径上传到 FileField 时遇到问题。

我已在 S3 存储桶中正确配置 CDN 后端并将其用作我的模型字段之一的 PrivateMediaStorage

class MyModel(models.Model):
    some_file = models.FileField(storage=PrivateMediaStorage())
    ...

只要我通过 creating/updating 模型通过 django-admin 使用这个非常简单的配置,它就会被保存,并且作为 some_file 附加的文件被正确上传到 S3 存储桶。

然而,如果我尝试以编程方式 create/update 模型实例,比如通过自定义 manage.py 命令,模型实例本身会创建,但附件永远不会上传到 CDN。这是我用来上传文件的代码的简化版本:

class Command(BaseCommand):
    help = 'Creates dummy instance for quicker configuration'

    def handle(self, *args, **options):
        some_file = os.path.join(os.path.dirname(__file__), '../../../temporary/some_image.png')

        if not os.path.exists(some_file):
            raise CommandError(f'File {some_file} does not exist')
        else: 
            instance, created = MyModel.objects.get_or_create(defaults={'some_file': some_file}, ...)

我的实现中缺少什么以及需要调整什么以允许从本地存储上传文件?

您正在将一个字符串(os.path.join() 的结果)传递给您的 some_file 字段,但您需要将它传递给一个实际的 File 对象。

直接在模型上保存文件的最简单方法是使用 FieldFile's save() 方法。

作为所提供案例的有效解决方案,创建记录的有效方法是:

instance = MyModel.objects.create(some_file=File(file=open(some_file, 'rb'), name='some_name.png'))

或者更好地使用pathlib动态获取名称:

from pathlib import Path

instance = MyModel.objects.create(some_file=File(file=open(some_file, 'rb'), name=Path(some_file).name))

请注意,基于文件获取行不太可能起作用,AFAIK 每次打开文件时,使用 File 实例作为参数执行 get_or_create() 可能会创建一个新行每一次。最好将文件字段放入 defaults:

instance, created = MyModel.objects.get_or_create(
    some_other_field=..., 
    defaults={'some_file': File(
        file=open(some_file, 'rb'), 
        name=pathlib.Path(some_file).name
        )}
)

你也可以这样做

      some_file = os.path.join(os.path.dirname(__file__), '../../../temporary/some_image.png')
instance.some_file.name = some_file
instance.save()