Skip to content

Instantly share code, notes, and snippets.

@voluntas
Last active May 13, 2022 13:46
Show Gist options
  • Save voluntas/7002085 to your computer and use it in GitHub Desktop.
Save voluntas/7002085 to your computer and use it in GitHub Desktop.
S3 と非同期サムネイル作成 コトハジメ

S3 と非同期サムネイル作成 コトハジメ

更新:2013-11-04
バージョン:0.0.4
作者:@voluntas
URL:http://voluntas.github.io/

概要

  • 画像のアップロード先を S3 にして欲しい
  • アップロードと同時にサムネイルを生成して欲しい
  • サムネイル生成は非同期であって欲しい

この 3 つの願いはよくある話なのではないでしょうか。

この辺の処理がまとまってるのが見つけられなかったのでまとめてみました。

ゴール

  • S3 アップロードには django-storages を使う
  • サムネイル生成には django-imagekit を使う
  • 非同期処理には django-celery を使う
  • Celery のキューには Redis を使う

これらの 3 つを組み合わせることで画像を S3 にアップロードし、 非同期にサムネイルを生成するという処理を実現させます。

セットアップ

必須:

$ pip install django django-celery django-imagekit django-storages boto redis Pillow celery

pip freeze:

Django==1.5.5
Pillow==2.2.1
amqp==1.0.13
anyjson==0.3.3
billiard==2.7.3.34
boto==2.15.0
celery==3.0.24
django-appconf==0.6
django-celery==3.0.23
django-imagekit==3.0.4
django-storages==1.1.8
kombu==2.5.16
pilkit==1.1.5
python-dateutil==2.2
pytz==2013.7
redis==2.8.0
six==1.4.1
wsgiref==0.1.2

おまけ:

$ pip install flower

Pillow はイメージ変換ライブラリだが、libjpeg 等が必要なのでなんとか動くようにすること

Pillow インストール例:

--------------------------------------------------------------------
PIL SETUP SUMMARY
--------------------------------------------------------------------
version      Pillow 2.2.1
platform     darwin 2.7.5 (default, Aug  1 2013, 01:01:17)
             [GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))]
--------------------------------------------------------------------
--- TKINTER support available
--- JPEG support available
--- ZLIB (PNG/ZIP) support available
*** TIFF G3/G4 (experimental) support not available
--- FREETYPE2 support available
*** LITTLECMS support not available
*** WEBP support not available
*** WEBPMUX support not available
--------------------------------------------------------------------

macports:

$ sudo port install libjpeg-turbo

yum:

$ sudo ...

aptitude:

$ sudo ...

django-storages

まずは django-storages を使って ImageField や FileField を使ったデータを S3 に上がるようにします。

settings.py に以下の設定はが必要になります。

# ストレージを boto を使った S3 に指定します
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'

# https を有効にします
AWS_S3_SECURE_URLS = True

# 認証クエリーを無効にします
AWS_QUERYSTRING_AUTH = False

# アクセスキーを指定します
AWS_ACCESS_KEY_ID = ''

# シークレットキーを指定します
AWS_SECRET_ACCESS_KEY = ''

# バケット名を指定します
AWS_STORAGE_BUCKET_NAME = ''

この設定をすることで後は普通にアップロードすることで S3 にファイルが置かれるようになります。

media と static

メディアファイルは /media/ で、static ファイルは /static/ から始まるようにしたい場合は以下のようにします。

django-imagekit

サンプルプロジェクト

  • ジェネリックビューは使ってない
  • HTML は凄く適当

ソースコード

project/core/views.py

# coding=utf8

from django.shortcuts import render, redirect
from django.views.decorators.http import require_GET, require_http_methods

from .models import Entry
from .forms import EntryForm


@require_GET
def home(request):
    entries = Entry.objects.all()
    return render(request, 'core.html', {'entries': entries})


@require_http_methods(["GET", "POST"])
def upload(request):
    if request.method == 'POST':
        form = EntryForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('/')
    else:
        form = EntryForm()
    return render(request, 'core.html', {'form': form})

project/core/models.py

# coding=utf8

from django.db import models

from imagekit import ImageSpec, register
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill


class Entry(models.Model):
    title = models.CharField(max_length=255)
    img = models.ImageField(upload_to='entry/%Y%m%d')
    img_thumbnail = ImageSpecField(source='img',
                                   id='core:profile:image_thumbnail')

    class Meta:
        ordering = ('title', )

    def __unicode__(self):
        return self.title


class ImageThumbnail(ImageSpec):
    processors = [ResizeToFill(100, 50)]
    format = 'JPEG'
    options = {'quality': 60}

register.generator('core:profile:image_thumbnail', ImageThumbnail)

project/core/forms.py

# coding=utf8

from django import forms

from .models import Entry

class EntryForm(forms.ModelForm):
    class Meta:
        model = Entry

project/core/templates/core/home.html

{% for entry in entries %}
    <div><img src="{{ entry.img_thumbnail.url }}"><br></div>
{% endfor %}

project/core/templates/core/upload.html

<form action="/upload" method="post" enctype="multipart/form-data">{% csrf_token %}
    {% for field in form %}
        <div >
            {{ field.errors }}
            {{ field.label_tag }}: {{ field }}
        </div>
    {% endfor %}
    <p><input type="submit" value="アップロード" /></p>
</form>

project/core/settings.py

INSTALLED_APPS = (
    ...

    'djcelery',
    'imagekit',
    'storages',

    'core',
)

DEFAULT_FILE_STORAGE = 'core.s3.MediaRootS3BotoStorage'
STATICFILES_STORAGE = 'core.s3.StaticRootS3BotoStorage'

AWS_S3_SECURE_URLS = True
AWS_QUERYSTRING_AUTH = False

AWS_ACCESS_KEY_ID = ''
AWS_SECRET_ACCESS_KEY = ''
AWS_STORAGE_BUCKET_NAME = ''

IMAGEKIT_DEFAULT_FILE_STORAGE = DEFAULT_FILE_STORAGE
IMAGEKIT_DEFAULT_CACHEFILE_BACKEND = 'imagekit.cachefiles.backends.Async'
IMAGEKIT_DEFAULT_CACHEFILE_STRATEGY = 'imagekit.cachefiles.strategies.Optimistic'

import djcelery
djcelery.setup_loader()

BROKER_URL = 'redis://localhost:6379/0'

project/core/s3.py

# coding=utf8

from storages.backends.s3boto import S3BotoStorage

StaticRootS3BotoStorage = lambda: S3BotoStorage(location='static')
MediaRootS3BotoStorage  = lambda: S3BotoStorage(location='media')

project/core/urls.py

# coding=utf8

from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^$', 'core.views.home', name='home'),
    url(r'^upload$', 'core.views.upload', name='upload'),
)

起動

アプリを起動する:

$ python manage.py runserver

redis サーバを立てる:

$ redis-server

celery ワーカを起動する:

$ python manage.py celery worker -E

flower をインストールしている場合:

$ python manage.py celery flower
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment