はじめに
「画像でゴミ分類!」アプリ作成日誌6日目の今日はディレクトリ構成を修正します。今日は忙しかったこともあり軽めです。
<記事一覧>
- 「画像でゴミ分類!」アプリ作成日誌day1~データセットの作成~
- 「画像でゴミ分類!」アプリ作成日誌day2~VGG16でFine-tuning~
- 「画像でゴミ分類!」アプリ作成日誌day3~Djangoでwebアプリ化~
- 「画像でゴミ分類!」アプリ作成日誌day4~Bootstrapでフロントエンドを整える~
- 「画像でゴミ分類!」アプリ作成日誌day5~Bootstrapでフロントエンドを整える2~
- 「画像でゴミ分類!」アプリ作成日誌day6~ディレクトリ構成の修正~ ←イマココ
- 「画像でゴミ分類!」アプリ作成日誌day7~サイドバーのスライドメニュー化~
- 「画像でゴミ分類!」アプリ作成日誌day8~herokuデプロイ~
前回までのあらすじ
前回までの記事では画像認識アプリを実装してDjangoに載せたうえで、Bootstrapを使ってフロントエンドを整えるところまでやりました。現時点での問題点の一つ目はindexとresultのtemplateファイルで重複した記述が存在していることであり、これはbaseファイルを作成して対応します。2つ目の問題は画像ファイルをHTMLから相対パスで参照してしまっているので、それをstaticフォルダから読めるようにしたいと思います。
base.htmlの作成
indexとresultで重複した記述をbaseに移行します。これは、今後デザインを変更した際にいちいち二つのファイルをいじるのが非効率だからです。
{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>画像でゴミ分類!</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.2/css/all.css" integrity="sha384-/rXc/GQVaYpyDdyxK+ecHPVYJSN9bmVFBvjA/9eOB+pb3F2w2N6fc5qB9Ew5yIns" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="{% static 'garbage/css/bootstrap.css' %}" />
<link rel="stylesheet" type="text/css" href="{% static 'garbage/css/style.css' %}" />
</head>
<body>
<div id="wrapper">
<button class="toggler d-md-none" type="button" id="toggler" data-toggle="collapse-side" data-target=".side-collapse">
<i class="fas fa-bars fa-2x"></i>
</button>
<img src="{% static 'garbage/media/images/title.png' %}" alt="画像でゴミ分類!" class="m-4 pb-3" id="title">
<div class="container row">
<div class="card col-md-4 py-4 px-0 d-none d-md-block h-100" id="sidebar">
<p role="button" class="mb-2 btn border-dark rounded-0 btn-secondary">外部リンク集</p>
<a href="https://manage.delight-system.com/threeR/web/bunbetsu?menu=bunbetsu&jichitaiId=kashiwashi&areaId=22125&areaName=%2F&lang=ja&benriCateId=7&bunbetsuCateId=7&faqCateId=%2F&howToCateId=&search=%E3%83%9A%E3%83%83%E3%83%88%E3%83%9C%E3%83%88%E3%83%AB&dummy=" class="btn btn-default border-dark mb-1 rounded-0" role="button" target="_blank" rel="noopener noreferrer">分別検索</a>
<a href="https://manage.delight-system.com/threeR/web/benri?menu=benri&jichitaiId=kashiwashi&areaId=22125&benriCateId=7&bunbetsuCateId=7&faqCateId=%2f&lang=ja" class="btn btn-default border-dark mb-1 rounded-0" role="button" target="_blank" rel="noopener noreferrer">ごみの分け方・出し方</a>
</div>
{% block main %}{% endblock main %}
</div>
{% block second %}{% endblock second %}
<footer>
<p id="copyright" class="mb-0">Copyright © 2020 eycjur All Rights Reserved.</p>
</footer>
</div>
</body>
</html>
冒頭の記述やサイドバーが共通しているもののため、baseにします。{% block main %}{% endblock main %}
のところに各ファイルごとの記述が入ります。
では、各ファイルが実際にどうなるかを見てみると、
{% extends "garbage/base.html" %}
{% load static %}
{% block main %}
<div class="col-md-8">
<div class="container card p-4 h-100">
<p>分類を調べたい画像を入力してください</p>
<form action="{% url "garbage:result" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<br>
<button type="submit" class="mt-3 wait-disappear">調べる!</button>
</form>
</div>
</div>
{% endblock main %}
{% block second %}
<h4>既存の画像を利用する</h4>
<div class="container row">
<div class="col-md-6 p-3">
<a href='{% url "garbage:result_num" num=1 %}'>
<img src="{% static 'garbage/media/images/temp1.jpg' %}" alt="画像1" class="sample-img">
</a>
</div>
<div class="col-md-6 p-3">
<a href='{% url "garbage:result_num" num=2 %}'>
<img src="{% static 'garbage/media/images/temp2.jpg' %}" alt="画像2" class="sample-img">
</a>
</div>
</div>
{% endblock second %}
最低限の部分だけを書くことで、このようにだいぶすっきりしたのが伝わるかと思います。
画像ファイルの配置の修正
完成イメージ
まず、どのようなディレクトリ構成にするかを決めておきます。
今回は以下のような構成にします。
garbage_proj
├garbage_proj
│ └settings.pyなど
├garbage
│ └views.pyなど
└static
└garbage
├css
│ └style.css
└media
└images
└image.pngなど
staticとmediaのパス
まず、staticとmediaのパスを設定しておきましょう。
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/garbage/media')
MEDIA_URL = '/media/'
いま、BASE_DIRは大元のgarbage_projフォルダなので、static,mediaフォルダをそれぞれ指定できていることがわかります。
こうすると、staticディレクトリを読み込むことで利用できるようになるので、templateファイルは<img src="{% static 'garbage/media/images/title.png' %}">
のように画像を指定できます。
これをもとに記述してきます。
{% extends "garbage/base.html" %}
{% load static %}
{% block main %}
<div class="col-md-8">
<div class="container card p-4 px-5">
<h2 class="m-3">分類結果</h2>
<img src="{% static 'garbage/media/images/image.png' %}" alt="画像" id="result-img">
<div class="container">
<table class="table">
<tr><th>分類</th><td>確率</td><td>収集曜日</td></tr>
{% for key, value, day in pred %}
<tr><th>{{ key }}</th><td>{{ value }}%</td><td>{{ day }}</td></tr>
{% endfor %}
</table>
<a href="{% url "garbage:index" %}">Topへ戻る</a>
</div>
</div>
</div>
{% endblock main %}
このように書くと相対パスで記述する必要がなくなるので、ルーティングを統一できます。
{% extends "garbage/base.html" %}
{% load static %}
{% block main %}
<div class="col-md-8">
<div class="container card p-4 h-100">
<p>分類を調べたい画像を入力してください</p>
<form action="{% url "garbage:result" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<br>
<button type="submit" class="mt-3 wait-disappear">調べる!</button>
</form>
</div>
</div>
{% endblock main %}
{% block second %}
<h4>既存の画像を利用する</h4>
<div class="container row">
<div class="col-md-6 p-3">
<a href='{% url "garbage:result_num" num=1 %}'>
<img src="{% static 'garbage/media/images/temp1.jpg' %}" alt="画像1" class="sample-img">
</a>
</div>
<div class="col-md-6 p-3">
<a href='{% url "garbage:result_num" num=2 %}'>
<img src="{% static 'garbage/media/images/temp2.jpg' %}" alt="画像2" class="sample-img">
</a>
</div>
</div>
{% endblock second %}
garbageアプリのresult_num
に対してパラメーターnum
を指定して渡しています。また、これを処理するurls.py
は以下のようになっています。
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from . import views
app_name="garbage"
urlpatterns = [
path("", views.index, name="index"),
path("result", views.result, name="result"),
path("result/<int:num>", views.result, name="result_num"),
]
result_num
に対してはパラメーターを渡しつつ、"result"という同じ関数を割り当てています。
def result(request, num=0):
if num:
img = "./static/garbage/media/images/" + ["temp1.jpg", "temp2.jpg"][num-1]
else:
form = UploadPictureForm(request.POST, request.FILES)
if form.is_valid():
img = form.cleaned_data["img"]
else:
params = {
"form":UploadPictureForm()
}
return render(request, "garbage/index.html", params)
pred = predict(img)
params = {
"img":img,
"pred":pred
}
return render(request, "garbage/result.html", params)
サンプルが選択されたときは既存の画像を利用するようにすることができました。
さいごに
以上のことで、だいぶファイル構造がわかりやすくなったかと思います。今後の開発がだいぶ楽になりそうです!
ちなみに、今回記事を書いていてコードブロックにdjangoという言語の指定ができることを初めて知りました。HTMLのシンタックスハイライトを引き継いだうえでdjango templateも見やすくなっているので非常に便利ですね。
<記事一覧>
- 「画像でゴミ分類!」アプリ作成日誌day1~データセットの作成~
- 「画像でゴミ分類!」アプリ作成日誌day2~VGG16でFine-tuning~
- 「画像でゴミ分類!」アプリ作成日誌day3~Djangoでwebアプリ化~
- 「画像でゴミ分類!」アプリ作成日誌day4~Bootstrapでフロントエンドを整える~
- 「画像でゴミ分類!」アプリ作成日誌day5~Bootstrapでフロントエンドを整える2~
- 「画像でゴミ分類!」アプリ作成日誌day6~ディレクトリ構成の修正~ ←イマココ
- 「画像でゴミ分類!」アプリ作成日誌day7~サイドバーのスライドメニュー化~
- 「画像でゴミ分類!」アプリ作成日誌day8~herokuデプロイ~