「画像でゴミ分類！」アプリ作成日誌day5～Bootstrapでフロントエンドを整える2～

# はじめに
「画像でゴミ分類！」アプリ作成日誌5日目の今日はBootstrapを使ってフロントエンドを整えていきたいと思います。

＜記事一覧＞

- [「画像でゴミ分類！」アプリ作成日誌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) ←イマココ
- [「画像でゴミ分類！」アプリ作成日誌day6～ディレクトリ構成の修正～](https://qiita.com/eycjur/items/f436787c2d517af6cad6)
- [「画像でゴミ分類！」アプリ作成日誌day7～サイドバーのスライドメニュー化～](https://qiita.com/eycjur/items/009dca5866c3e9ad0dd6)
- [「画像でゴミ分類！」アプリ作成日誌day8～herokuデプロイ～](https://qiita.com/eycjur/items/ebfae5db5dd1cd8349ea)

# 前回までのあらすじ
前回までの記事では画像認識アプリを実装してDjangoに載せたうえで、フロントエンドを整えるところまでやりました。今回の記事では機能を追加していき、それに合わせて`views.py`やtemplateファイルをいじっていこうと思います。

# 追加する機能
追加する機能は以下の通りです。

- サンプル画像による実行
- サイドメニューの実装
- フッターの実装

# サンプル画像による実行
まず、indexに画像をリンクとして表示できるようにします。

```django:garbage/templates/garbage/index.html
		<h4>既存の画像を利用する</h4>
		<div class="container row">
			<div class="col-md-6 p-3">
				<a href="{% url "garbage:sample1" %}">
					<img src="./media/images/temp1.jpg" alt="画像1" class="sample-img">
				</a>
			</div>
			<div class="col-md-6 p-3">
				<a href="{% url "garbage:sample2" %}">
					<img src="./media/images/temp2.jpg" alt="画像2" class="sample-img">
				</a>
			</div>
		</div>
```

ルーティングとしては

```py:garbage/urls.py
    path("sample1", views.sample1, name="sample1"),
    path("sample2", views.sample2, name="sample2"),
```
このようにそれぞれ別の関数に渡すようにしています。本来はパラメータとして`<a href="{% url "garbage:sample" num:1 %}">`として渡して`path("sample/<int:num>", views.sample, name="sample"),`と処理すべきだとは思いますが、遷移先のページ上の画像のパスを相対パスで指定しているのでリンクがおかしくなってしまう都合上こうしています。なので、画像の静的フォルダをloadする方法があれば改良したいとは思っています。

そして、viewファイルは以下のようにします。パラメーターで渡せるようになればresultに結合したいですが、とりあえず動くようにしたかったので不格好ですがここに指定する形をとっています。

```py:garbage/views.py
def sample1(request):
    img = "./media/images/temp1.jpg"
    pred = predict(img)

    params = {
        "img":img,
        "pred":pred
    }
    return render(request, "garbage/result.html", params)
```

# サイドメニューの実装
ここはHTMLとCSSで設定をしていきます。
まず、HTMLの書き方は以下です（リンクはリクエストパラメータを省いています）。

```django:garbage/templates/garbage/index.html
		<div class="container row">
			<div class="card col-md-4 py-4 px-0 d-none d-md-block">
				<p role="button" class="mb-2 btn border-dark rounded-0 btn-secondary">外部リンク集</p>
				<a href="https://manage.delight-system.com/threeR/web/bunbetsu" 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" class="btn btn-default border-dark mb-1 rounded-0" role="button" target="_blank" rel="noopener noreferrer">ごみの分け方・出し方</a>
			</div>
```
まず、サイドメニューの中に大きく分けて2種類のものを配置しようとしていて、リンクの分類については灰色背景で押せないようになっているボタン、リンクについては点線で枠線を引いたボタンにしています。
p要素については暗めのボタンにしていて、角を尖らせたり色を設定したりするのをBootstrapで指定しています。リンクについては別のタブで開くような設定を書いてあります。

これに対してCSSを以下のように設定します。

```css:garbage/static/garbage/css/style.css
a[role="button"]{
	width: 90%;
	border: dotted 1px;
}

p[role="button"]{
	width: 90%;
}

p[role="button"]:not(:disabled):not(.disabled) {
    cursor: default;
}
p[role="button"]:hover{
	background-color: #6c757d ;
}
```
width90%や枠線を点線にするのはBootstrapでは設定できないのでCSSで書きます。また、押せないボタンについては、ポインタになったり背景色が変わったりしたら紛らわしいので、Bootstrapで勝手に指定される疑似クラスを上書きするような設定を書いています。（なぜ、こんなことをしてまでBootstrapでボタンにするかというと、リンクのほうでボタンを使うのでそれに合わせて分類についてもボタンにしたほうが見栄えがそろうからです）

# フッターの実装
HTMLの書き方は以下です。

```django:garbage/templates/garbage/index.html
		<footer>
			<p id="copyright" class="mb-0">Copyright &copy; 2020 eycjur All Rights Reserved.</p>
		</footer>
```
これに対してCSSを以下のようにかけます

```css:garbage/static/garbage/css/style.css
#wrapper{
	min-height: 100vh;
	position: relative;
	padding-bottom: 40px;
}

footer{
	position: absolute;
	bottom: 0;
	width: 100%;
}
```

`min-height`を設定することで、footerが浮くことを防止しています。また、`padding-bottom`で全部スクロールした際にかぶることを防止しています。また、`position`を親要素を`relative`にしてfooterを`absolute`にすることで、固定位置で表示します。

以上の3機能を搭載した画面はこんな感じになっています。

![ps-3.png](https://raw.githubusercontent.com/eycjur/garbage/master/qiita_image/ps-3.png)
![ps-4.png](https://raw.githubusercontent.com/eycjur/garbage/master/qiita_image/ps-4.png)


# さいごに
今回は落穂拾い的な感じであまりまとまったことを書けなかったです。逆に個々の機能についてはそれぞれで詳しい記事を書けるような内容であり、需要もそちらのほうがあるとは思うのですが、開発日誌なので自分の作業ペースに合わせて記事を書きたいこともあり、どうすべきかはだいぶ悩んでいます。

次回はサイドバーのスマホ対応についてやろうと思っています！


＜記事一覧＞

- [「画像でゴミ分類！」アプリ作成日誌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) ←イマココ
- [「画像でゴミ分類！」アプリ作成日誌day6～ディレクトリ構成の修正～](https://qiita.com/eycjur/items/f436787c2d517af6cad6)
- [「画像でゴミ分類！」アプリ作成日誌day7～サイドバーのスライドメニュー化～](https://qiita.com/eycjur/items/009dca5866c3e9ad0dd6)
- [「画像でゴミ分類！」アプリ作成日誌day8～herokuデプロイ～](https://qiita.com/eycjur/items/ebfae5db5dd1cd8349ea)