Lolipop!マネージドクラウドにDjangoをデプロイしようとしたときに、静的ファイルの配置で躓いた件

# 概要

Django製のアプリケーションを[Lolipop!マネージドクラウド](https://mc.lolipop.jp/)(以下マネクラ) へデプロイする過程でいくつか詰まった部分があったのでメモ。

Djangoの静的ファイルの配信周りは、

- デプロイの情報がHerokuに偏っている
- NGINX,Apache,uWSGI (Webサーバー側)での配信に任せることが多い
- 現行の4系に対して検索する言語(jp,en)問わず1~2系の情報が引っかかりがち
- そもそも情報が少ない

みたいな辛さを内包しがちで、情報の検索が難しかったです。

当のマネクラのサポートにも連絡したところ解決しなかったので仕方なく試行錯誤しました。

# Djangoの仕様いろいろ

DjangoはMVCアーキテクチャを採用したアプリケーションです。


[Djangoのチュートリアル](https://docs.djangoproject.com/ja/4.0/)はMVCフレームワークとしての基礎から、
Model作成の段階でテスト駆動開発についても触れていて、かなりしっかりしているなという印象を受けます。

Viewを含む静的ファイルの取り扱いもテスト環境用のチュートリアルに沿ってプロジェクトを作成すると問題なく動かせると思います。


# 上手く行った方法

早速ですが上手く行った方法を書いておきます。


```python:manage.py

ALLOWED_HOSTS = ['*']

# production
STATIC_ROOT = "/var/app/current/static"

STATIC_URL = 'static/'

```

stackoverflowの自動翻訳(転載)のような謎サイトで答えを見つけてしまった...
https://code-examples.net/ja/q/16267f5


どうやら`STATIC_ROOT`にstaticディレクトリの実パスを入力しておくとDjango側がviewを作成する際に静的なファイルを認識してくれる模様。
WebサーバにApacheを使ってる場合は`/var/www/static`のような感じで指定してあげるといいらしく応用が効く方法ですね。

参考 -> [DjangoNote 5 Apache で静的ファイルを開く | みろりHP](https://www.mrrhp.com/ja/djangonote-5-staticfiles)


デバッグモードをTureにした状態ではローカルで`runserver`を利用して開発していたときと同じ様なパスの読み込みが可能だったので油断していましたが、本番環境においてはセキュリティの観点から静的なファイルの配信を工夫する必要があるみたいです。




# lolipop側の準備


Lolipop! マネージドクラウド(以下MC)ではコンテナ型のサービスではあるものの、よくあるレンタルサーバーでプランを選ぶような感じで、どのフレームワークを使うか環境設定を自動的に行う事ができます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609338/3b0b533b-3076-0acf-504b-e5d5c42af0ac.png)
登録 -> プロジェクト 新規追加 -> フレームワークを選ぶ -> ドメインを決める ->DBパスを決める
で10日間も無料で試せます。



基本的に言語を問わず利用できるDBはMySQLになるのでPythonを使い慣れているとSQLiteを使いたいと思ってしまうかもしれないですね。


公式からもマネクラへのflaskやDjangoのデプロイ方法はサポートされています。



👉[[Python] Django を使用したWebアプリの作成 – ヘルプ - ロリポップ！マネージドクラウド](https://support.mc.lolipop.jp/hc/ja/articles/360011824713--Python-Django-%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9FWeb%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E4%BD%9C%E6%88%90)

<details><summary>「4. 最初のソースコードを作成」の項目にタイポがあるので後で修正を依頼しておく </summary>

```python
# 誤
pipenv install gunicorn django# 依存関係 を requirements.txt に記録するpipenv lock -r > requirements.txt

# 正
pipenv install gunicorn django# 依存関係 を requirements.txt に記録する
pipenv lock -r > requirements.txt
```

単に改行漏れだけど。
</details>


# 試したこと


## collectstaticを使う


マネクラの内部もHerokuなどと同じく今風にコンテナ駆動で運用されていて、
デプロイ後にリポジトリが各ノード内でクローンされるみたいです。

ディレクトリの構造は例えば、

```bash
$ls
0000000000000000  1640876919xxxxxx  current  projrepo  shared  user_command.sh	user_command.sh.sample
```

のようになっています。
それぞれのディレクトリの内部構造は以下の通り。

```bash
$ls current
Pipfile  Pipfile.lock  app  manage.py  requirements.txt
$ls 1640876919xxxxxx
Pipfile  Pipfile.lock  app  manage.py  requirements.txt

```
currentのアプリケーションが通常稼働するもので、タイムスタンプのディレクトリはそのクローンになっている模様です。(どちらが親かわからないけど...)


これがなかなか曲者で、`current` ディレクトリで `python manage.py collectstatic` 実行すると16~~のディレクトリに集まってしまい、なかなかmanage.py周りの挙動が読めずに難しいです。

結果的に失敗。

ちなみに1640876919 はUNIX時間で、 `2021年12月31日 00:08:39` を指しています。

## Whitenoiseを使う

検索する中で静的ファイルの配信を補助するミドルウェアとして**Whitenoise**が紹介されていたのでこちらを試してみました。


`manage.py`に記載して配信を試みたものの使い方がわからない...



## Urls.py(ルーティング)のパターンマッチで試行錯誤



```python:mysite/urls.py
urlpatterns = [
    path('startapp/', include('startapp.urls')), #ここをnamespaceで渡すと怒られる
    url(r'^admin/', admin.site.urls),
]

```

を`url('{実際のstaticファイルの階層}', include('startapp.urls'))`などに書き換えてみたがうまくいかず。

URLのディスパチャについては公式ドキュメントにもまとめがあったのでこちらを参考にするといいかも。
https://docs.djangoproject.com/en/4.0/topics/http/urls/


## setting.pyのstatic URLを試す

検索でひっかかるものではこれが一番多かったように思います。

```python:mysite/settings.py

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / "static",
]
```

Djangoの組み込み定数などに渡そうとしてもなかなかうまく使えず、
実パスを指定する、という方向性が今回の正解だったようです。


## その他

これらの静的なファイルが読み込まれてどうかをどうかを出力するために、
htmlに

```html:index.html
<script>
  {% load static %}
  console.log("{% static 'アプリケーション名' %}");
  document.write("{% static 'アプリケーション名' %}");
<script/>
```
を記載してデバッグを行いました。(これはcssや画像などのメディアファイルを指定してもOK)

Printデバッグはあらゆる場面で大切ですね。




# 所感


Djangoはフルスタックなフレームワークの中でも言語側(python)の仕様をあまり知らなくても使いやすいという感覚があるのですが、簡単なPrintデバッグや組み込みの定数にどういうパスが格納されるか、といった情報を理解するためにもPythonの素振りは大切ですね。

デバッグモードだとこれらの静的なファイルをDjangoくんが探してくれるだけになかなか正解にたどり着くのに苦労しました。

正解を求めてネットサーフィンをする中で何処かの記事で見かけましたが、
デプロイについては本当に「正解が無い」、あるいは正答が無数にあるのでそれを選ぶのが大変、みたいなのは真だな、とうなずく出来事でした。


マネクラ(というか今風のデプロイ環境)に関しては、フロントエンドに当たる部分の安定化の流れとしてはAPIモードでのフロントエンドとの関心の分離やCDNの利用を前提として、プリミティブなマークアップの利用はあまり考慮されてなかったりするんでしょうかね。(特にロリポップなどはプロによる商用利用が多いでしょうし。)




おわり。