Django: загрузка FileField и ImageField из файловой системы

Не знаю как вы, а я чаще стал сталкиваться с ситуацией, когда мне нужно программно загрузить файл из локальной файловой системы или с помощью удаленного URL в модель Django. Это может понадобиться в контексте работы в оболочке Python, исполнения отдельного скрипта или команды управления Django.

В типичном веб-приложении такая задача встречается нечасто. Я заметил, что мы это делаем, когда переносим сайт с какой-то другой технологии на Django, и привязываем изображение к некой контентной сущности.

Если вы поищете ответ как сделать это в Google, то обнаружите документацию Django File Uploads, File objects и Managing Files, которые сами по себе отличные. Тем не менее они не содержат последовательного руководства для решения нашей задачи.

Первый порыв — присвоить полю модели путь к файлу, но это ведет к потере информации об относительном пути к файлу, в которой нуждается Django.

Я выделил время, чтобы написать этот пост в основном для собственного блага, чтобы не искать заново решение в будущем. Но, надеюсь, вы также получите некоторую пользу.

Этапы загрузки локального файла в Django ImageField

Действия, которые необходимо выполнить:

  1. Получить файл (если он удаленный) и сохранить его локально
  2. Открыть файл как обычный объект файла Python
  3. Конвертировать открытый файл в Django FIle
  4. Привязать его к полю вашей модели

Пример модели

Предположим, у нас есть модель вроде этой:

from django.db import models

class Company(models.Model):
    name = models.CharField(max_length=100) 
    logo = models.ImageField()

Давайте создадим запись для RevSys, скачав логотип с помощью библиотеки requests:

import requests
from django.core.files import File

from .models import Company

r = requests.get(“http://media.revsys.com/img/revsys-logo.png”)

with open(“/tmp/revsys-logo.png”, “wb”) as f:
    f.write(r.content)

reopen = open(“/tmp/revsys-logo.png”, “rb”)
django_file = File(reopen)

revsys = Company()
revsys.name = “Revolution Systems”
revsys.logo.save(“revsys-logo.png”, django_file, save=True)

Последняя строка здесь самая важная. Методу save передается три аргумента:

  1. Относительный путь и имя файла внутри MEDIA_ROOT.
  2. Файл, открытый с помощью File объекта Django.
  3. Логическое значение, показывающее хотим ли мы сохранить экземпляр revsys модели Company после того, как изображение сохранено.

Иногда, если вы работаете с набором изображений, вам требуется распарсить URL или пути к файлам для извлечения имен файлов. Нижеследующий код послужит отправной точкой. Обратите внимание, что тут используется Python 3:

import os 
from urllib.parse import urlparse

# from urlparse import urlparse for Python 2.7

url = “http://media.revsys.com/img/revsys-logo.png” 
filename = os.path.basename(urlparse(url).path)

# This returns ‘revsys-logo.png’ from the URL

…

revsys.logo.save(filename, django_file, save=True)`

Надеюсь, это вам поможет!

Эта статья перевод. Оригинал: Loading Django FileField and ImageFields from the file system