Django2で画像を指定サイズで保存する　django-stdimage

# はじめに
Djangoの画像アップロードは、標準機能の`ImageField`を使うべしと、Django公式や先人のブログに書かれていた。
しかし、`models.py`に`ImageField`を用いて、画像アップロード、そして画面に表示することを試したところ、サイズがバラバラであることにショックを受けた。
画像サイズを均一にして、アップロードすれば問題ないと思うのだが、ひと手間かけることも馬鹿馬鹿しいと思った。

そこで保存時なのか表示時なのかでリサイズできないか調べていたところ、`django-stdimage`に出会った。
だが、日本語ドキュメントが見つからず、本家Githubページ( https://github.com/codingjoe/django-stdimage )を読んで、簡単にまとめることにした。

# 環境
Windows10
Python 3.6.0
Django 2.1.1

# Pillowのインストール
ImageField（stdimage）を扱う上で、Pillowをインストールする。
`>pip list Pillow`

# django-stdimageのインストール
django-stdimage(Django Standardized Image Field)をインストールする。
`>pip install django-stdimage`

# settings.pyの編集
INSTALLED_APPにdjango-stdimageを使用することを伝える。

```python:settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'news',
    'stdimage',  #追記
]
```
# models.pyの編集
Modelに属性を追記する。
画像のアップロード先 `upload_to` は環境に合わせて記載する。

```python:models.py
from django.db import models
from stdimage.models import StdImageField  #追記


class Post(models.Model):
    title = models.CharField(max_length=150)
    text = models.TextField(blank=True)

    # 以下を追記
    image = StdImageField(upload_to='path/to/img', blank=True, variations={
        'large': (600, 400),
        'thumbnail': (100, 100, True),
        'medium': (300, 200),
    })
```

# マイグレーションを実行
modelを編集したら、マイグレーションファイルを作成し、
`>python manage.py makemigrations news`
※「news」は各自のアプリ名に読み替える必要あり。

マイグレーションを行い、データベースに反映する。
`>python manage.py migrate`

# テンプレートの編集
ここでは、ニュース一覧の表示を例とした。
投稿日、タイトル、本文、そして画像を表示する。
`models.py`のPostクラスにおいて、`image`は`blank=True`のため、画像がない場合は非表示にする。

```python:index.html

{% extends 'news/base.html' %}

{% block content %}

    {% for post in posts %}

    <div>
        {{ post.created_datetime }}
    </div>
    <div>
        <h1><a href="{% url 'news:detail' pk=post.pk  %}">{{post.title}}</a></h1>
        <p>{{ post.text|truncatechars:100 }}</p>
        
        # 画像がある時のみ表示
        {% if  post.image %} 
            <p><a href="{{ post.image.url }}"><img alt="" src="{{ post.image.thumbnail.url }}"/></a></p>
        {% endif %}
    
    </div>

    {% endfor %}

{% endblock content %}
```
こんな感じになる。
「aaa」と「bbb」はサムネイルサイズの画像を表示。
「ccc」は画像なし。

<img width="182" alt="image01.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/299159/4005abfc-c2a9-65b0-bd8e-630993276f9f.png">

`models.py`のPostクラスにおいて、thumbnail、medium、largeの3サイズでデータベースに保存するようにした。
ニュース詳細ページで、各サイズの画像を表示してみる。
テンプレートは以下の通り。

```python:detail.html

{% extends 'news/base.html' %}

{% block content %}

<h1>{{ post.title }}</h1>
<p>{{ post.text|linebreaks }}</p>
{% if post.image %}
<p><a href="{{ post.image.url }}"><img alt="" src="{{ post.image.thumbnail.url }}"/></a></p>
<p><a href="{{ post.image.url }}"><img alt="" src="{{ post.image.medium.url }}"/></a></p>
<p><a href="{{ post.image.url }}"><img alt="" src="{{ post.image.large.url }}"/></a></p>
{% endif %}

{% endblock content %}
```
こんな感じになる。
thumbnail、medium、largeの3サイズが表示できている。
<img width="337" alt="image02.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/299159/3136ec6c-dc07-03dc-5a82-98978cab7a0b.png">

# おわりに

Djangoの画像サイズを指定して保存するやり方は複数あるようだ。
軽く調べたところ、ImageKitやsorl-thumbnail、stdimageなどがあった。
（はじめに、django-thumbsを使おうとしたが、python2のみの対応であることに途中で気づきました。。。）
色々な方法を試してみたい。