Как программно загрузить локальный файл в виде Django поля модели? - PullRequest
1 голос
/ 07 января 2020

У меня возникают проблемы при попытке загрузить файлы на FileField по локальному пути.

Я правильно настроил серверную часть CDN в S3 корзине и использую ее как PrivateMediaStorage для одного из полей моей модели :

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

С этой очень простой конфигурацией, когда я создаю / обновляю модель с помощью django-admin, она сохраняется и файл, прикрепленный как some_file, корректно загружается в S3 корзину.

Тем не менее, если я пытаюсь создать / обновить экземпляр модели программно, скажем, с помощью специальной команды 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}, ...)

Что отсутствует в моей реализации и что необходимо настроить, чтобы разрешить загрузку файлов из локального хранилища?

Ответы [ 2 ]

1 голос
/ 07 января 2020

Вы передаете строку (результат os.path.join()) в ваше поле some_file, но вам нужно передать ей фактический File объект.

Самый простой способ сохранить файл в модели напрямую - использовать метод FieldFile 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 каждый раз, когда вы открываете файл, выполнение get_or_create() с экземпляром File в качестве аргумента, вероятно, будет каждый раз создавать новую строку. Лучше положить поля файла в 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
        )}
)
0 голосов
/ 07 января 2020

вы также можете сделать что-то вроде этого.

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