2014-10-26 5 views
1

Я работаю с Django 1.7 и Python 3.4.Django download image from ImageField

У меня есть модель, как этот:

class ImageModel(models.Model): 
    image = models.ImageField(verbose_name='image', upload_to='uploaded_images/') 

Теперь я хочу, чтобы загрузить файл, который сохраняется в/статический/uploaded_images /. Например, у меня есть ссылка: www.example.com/image/download/1, где 1 - id объекта ImageModel.

Теперь у меня есть мнение:

def download_image(request, image_id): 
    img = ImageModel.objects.get(id=image_id) 
    (what I need to do?) 

Что дальше? Как создать представление, которое приведет к загрузке этого изображения?

ответ

3

Вы можете попробовать этот код, возможно, потребуется несколько предостережений:

from django.core.servers.basehttp import FileWrapper 
import mimetypes 

def download_image(request, image_id): 
    img = ImageModel.objects.get(id=image_id) 
    wrapper  = FileWrapper(open(img.file)) # img.file returns full path to the image 
    content_type = mimetypes.guess_type(filename)[0] # Use mimetypes to get file type 
    response  = HttpResponse(wrapper,content_type=content_type) 
    response['Content-Length']  = os.path.getsize(img.file)  
    response['Content-Disposition'] = "attachment; filename=%s" % img.name 
    return response 
  1. Я предполагаю, что есть поле .name в вашем ImageModel, чтобы получить имя файла во втором-to последняя строка ...filename=%s" % img.name Вы должны отредактировать код, соответствующий вашему проекту.

  2. Существует поле в ImageField что file, в коде здесь я использую img.file, чтобы получить путь к файлу, вы должны изменить что для img.YOUR_IMAGE_FIELD.file или все, что нужно, чтобы получить путь к изображение

+0

Обратите внимание, что это будет нормально работать, если имена находятся в пределах диапазона ASCII, но с ошибками с большими символами. Content-Disposition поддерживает кодированное имя UTF-8, но старые браузеры (pre IE8) полностью игнорируют это. Внутри он лучше работает с скрытым перенаправлением на URL с именем файла в URL-адресе. Все браузеры будут поддерживать это, и вы избежите неприятной ошибки '[1]', которую IE будет прикреплять к удаленным именам файлов. –

+0

@MikeMcMahon. Я не совсем уверен в том, что вы пытаетесь объяснить, но я был бы рад выучите любой другой способ сделать это, если это будет лучше. Не могли бы вы дать некоторую ссылку на информацию об этом? – AlvaroAV

+0

Рассмотрите имена файлов с символами кандзи или кириллицей. 'filename =% s' не будет работать. Он будет работать в FireFox/Chrome, но не <= IE8 и, возможно, мобильных браузерах (в зависимости от используемого мобильного устройства и технологии браузера). Существует формат 'filename * = UTF-8 ''% s', который поддерживает кодированные символы UTF-8, и это будет работать * иногда *. Лучше всего (изнутри DJango) выполнить HttpRedirect() до URL, содержащего полное имя файла, как часть пути. ВСЕ браузеры могут интерпретировать это и символы вне стандартного диапазона. –

0

Вы должны использовать Content-Disposition заголовок, посмотрите здесь:

Generating file to download with Django
Django Serving a Download File

+1

Хотя эта ссылка может ответить на вопрос, лучше включить здесь основные части ответа и предоставить ссылку для справки. Ответные ссылки могут стать недействительными, если связанная страница изменится. –

+0

Отмечено, извлеченный урок :) –

0

Остальные два ответа одобрены, но по многим причинам использование Django для обслуживания статического файла не рекомендуется по соображениям производительности. Лучше обслуживать его с помощью вашего веб-сервера (nginx/apache ...).

Вам не нужен дополнительный просмотр для статических файлов. Просто делают ссылку на файл в шаблоне:

<a href="{{object.image.url}} download">Download this image!</a> 

