Лучший способ написать изображение в Django HttpResponse()

Мне нужно безопасно обслуживать изображения только для проверенных пользователей (т. е. они не могут обслуживаться как статические файлы). В настоящее время у меня есть следующее представление Python в моем проекте Django, но оно кажется неэффективным. Любые идеи для лучшего способа?

def secureImage(request,imagePath):
    response = HttpResponse(mimetype="image/png")
    img = Image.open(imagePath)
    img.save(response,'png')
    return response

(Изображение импортировано из PIL.)


person k-g-f    schedule 09.06.2010    source источник
comment
Как прокомментировал Сантия: Если вы попробуете это с более поздней версией Django (как я сделал...), начиная с Django 1.7, ключевое слово mimetype было переименовано в content_type для HttpResponse()   -  person kenorb    schedule 29.05.2015
comment
как работает «red.save (ответ, png)», я проверяю, что исходный код «ответ» передается в «сохранить» как «fd», но ничего не работает? Может кто-нибудь сказать мне, пожалуйста? Благодарность   -  person Henning Lee    schedule 02.07.2019
comment
@HenningLee, ответ действует как дескриптор файла, и вы записываете файл в объект ответа. k-g-fis совершенно прав насчет того, что это ужасно неэффективно   -  person boatcoder    schedule 30.08.2019
comment
Используйте FileResponse для обслуживания файлов вместо HttpResponse.   -  person Boris    schedule 23.11.2020


Ответы (3)


Что ж, иногда требуется перекодирование (например, наложение водяного знака на изображение с сохранением оригинала нетронутым), но для самых простых случаев вы можете использовать:

try:
    with open(valid_image, "rb") as f:
        return HttpResponse(f.read(), content_type="image/jpeg")
except IOError:
    red = Image.new('RGBA', (1, 1), (255,0,0,0))
    response = HttpResponse(content_type="image/jpeg")
    red.save(response, "JPEG")
    return response
person StefanNch    schedule 05.04.2013
comment
Чтобы определить MIME-тип файла, вы можете использовать python-magic. - person Arjan; 29.04.2013
comment
mimetype устарело в Django 1.5, эта опция теперь называется content_type. - person bjacobel; 09.10.2014
comment
Кроме того, я думаю, что JPEG не поддерживает RGBA, вы можете отредактировать его на «RGB». - person sP_; 26.06.2018
comment
@sP_ прошло некоторое время с тех пор, как я коснулся python, но я почти уверен, что при вызове save любая прозрачность игнорируется (если вы сохраняете ее как .jpg). Были ли у вас ошибки при его использовании? Я намеренно использовал RGBA, потому что он был взят из скрипта, который наносил прозрачные водяные знаки на изображения. Если вы собираетесь использовать его в режиме RGB, вырежьте последний 0 также red = Image.new('RGB', (1, 1), (255,0,0)) - person StefanNch; 27.06.2018
comment
как работает «red.save (ответ, JPEG)», я проверяю, что исходный код «ответ» передается в «сохранить» как «fd», но ничего не работает? Может кто-нибудь сказать мне, пожалуйста? Благодарность - person Henning Lee; 02.07.2019
comment
Если вы хотите использовать RGBA, используйте image/png и PNG. - person Eli Front; 19.02.2021

Просто наткнулся на несколько плохой совет (для производства) и подумал, что упомяну X-Sendfile, который работает как с Apache, так и с Nginx и, возможно, с другими веб-серверами.

https://pythonhosted.org/xsendfile/

Современные веб-серверы, такие как Nginx, обычно могут обслуживать файлы быстрее, эффективнее и надежнее, чем любое веб-приложение, которое они размещают. Эти серверы также могут отправлять клиенту файл на диске, как указано веб-приложениями, которые они размещают. Эта функция широко известна как X-Sendfile.

Эта простая библиотека позволяет любому приложению WSGI использовать X-Sendfile, чтобы они могли контролировать, можно ли обслуживать файл или что еще делать, когда файл обслуживается, без написания специфичных для сервера расширений. Варианты использования включают в себя:

  • Ограничьте загрузку документов только пользователям, прошедшим проверку подлинности.

  • Запишите, кто скачал файл. Принудительно загружайте файл, а не отображайте его в браузере, или обслуживайте его с именем, отличным от имени на диске, установив заголовок Content-Disposition.

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

Вот репозиторий, который показывает, как это сделать для различных веб-серверов, и хотя он довольно старый, он, по крайней мере, даст вам представление о том, что вам нужно делать. https://github.com/johnsensible/django-sendfile

person boatcoder    schedule 30.08.2019

Используйте FileResponse
A более чистый способ, здесь нам не нужно беспокоиться о заголовках Content-Length и Content-Type, они автоматически устанавливаются, когда их можно угадать из содержимого open().

from django.http import FileResponse

def send_file(response):

    img = open('media/hello.jpg', 'rb')

    response = FileResponse(img)

    return response
person Sumithran    schedule 01.02.2021