HTTP 504 при обработке загруженных zip изображений - PullRequest
4 голосов
/ 09 января 2012

Я новичок в веб-разработке и работаю над базовым приложением для создания галереи изображений (учебное упражнение) с использованием Django.Я настроил его так, чтобы я мог загрузить zip-архив с изображениями сразу, чтобы создать новый альбом.Кажется, все это работает нормально, но я получаю ошибку HTTP 504, когда загружаемый файл особенно велик.

Я получаю (пожалуйста, исправьте меня, если я ошибаюсь), эта ошибка означает, что мое приложение слишком медленно для возвратаHTTP-ответ.Я предполагаю, что это потому, что требуется много времени, чтобы распаковать и обработать (создать объект Pic в БД и создать миниатюры) всех изображений.

Есть ли способ вернуть ответ (скажем, некоторому промежуточномустраница), пока еще выполняем обработку в фоновом режиме - возможно, с использованием потоков?Как правильно справиться с этим?Не пора ли мне начать изучать Javascript / AJAX?

Спасибо!


Модели:

from django.db import models
from blog.models import Post

class Album(models.Model):
    title = models.CharField(max_length=128)
    slug = models.SlugField()
    description = models.TextField()
    parent = models.ForeignKey('self', null=True, blank=True)

    pub = models.BooleanField()
    date_created = models.DateTimeField(auto_now_add=True)
    date_published = models.DateTimeField(null=True, blank=True)
    date_modified = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return self.title

class Pic(models.Model):
    image = models.ImageField(upload_to='pics/%Y/%m') 
    title = models.CharField(max_length=128)
    caption = models.TextField(blank=True, null=True)
    albums = models.ManyToManyField('Album', null=True, blank=True)
    posts = models.ManyToManyField(Post, blank=True, null=True)

    date_taken = models.DateTimeField(null=True, blank=True) 
    date_uploaded = models.DateTimeField(auto_now_add=True) 
    date_modified = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return self.title

Просмотр:

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

def new_album(request):
    if request.method == "POST":
        form = AlbumForm(request.POST, request.FILES)
        if form.is_valid():
            from gallery.pic_handlers import handle_uploaded_album
            pics = handle_uploaded_album(request.FILES['pic_archive'])
            a = form.save()
            a.slug = slugify(a.title)
            a.save()
            for pic in pics:
                pic.albums.add(a)
            return HttpResponseRedirect('/gallery/album/%s/' % a.slug)
    else:
        form = AlbumForm()

    return render_to_response('new_album.html', {
        'form' : form,
    }, context_instance = RequestContext(request))

Дополнительная обработка:

def handle_uploaded_album(pic_archive):
    destination = open(join(settings.MEDIA_ROOT,pic_archive.name), 'wb+')
    for chunk in pic_archive.chunks():
        destination.write(chunk)
    destination.close()

    today = datetime.date.today()
    save_path = 'pics/{0}/{1:02}/'.format(today.year, today.month)
    tmp_path = 'tmp/'
    z = zipfile.ZipFile(join(settings.MEDIA_ROOT,pic_archive.name), 'r')
    pics = []
    for member in z.namelist():
        if '/' in member or '\\' in member: 
            # don't deal with any directories inside the zip
            # this also solves the '__MACOSX' issue
            continue
        if splitext(member)[1] in IMG_EXT:
            z.extract(member,join(settings.MEDIA_ROOT,tmp_path))
            im = File(open(join(settings.MEDIA_ROOT,tmp_path,member), 'rb'))
            # create a Pic from this file
            pic = Pic()
            pic.title = member
            pic.image.save(
                join(save_path, member),
                im,
                True)
            create_thumbnails(pic)
            im.close()
            # remove extracted images
            remove(join(settings.MEDIA_ROOT,tmp_path,member))

            # TODO: save date taken if available
            pics.append(pic)

    z.close()
    remove(join(settings.MEDIA_ROOT,pic_archive.name))

    return pics

def create_thumbnails(pic):
    fname, ext = splitext(pic.image.path)
    img = Image.open(pic.image.path)

    img.thumbnail((512,512), Image.ANTIALIAS)
    img.save(fname + '_m' + ext)

    img.thumbnail((128,128), Image.ANTIALIAS)
    img.save(fname + '_s' + ext)

Ответы [ 2 ]

5 голосов
/ 09 января 2012

Длинные задачи, такие как эта обработка, занимают слишком много времени, и время ожидания вашего клиента и / или вашего прокси-сервера - это ошибка 504 , которую вы видите.

Вы не должны выполнять длинные задания таким образом!

Как вы правильно спросите в конце, вам нужен способ отсоединения длинных исполнений - через асинхронную систему очередей , например celery . Таким образом, вы можете сразу же вернуть ответ своим клиентам, в то время как серверная часть выполняет задания асинхронно.

Вы должны взглянуть на одно из следующих действий:

Поскольку django-celery , безусловно, лучший вариант, следующий шаг - узнать об этом; вокруг него также много ТАК вопросов

Если вы хотите быть уверены, что происходит сбой при обработке, а не при загрузке, просто попробуйте отключить всю обработку и сразу вернуться к своему клиенту. Если он все еще не работает, вам также нужно настроить свой веб-сервер, чтобы он не работал по таймауту!

1 голос
/ 09 января 2012

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

Итак, вы получаете ошибку 5xx, которая генерируется сервером, ошибка 504 указывает

504 Gateway Timeout
    The server was acting as a gateway or proxy and did not receive a timely response from the upstream server.

Ну, я никогда не программирую на Django, но что я могу понять из приведенных вами подробностей, так это то, что причиной этой ошибки, несомненно, является большой файл. Что может случиться, так это то, что когда вы загружаете большой файл, устанавливается тайм-аут, но поскольку файл большой, время, которое требуется для загрузки файла, превышает тайм-аут, и, следовательно, генерируется ошибка. .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...