Где object является экземпляром ImageModel.

См django.db.models.fields.files.FieldFile.url

Если вы действительно хотите иметь представление в качестве URL, как www.example.com/image/download/1 вы можете просто написать мнение, что перенаправлять на URL изображения, полученного с поля.

+0

Это откроет изображение в веб-браузере, и я хочу добиться того, чтобы загрузить это изображение в папку загрузки пользователя;). –

+0

Я отредактировал ответ, чтобы добавить http://www.w3schools.com/tags/att_a_download.asp – dukebody

-1

Вот ваш кросс-браузер безопасным для загрузки файлов, содержащих любой тип символов

# Even better as it works in any browser (mobile and desktop) 
def safe_name(file_name): 
    """ 
    Generates a safe file name, even those containing characters like ? and & 
    And your Kanji and Cyrillics are supported! 
    """ 
    u_file_name = file_name.encode('utf-8') 
    s_file_name = re.sub('[\x00-\xFF]', lambda c: '%%%02x' % ord(c.group(0)), u_file_name) 
    return s_file_name 

# Handled by url(r'^/image/download/(\d+)/.+$ 
def safe_download_image(request, image_id): 
    """ 
    Safely downloads the file because the filename is part of the URL 
    """ 
    img = ImageModel.objects.get(id=image_id) 
    wrapper  = FileWrapper(open(img.file)) # img.file returns full path to the image 
    content_type = mimetypes.guess_type(filename)[0] # Use mimetypes to get file type 
    response  = HttpResponse(wrapper,content_type=content_type) 
    response['Content-Length']  = os.path.getsize(img.file)  
    # This works for most browsers, but IE will complain sometimes 
    response['Content-Disposition'] = "attachment;" 
    return response 

def download_image(request, image_id): 
    img = ImageModel.objects.get(id=image_id) 
    redirect_do = safe_name(img.name) 
    return HttpResponseRedirect('/image/download/' + img_id + '/' + redirect_to) 
+0

. Несчастливо он не работает. См. Мой ответ ниже. –

+0

Я вытащил это из своего исходного кода, который мы используем для нашей системы распространения файлов. Что не сработало? –

+0

@SzymonBarylak, что не сработало для вас? –

-1

Это не работает. Я сделал что-то вроде этого:

wrapper = FileWrapper(img.file) # img.file returns full path to the image 
content_type = mimetypes.guess_type(str(img.file))[0] # Use mimetypes to get file type 
response = HttpResponse(wrapper, content_type=content_type) 
response['Content-Length'] = os.path.getsize(str(img.file)) 
response['Content-Disposition'] = "attachment; filename=%s" % img.name 

где img пунктов к моим ImageField полю. Файл загружен, но я не могу его открыть.xUbuntu image viewer seys 'Не файл JPEG. начинается с 0x89 0x50'

+0

Первые два байта файла ANY JPEG должны быть «0xFF» и «0xE0» соответственно. Вы в какой-то момент не рассматриваете изображение как двоичное при загрузке или загрузке? любые действия, которые влияют на содержимое, должны открывать файл в режиме «rb» или «wb» соответственно. –

0

базирующийся класс просмотров типа exampe это было бы, как это (я использую питона-магию, чтобы получить правильный тип содержимого для файла):

import os 
import magic 

from django.views.generic import View 
from django.http import HttpResponse 

from .models import ImageModel 


class ImageDownloadView(View): 

    def get(self, request, *args, **kwargs): 
     image = ImageModel.objects.get(pk=self.kwargs['image_id']) 
     image_buffer = open(image.file.path, "rb").read() 
     content_type = magic.from_buffer(image_buffer, mime=True) 
     response = HttpResponse(image_buffer, content_type=content_type); 
     response['Content-Disposition'] = 'attachment; filename="%s"' % os.path.basename(image.file.path) 
     return response 

Это работает для Django 1.10.7, но не должно отличаться для Django 1.7.