【Django】PythonAnywhere.comへdeploy

Djangoで作ったwebアプリをPythonAnywhere.comにデプロイしたときの忘備録です。
初めてPythonAnywhere.comを使用される方で、いろいろな記事を参考にデプロイしようとしているのであれば、**全体の流れを確認してから作業することをお勧めします。**
※プランによってはサーバーのCPUの使用制限により、しばらく作業ストップとなる恐れがあるため。

1\. 【pythonanywhere】pythonanywhereのアカウントをとり、APIトークンを作成する。
2\. 【ローカル】settings.pyをデプロイ用の設定にする。
3\. 【GitHub】GitHubにプッシュしておく。
4\. 【pythonanywhere/Bash】Bashでpythonanywhereをインストール
5\. 【pythonanywhere/Bash】pythonanywhereの自動デプロイを実行する。
（自動デプロイしなかった場合、手動でデプロイする場合は６～９の手順を踏む）
6\. 【pythonanywhere/Bash】python-dotenvをインストールして.envファイル作成
7\. 【pythonanywhere/Web】Webページの設定を行う。
8\. 【pythonanywhere/Web】wsgiファイルを設定する。
9\. 【pythonanywhere/Web】Reload実行してサーバーへアクセスして確認。

# 1\. 【PythonAnywhere】PythonAnywhereのアカウントをとり、APIトークンを作成する。

まず下記リンクにアクセスしてアカウントをとるところから始めます。

https://www.pythonanywhere.com/

![pythonanywhere-top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/6d4ac968-9f52-8bf4-33f3-828c70fc54cf.png)


"Start running Python online in less than a minute!"をクリックすると料金一覧のページに移ります。

![pythonanywhere.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/dc0f0d51-42e3-248d-90f0-6d8289ebf33c.png)

無料でPythonAnywhereを使う場合は"Beginner: Free!"のブロックの"Create a Beginner account"をクリックします。

登録するためのフォームに移るので、以下を入力し登録します。
* Username※
* Email
* Password
* Password(agein)
* 利用規約のチェックボックス

なお、"Username"はデプロイした後、Webアプリにアクセスする時のURLに含まれることを考慮して入力するようにしてください。

<details><summary>その他注意点</summary>
また、ここで設定した"Email"をもとに、PythonAnywhereのサーバーCPU利用時間がカウントされます。

**Freeプランの場合は24時間内に100秒サーバーCPUを使うと、その後はしばらく(丸１日)サーバーCPUの優先順位が下がりサーバー側の処理速度が低下します。**
</details>

PythonAnywhereの自動設定を行うためにAPIトークンを作成します。

一番上の青い部分のnavbarにある"Account"をクリック。
![Account-0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/ad6e9509-dc54-4a71-87d7-f1466facbe1a.png)
"API Token"のタブをクリック。

![API_Token00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/0c802d9a-5308-727c-1d5e-6bf34ab7b6c3.png)
"Create a new API token"をクリック。

![API_Token01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/f15ec7d1-5b38-6c61-4a79-b6ac31059590.png)
"Your API token"の下の枠内のコードがAPI Tokenですが、特にメモ等で残す必要はありません。
これでAPI Token作成までできました。

# 2\. 【ローカル】settings.pyをデプロイ用の設定にする。
開発環境のままデプロイするとセキュリティ上まずい部分があるので、最低限の処理をしておきます。ここではローカルでの作業となります。
ローカルでの開発環境でも本番環境での運用時も、書き換えの必要が無いように設定していきます。
以下を組み合わせて設定していきます。
* get_random_secret_key
* python-dotenv
* .gitgnore (local_settings.py)

<details><summary>注意点</summary>
settings.pyにそのままIDやPasswordなど記述してしまっている場合は、セキュリティ上よくありません。.envファイルを設け、そこにIDやPasswordなどを記述して起き、settings.pyで変数として呼び出す形がいいかと思います。
.envファイルはGit管理外にして公開しないようにしておき、PythonAnywhere上では直接.envファイルを作り内容をコピペして読み込むようにします。
"SECRET_KEY"についてはランダムのキーを生成する関数を設定しておくといいと思います。
</details>

python-dotenvをインストールします。
```python:ターミナル【ローカル】
(venv)$ pip install python-dotenv
```

