公式ドキュメントをちゃんと読まない私がDjangoの静的ファイルについて理解するまで

アドベントカレンダー11日目の記事です。

# はじめに
週末・深夜Pythonistaです。仕事でデータまとめるときにpandas,numpy,scipyあたりをちょこちょこする程度の人です。
趣味でDjangoを使うにあたって静的ファイルでよく躓いたので、『わからないところがわからない人』向けに、その躓きポイントと解決法をまとめられたらなと思います。
間違っている点があればご指摘いただけるとありがたいです。


~~ぶっちゃけると[公式ドキュメント](https://docs.djangoproject.com/ja/3.0/)がとてつもなく親切なので、
しっかり読んで、理解して、その通り手を動かせば必ず理解しているはずの内容なのです。~~


## Q1:そもそも静的ファイルis何？

静的ファイル？:thinking:
動かないファイルって何だよ・・・？

## A1: **Webの仕組みを知りましょう。**

~~公式ドキュメント読みましょう~~
ものすごく乱暴に言うとCSS,JS等です。
Djangoが生成する動的なコンテンツに対して、サーバーから何も加工を加えずクライアント側に提供するファイルのことを指します。

Webサーバの仕組み：[MDNリファレンス](https://developer.mozilla.org/ja/docs/Learn/Common_questions/What_is_a_web_server)

静的ファイルという言い方自体はDjango独自の言い回し（？）のようですが、ウェブアプリケーションの仕組みがわかっていれば難なく理解できるものだと思います。

これがわからないあなた（過去の自分）はWebの仕組みを勉強しましょう。


>静的ファイル (画像、JavaScript、CSS など) を管理する¶
ウェブサイトではふつう、画像や JavaScript、CSS などの追加のファイルを配信する必要があります。Django では、こうしたファイルのことを「静的ファイル (static files)」と呼んでいます。静的ファイルの管理を簡単にするために、Django は django.contrib.staticfiles を提供しています。
>(Django公式ドキュメント)

ちゃんと公式ドキュメントに書いてありますね。。。

## Q2:結局静的ファイルはどこに置くのが正解？

Django公式ドキュメント付属のチュートリアル・DjangoGirlsTutorial(有名なDjangoのチュートリアル）では、staticディレクトリをアプリ内に掘るように紹介されています。

>polls ディレクトリの中に、 static ディレクトリを作成します。Django はそこから静的ファイルを探します。

>(Django公式ドキュメント)

上記のpollsはアプリ名なので、アプリ内にディレクトリを作成するように指示しています。


>静的ファイルはプロジェクトのどこに置けばいいの？
Djangoは、ビルトインの "admin" アプリにより、静的ファイルをどこで探せばいいのかわかっています。私たちがやることは、blog アプリのための静的ファイルを追加することだけです。

>そのために、blogアプリの中に static というフォルダを作ります

>djangogirls
├── blog
│   ├── migrations
│   ├── static
│   └── templates
└── mysite
>(DjangoGirlsTutorial)

こちらも同様にアプリ内にディレクトリを作成しています。

一方で、ベストプラクティスではプロジェクト直下にstaticフォルダを置くことを推奨しています。

## A2: どっちでもいい

アプリ内にstaticディレクトリを作成する場合も、以下のような構成にして名前空間を利用することがほとんどだからです。（※名前空間を使わない場合のまずい場合を番外編でご紹介します）
強いて言えば、散らばっていると個人的に見にくいので、ベストプラクティスを踏襲することをお勧めします。
併用は避けましょう。

```
(アプリ名) 
　┣static
     └ (アプリ名)
           ┣css
           ┣js
```

## Q3:本番環境css当たらない問題

Djangoアプリをデプロイしようとする者の心を折るものそれが静的ファイルだと信じています。。。

## A3:Webサーバーの設定の見直しをしましょう

本番環境で静的ファイルの提供を行うのはWebサーバー側が担うことが多いと思います。
静的ファイルが一か所にまとめられているか？正しく配信の設定がなされているかを確認しましょう。

Django側で気を付けるべきは1か所に静的ファイルをまとめられているかどうかに尽きます。
静的ファイルを１か所にまとめるコマンドは`python manage.py collectstatic`です。

このコマンドを叩くと開発環境下でdjango.contrib.staticfilesから見えている静的ファイルをsettings.pyで設定した`STATIC_ROOT`に集められます。








しかもすでに同名のファイルがある場合はタイムスタンプを確認して新しいものを保存してくれるスグレモノ！
これを行うことで、Nginxなどの設定が楽になります。


このcollectstaticコマンド周りの公式ドキュメントは日本語化が進んでおらず英語のままなのも、公式ドキュメント斜め読み勢を陥れる一端となっているのかもしれません。。。

## 番外編:静的ファイルの衝突

アプリ内にstaticディレクトリを作成する場合、静的ファイルの名前の衝突に注意が必要です。
Djangoでは名前が同じ静的ファイルが存在する場合、最初に検索に引っかかった方のファイルのみ提供されます。

以下のように同じ名前の静的ファイルが存在する場合、Django側ではどちらの静的ファイルを提供すべきかがわかりません。
この場合saticfilesが見つけた**最初**のcssを当てることになります。

```project_root/app1/static/main.css
h1{
  color: blue;
}
```

```project_root/app2/static/main.css
h1{
  color: red;
}
```

なので、それぞれのテンプレートで以下のように`main.css`を呼ぼうとしても...

```project_root/app1/templates/app1.html
{% load static %}
<link rel="stylesheet" href="{% static "main.css" %}">
{% static "main.css" %}　 <!-- デバッグ用 -->
<h1>App1.html<h1>
```
```project_root/app2/templates/app2.html
{% load static %}
<link rel="stylesheet" href="{% static "main.css" %}">
{% static "main.css" %}　　<!-- デバッグ用 -->
<h1>App2.html<h1>
```
このように片方のCSSしか当たりません。
App1はテキスト青色、App2はテキスト赤色にしたかったのに両方青色になってしまいます
![app1_app2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251535/13ad9720-7b8a-44a0-3cbf-73e064858f92.png)

こんな時はfindstaticコマンドを叩きましょう。
このコマンドを使うことで、Djangoの検索順がわかります。

``` shell
$ python manage.py findstatic main.css
Found 'main.css' here:
  C:\Users\Cuz\Desktop\Projects\static_files_sample\app1\static\main.css
  C:\Users\Cuz\Desktop\Projects\static_files_sample\app2\static\main.css
```

この時上のapp1のcssが当たり、app2のcssが当たっていないことがわかると思います。


これもまた[公式ドキュメント](https://docs.djangoproject.com/en/2.2/ref/contrib/staticfiles/)に書いてあります


## まとめ

公式ドキュメント読みましょう！読もう！いや読むんだ！
これに尽きますね。。。
改めて読むととても細かいところまで書いているので、きちんと隅から隅まで丁寧に読むことをお勧めします。

（メディアファイル関連やデプロイまでは時間が足りませんでした。。。来年こそ計画的に書くぞっ！）

明日は@skd_nwさんの『開発で使ったライブラリの話とか』です！
よろしくお願いいたします！