如何以编程方式将本地文件上传为 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()
我在尝试将文件从本地路径上传到 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()