1. eycjur

    Posted

    eycjur
Changes in title
+「画像でゴミ分類!」アプリ作成日誌day6~ディレクトリ構成の修正~
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,237 @@
+# はじめに
+「画像でゴミ分類!」アプリ作成日誌6日目の今日はディレクトリ構成を修正します。今日は忙しかったこともあり軽めです。
+
+<記事一覧>
+
+- [「画像でゴミ分類!」アプリ作成日誌day1~データセットの作成~](https://qiita.com/eycjur/items/7d8223b28758c7dfaaa0)
+- [「画像でゴミ分類!」アプリ作成日誌day2~VGG16でFine-tuning~](https://qiita.com/eycjur/items/3e954cb70dc15f996c2d)
+- [「画像でゴミ分類!」アプリ作成日誌day3~Djangoでwebアプリ化~](https://qiita.com/eycjur/items/9c618538177c82f7fdc3)
+- [「画像でゴミ分類!」アプリ作成日誌day4~Bootstrapでフロントエンドを整える~](https://qiita.com/eycjur/items/7b58c28eb8b16e722b5d)
+- [「画像でゴミ分類!」アプリ作成日誌day5~Bootstrapでフロントエンドを整える2~](https://qiita.com/eycjur/items/08808097acd625e00652)
+
+# 前回までのあらすじ
+前回までの記事では画像認識アプリを実装してDjangoに載せたうえで、Bootstrapを使ってフロントエンドを整えるところまでやりました。現時点での問題点の一つ目はindexとresultのtemplateファイルで重複した記述が存在していることであり、これはbaseファイルを作成して対応します。2つ目の問題は画像ファイルをHTMLから相対パスで参照してしまっているので、それをstaticフォルダから読めるようにしたいと思います。
+
+# base.htmlの作成
+indexとresultで重複した記述をbaseに移行します。これは、今後デザインを変更した際にいちいち二つのファイルをいじるのが非効率だからです。
+
+```django:garbage/templates/garbage/base.html
+{% 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 &copy; 2020 eycjur All Rights Reserved.</p>
+ </footer>
+ </div>
+</body>
+</html>
+```
+冒頭の記述やサイドバーが共通しているもののため、baseにします。`{% block main %}{% endblock main %}`のところに各ファイルごとの記述が入ります。
+
+では、各ファイルが実際にどうなるかを見てみると、
+
+```django:garbage/templates/garbage/index.html
+{% 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のパスを設定しておきましょう。
+
+```py:garbage_proj/setting.py
+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' %}">`のように画像を指定できます。
+
+これをもとに記述してきます。
+
+```django:garbage/templates/garbage/result.html
+{% 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 %}
+```
+このように書くと相対パスで記述する必要がなくなるので、ルーティングを統一できます。
+
+```django:garbage/templates/garbage/index.html
+{% 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`は以下のようになっています。
+
+```python:garbage/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"という同じ関数を割り当てています。
+
+```py:garbage/views.py(一部略)
+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も見やすくなっているので非常に便利ですね。
+
+
+