LoginSignup
43
35

More than 3 years have passed since last update.

Djangoを使って画像アップロード、閲覧を実装してみる

Posted at

こんにちは!やっしーです

今回はDjangoを使って画像アップロード機能を実装しようとした時のつまづいた点含め手順を載せていこうと思います。

Goal 画像アップロードの実装

本のレビューサイトを作成するにあたり、本のタイトル、内容等に加え、その本の表紙が写った画像があるとわかりやすいと感じ、実装項目に追加した。

データベースのカラムに画像パスを保存。変数の設定を通じて保存先フォルダから引っ張ってこれる仕組みがDjangoにあります。ImageFieldというカラムです

環境

OS:Mac OS Mojave 10.14.6
* python 3.7
* Django 2.2
* Pillow 6.1.0

手順

1. 画像保存用のフォルダを作成する

django-admin startproject プロジェクト名にて作成されたプロジェクトフォルダ(以下PROJECT)直下(各種appと同階層)に、Imagesというフォルダ(名前は任意)を作成する。

2. PROJECTのsettings.pyで、画像保存パスを指定、urls.pyに画像に対するパスを追加

settings.py
IMAGE_ROOT = os.path.join(BASE_DIR, 'images')
IMAGE_URL = '/images/'
PROJECT/urls.py
if settings.DEBUG:
    urlpatterns += static(settings.IMAGE_URL, document_root=settings.IMAGE_ROOT)

これでユーザーが画像を参照できるようになる

3. アップロードフォームの作成(+カラムの作成)

model定義

models.py
class Book(models.Model):
    author = models.CharField(max_length=20)
    image = models.ImageField(upload_to='images',blank=True, null=True)
    title = models.CharField(max_length=32)
    link = models.CharField(max_length=200)
    published_date = models.DateTimeField(blank=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

三行目の

image = models.ImageField(upload_to='images',blank=True, null=True)

が画像のパスを保存するカラムっぽいupload_toはアップロード先を示す。

フォームの作成

forms.py一部
class BookForm(forms.ModelForm):

    class Meta:
        model = Book
        fields = ('title', 'link','image')

ModelFormを使用していますが、必ずこうでなくてはいけない項目ではありません。

<form method="POST" class="post-form" enctype="multipart/form-data">{% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="save btn btn-default">Save</button>
</form>

アップロード処理のviews.py
Postリクエストでない時は投稿用画面をリターンする。登録時は登録処理が走る

views.py一部
def newBook(request):
    if request.method == "POST":
        form = BookForm(request.POST)
        if form.is_valid():
            book = Book()
            print(request)
            book.title = request.POST['title']
            book.link = request.POST['link']
            book.image = request.FILES['image']
            book.author = request.user
            book.published_date = timezone.now()
            book.save()
            return redirect('book_detail', pk=book.pk)
    else:
        form = BookForm()
    return render(request, 'blog/new.html', {'form': form})

ミソは

book.image = request.FILES['image']

ここ。画像はファイルデータなのでこうしないと取れないらしい

これで登録はできます。ただ、templateのenctype="multipart/form-data"をつけないと画像が上手く保存されない(エラーもでない)ので要注意。ただし、adminではできます。なんででしょうね。

表示はこうする

{% for book in books %}
        <div class="post">
        {% if book.image %}
        <div class ="image">
            <img src="/{{ book.image.url }}" style="width:300px;height:auto">
        </div>
        {% endif %}
            <div class="date">
                {{ book.published_date }}
            </div>
            <h1><a href="{% url 'book_detail' pk=book.pk %}">{{ book.title }}</a></h1>
            <p>{{ book.link|linebreaksbr }}</p>
        </div>
{% endfor %}

コードはgithubに上がっています。わからないことあったら、お気軽にTwitter(id:Yasshieeee)までお願いします!

43
35
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
35