settings.pyと同列に.envを作成します。そこにIDやPasswordなど公開したくない情報を下記のように"export"を付けて変数に格納します。
ここで注意するのが、"="の前後はスペースは入れず、そのあとのキーやパスワードはシングルクォーテーションなどで囲わないことです。

```python:.env
export EMAIL_HOST_PASSWORD=ここに実際のパスワードを記述
... 
```
そして、settings.pyには.envからインポートして変数として受け取るように関数を呼び出します。記述場所は最初の方でいいです。

```python:settings.py
...
import os
from dotenv import load_dotenv
load_dotenv()
...
```
ついでに"SECRET_KEY"にランダムのキーを作成する関数を適用するため、その関数もインポートしておきます。

```python:settings.py
...
from django.core.management.utils import get_random_secret_key
...
```

local_settings.pyに"SECRET_KEY"を記述してGit管理外にしておくことで、local_settings.pyの内容が読み取れれば開発環境、読み取れなければ本番環境という条件分けをします。

settings.pyと同列に**local_settings.py** を作成し、"SECRET_KEY"を記述します。
settings.pyで書かれている部分をそのままコピペします。
```python:local_settings.py
SECRET_KEY = 'django-insecure-$^1@=&p!3ipey$.....'
```
settings.pyの"SECRET_KEY"が書かれている行を削除し、そこに開発環境か本番環境かの条件文を記述します。
```python:settings.py
...
try:
    from .local_settings import *
    DEBUG = True
    FRONTEND_URL = 'http://127.0.0.1:8000/'
    ALLOWED_HOSTS = []

except ImportError:
    DEBUG = False
    SECRET_KEY = get_random_secret_key()
    ALLOWED_HOSTS = ['.pythonanywhere.com']
...
```
続いて、.envに記述した変数を受け取るように書き換えます。
以下は一例です。
```python:settings.py
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD")
...
```

settings.pyの最後に必要であれば下記を記述します。
```python:settings.py
...
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
```
サイト内で静的に画像を貼る、cssやjsファイルを扱う場合はSTATIC_ROOTを、写真付きのブログアプリなど画像ファイルをアップロードするような場合はMEDIA_URL、MEDIA_ROOTを記述します。

manage.pyと同列に、.gitignoreを作成します。
.gitignoreにGit管理外にするファイル、フォルダを書いていくのですが、「gitignore.io」のサイトを使うと便利です。

[gitignore.io](https://www.toptal.com/developers/gitignore ".gitignore.io")にアクセスし、検索窓にDjangoと入力します。
gitignore.ioで取得したコードを作成した.gitignoreファイルにコピぺします。
.gitignoreファイルの冒頭に個別にGit管理外にしたいファイル・フォルダがあれば記述してください。
.envは既に含まれています。
locak_settings.pyを.gitignoreに含めます。
私の場合、settings.pyは"config"フォルダ下に設定しているので、下記のようになりますが、フォルダ名をプロジェクト名にしている場合は適宜書き換えてください。
```python:.gitignore
# Created by https://www.toptal.com/developers/gitignore/api/django
# Edit at https://www.toptal.com/developers/gitignore?templates=django

config/local_settings.py #追加

### Django ###
*.log
*.pot
*.pyc
__pycache__/
local_settings.py
db.sqlite3
db.sqlite3-journal
media
...
```
requirements.txtを作成しておきます。**仮想環境に入った状態** で、かつmanage.pyを実行できるフォルダに移動した上で以下を実行します。
```:ターミナル【ローカル】
pip freeze > requirements.txt
```
これでrequirements.txtが作成され、「pip list」で表示した内容が記されているかと思います。
（自動デプロイを実行したときに、このrequirements.txtに記述したアプリケーションをサーバー側にインストールします）

# 3\. 【GitHub】GitHubにプッシュしておく。
これでローカルでの作業は完了なので、GitHubへプッシュします。

Gitについては、下記有料ですが実践的なことを詳しく解説しています。セール中に買うのがおすすめ。
[【udemy】Git](https://www.udemy.com/share/101WYW3@RDW3pB7EOUCMJnbEKGIlCCtbf7Ve9YcQbIHa3dthL2TrXShyMeQSooEtEIsC_XAWlA==/ "udemy")

# 4\. 【PythonAnywhere/Bash】BashでPythonAnywhereをインストール
PythonAnywhereの"Consoles"ページにアクセス。
![consoles.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/90eaf5b6-20be-4013-857e-575d9060be2c.png)
「Start a new console:」のブロック"Bash"のリンクをクリックしてBash(コンソール)を立ち上げます。

<details><summary>補足</summary>
ここで"ls"と入力してリターンを押すと「README.txt」と表示されます。
/home/＜Username＞/ にいることが、"Files"ページを見ると分かるかと思います。
「README.txt」以外のファイルは先頭に"."が付いていて見えない状態なので、コンソールでは「README.txt」のみ表示となっています。
</details>

PythonAnywhereの自動化ツールをインストールします。
```:Bash
pip install pythonanywhere
```
![pythonanywhere_install_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/66f10549-b5f6-3ced-e589-322ea816024c.png)

# 5\. 【PythonAnywhere/Bash】PythonAnywhereの自動設定を実行する。
自動設定する前に確認することがあります。
ローカルの開発環境のPythonのバージョンを確認しておきます。
```:ターミナル【ローカル】
(venv)$ python --version
```
Pythonのバージョンを確認したら、PythonAnywhereのBashで自動デプロイを実行します。
リモートにブランチを作成した場合は、"--branch"オプションをつけます。"--python"オプションでバージョンを指定します。
これを指定しないとPython3.7が勝手に選ばれてインストールされてしまい、requirements.txtで入れようとしているアプリケーションの対応しているPythonのバージョンが異なり、エラーとなることがあります。
「https://~.git」の部分はGitHubでpullやpushする際に使うURL()を入れてください。
```python:Bash
# WebAppが未作成の場合
pa_autoconfigure_django.py --branch=master --python=3.10 https://~.git

# pa_autoconfigure_django.pyをやり直す場合、"--nuke"オプションが必要。
pa_autoconfigure_django.py --nuke --branch=master --python=3.10 https://~.git
```
上手くデプロイできると下のような表示となります。
![自動デプロイ01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/d742bc96-ff88-0ff4-6f5f-109b544070b4.png)

サーバー側の.envファイルを作成します。
PythonAnywhereのFilesページへ行き、"Directories"の「(Username).pythonanywhere.com」のフォルダをクリックし、"Files"の入力欄に「.env」と入れてすぐ右の「New file」をクリックしてファイルを作成します。

![Files01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/5d044b70-d70c-4b67-7654-2eac07c0340b.png)

エディタが開くので、ローカルで作成した.envの内容をすべてコピペして「Save」ボタンでセーブします。
![dotenv01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/4f6a75c4-a458-7e7d-1e7d-18bc3cda6026.png)

Webページに移ります。
少し下にスクロールすると「Code」のブロックがあるので、そこの「Working directry」の右の青文字をクリックして、すぐ上の行と同様に「/home/(Username)/(Username).pythonanywhere.com」に直します。

![working_directry01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/c2b4932b-7f72-18b7-1dd8-334e32057ac0.png)


下の方にスクロールさせます。
![web-https.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/b2ec46d6-064f-209e-6850-4429c4adbaff.png)
"Force HTTPS"の横の"Disabled"をクリックして"Enabled"に切り替えて、また上にスクロールして"Reload ..."と書いてある緑のボタンをクリックしてリロードします。

![Web-app001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781392/309387ab-bc0b-648e-1a81-4aedf3b80ed1.png)

リロードが完了したら、その上のホームページへのリンクをクリックして、デプロイしていることを確認しましょう！

（※その後、プログラムを修正してアップロードする場合は手順が異なるので注意。データベースもGitHubのものが上書きされるので、データベースのバックアップが必要となります。）


下記を参考にしました。

https://qiita.com/connecrew-sugiyama/items/ce5beafce9201736c39e

https://qiita.com/connecrew-sugiyama/items/5080052e564334672bd6

https://itstudio.co/2020/09/19/11051/#toc4

https://itstudio.co/2020/09/23/11066/

https://note.com/masato1230/n/na63ac4e7ccdd

https://note.com/masato1230/n/n525ed979a59c

https://itc.tokyo/django/setup-static/

https://qiita.com/y_sone/items/2723bb7c1b63abb28f57