ハロートレーニングでは「Django3超入門」という書籍をテキストにDjangoを学習したのですが、自己学習でその本をもう一度おさらいした後、この本を新たに購入しました。Djangoは、なかなかにとっつきにくい感じがして、いろんな本で繰り返し学習するのがいいのかなと思ったからです。フレームワークを使うということは実際にソフトウェアを組み上げることに直接繋がっているので、実務でOJTできる環境にない私のような定年退職者には、とりあえずいろんな学習本を試してみる方法がいいように思いました。
さて、「Djangoのツボとコツがゼッタイにわかる本」(略称「ジャンツボ本」ってことで=^^;=)ですが、系統立てて書かれていて学びやすかったです。WindowsパソコンにWSLでLinuxの仮想環境を作り、VS Codeと連携させながら、さらにPythonの仮想環境を構築して学習環境を作るやり方は、とてもいいです。今後の開発環境をどうしようかなと考えていたこともあり、参考になります。Djangoのプログラミング部分も、「本棚アプリケーション」を作っていく流れで説明されていて、ちょうどこの手のアプリの作成を考えていたので、こちらもばっちりでした。
で、前回の「Pythonツボコツ本」に続いて、こちらも勝手に注釈というか増補しちゃいます。というのも、この本の最後の方で、Herokuを使ってデプロイする説明があるのですが、このHerokuが2022年11月28日をもって無料プランの提供が廃止されたそうなのです。私のような駆け出しの学習者&低収入定年退職者としては、やはり無料プランで始めたいところです。調べてみたところ、RenderというのがHerokuの代替として無料で使えそうだったので、これも修行じゃ、ということで、トライしてみました。といっても、すでにRenderでのデプロイについてとても詳しく解説されているサイト(Zennというエンジニアのための情報共有コミュニティサイトに、DjangoをRenderにデプロイする方法という記事をはるさんという方が書かれています。)があったので、それを参考にさせてもらいました。ここでは、「ジャンツボ本」の流れで、HerokuをRenderに置き換える際のポイントを中心に書いておこうとおもいます。DjangoのRenderへのデプロイの詳細は、先のサイトをご参照ください。私もほぼ同じ流れで作業してます。
というわけで、まずは「ジャンツボ本」第6-2章のgithubでのリモートリポジトリ作成とgitのインストールまでは終えておきます。なお、よくわからずにVSCodeからコミットしたら、リポジトリも新たに作成されたのですが、結果的にはこのままではだめでした。=^_^;= このあとにある「6.git環境の再設定」でやり直ししてます。なので、githubのリポジトリ作成は済ませておいてください。 続いて、DjangoをRenderにデプロイする方法を参照しながら、少し進めてみたところ、途中でエラーが発生したこともあり、Renderのドキュメントもあわせて参照しながら以下のやり方で切り抜けました。
行った手順は以下のとおりです。「ジャンツボ本」で既に実施済みや作成済みのものは、当然必要ないのでとばしてます。また、既にある内容に合わせて修正する必要もあるので、試行錯誤しながら進めました。こういうところは、パズル感覚で面白いのです。自分の手を動かした者のみがもらえる楽しみです。余談ですが、金はないけど時間はある定年後は、こういう楽しみを積極的に取りに行くのがいいと私は思ってます。
- .gitignoreの作成
- requirements.txtの作成とパッケージのインストール
- setting.pyを修正
- スーパーユーザー作成用環境の構築
- ビルドスクリプトの作成
- git環境の再設定
- いざデプロイ
- おまけ
なお、python仮想環境の作成やプロジェクトおよびアプリの作成は、「ジャンツボ本」の中でやっているので何もしてません。
1..gitignoreの作成
.gitignoreの作成は以下の内容で行いました。
__pycache__ .env /venv/ /media/* !/media/.gitkeep /static/ !/static/.gitkeep db.sqlite3 .vscode *.pyc .DS_Store
2.requirements.txtの作成とパッケージインストール
requirements.txtは以下の内容で作成し、「pip install -r requirements.txt」コマンドでパッケージをインストールしました。
asgiref==3.7.2 Django==3.2 Pillow==10.1.0 pytz==2023.3 sqlparse==0.4.4 typing_extensions==4.7.1 dj-database-url dj-static python-decouple django-environ gunicorn psycopg2-binary whitenoise
3.setting.pyファイルの修正
以下のようにsetting.pyファイルに修正(# for Renderでコメントしている箇所)を加えました。whitenoiseってのを使うようなのですが、よくわかってません=^_^;= Djangoでのstatic fileを使いやすくするソフトかなんかなのでしょうか。ただ、このままだとローカルで動かなくなるので、Renderのドキュメントに書いてあるように、if not DEBUG:を挿入して、ローカルでテストしたい場合は、DEBUG = Trueにして動かすようにしました。
from pathlib import Path
# for Render
import os
import environ
from decouple import config
from dj_database_url import parse as dburl
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# for Render
env = environ.Env()
env.read_env(os.path.join(BASE_DIR, ".env"))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-dd__p*&*vi3q__6vt8oog2g56ft#8-hils6e=u(+zl1q)odh1t'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False # デプロイする前には必ず False にします!ローカルでの動作確認時はTrueで
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'accounts.apps.AccountsConfig',
'book.apps.BookConfig',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # for Render
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# for Render
default_dburl = "sqlite:///" + str(BASE_DIR / "db.sqlite3")
ROOT_URLCONF = 'bookproject.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'bookproject.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
#'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
"default": config("DATABASE_URL", default=default_dburl, cast=dburl), # for Render
#}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
if not DEBUG: # ローカルでの動作確認用に追加
STATIC_ROOT = str(BASE_DIR / 'staticfiles') # for Render
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" # for Render
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_REDIRECT_URL = 'index'
LOGOUT_REDIRECT_URL = 'index'
# for Render
SUPERUSER_NAME = env("SUPERUSER_NAME")
SUPERUSER_EMAIL = env("SUPERUSER_EMAIL")
SUPERUSER_PASSWORD = env("SUPERUSER_PASSWORD")
4.スーパーユーザー作成用環境の構築
Renderへのssh接続は無料版だと使えないらしく、端末でスーパーユーザーの作成ができないので、python経由でスーパーユーザーを作成するコマンドを用意します。setthing.pyの最後にも一部記述がありますが、これに加えて、.envファイルに環境変数を記述し、コマンド発行用のプログラムをsuperuser.pyに書いておきます。
# .envファイル SUPERUSER_NAME=webadmin SUPERUSER_EMAIL=webadmin@webadmin.com SUPERUSER_PASSWORD=*******
# superuser.pyファイル
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from django.conf import settings
User = get_user_model()
class Command(BaseCommand):
def handle(self, *args, **options):
if not User.objects.filter(username=settings.SUPERUSER_NAME).exists():
User.objects.create_superuser(
username=settings.SUPERUSER_NAME,
email=settings.SUPERUSER_EMAIL,
password=settings.SUPERUSER_PASSWORD
)
print("スーパーユーザー作成")
5.ビルドスクリプトの作成
Render にデプロイするために、build.shファイルと、render.yamlファイルを作成します。
# build.shファイル #!/usr/bin/env bash # exit on error set -o errexit pip install -r requirements.txt python manage.py collectstatic --no-input python manage.py migrate python manage.py superuser
# render.yamlファイル
databases:
- name: django_render_db
region: singapore
plan: free
databaseName: django_render_db
user: django_user
services:
- type: web
name: django_render
env: python
region: singapore
buildCommand: './build.sh'
startCommand: 'gunicorn bookproject.wsgi:application'
plan: free
branch: main
healthCheckPath: /
envVars:
- key: DATABASE_URL
fromDatabase:
name: django_render_db
property: connectionString
- key: SECRET_KEY
generateValue: true
- key: WEB_CONCURRENCY
value: 4
autoDeploy: true
6.git環境の再設定
さて、いよいよデプロイへ、と行きたいところだったのですが、この後エラーが出て試行錯誤したのですが、原因としてgitのルートディレクトリ(って言うんでしょうか?)がmanage.pyのあるディレクトリでなかった(私の場合、ひとつ上にディレクトリになってた)ことでうまくいかなかったわけでした。なので、以下のコマンドをmanage.pyのあるディレクトリで発行してからgitへプッシュし直しました。あと、renderサイトのアカウントも作成しておきます。Renderへのログイン時の認証をgithub経由で行うことで、Renderとgithubの連携がされているようでした。このあたりは、私もよくわかってないので、今後の修練が必要です。ふぅ~
$ git init $ git add . # ローカルリポジトリにステージング $ git commit -m "コミットメッセージ(任意の文字列)" # ローカルリポジトリにコミット $ git status # 状態を確認 $ git remote add origin リモートリポジトリURL(githubに表示されてます) # ローカルリポジトリとリモートリポジトリを紐づけ $ git push origin main # リモートリポジトリにpush
7.いざデプロイ
RenderにログインしてBlueprintを発行します。詳細は、DjangoをRenderにデプロイする方法を参照してください。ここにも書かれてますが、初回はデプロイに失敗しますので慌てないようにします。(書いてあるのに、失敗にテンパって原因を探ろうとした私です=^_^;=)なお、失敗後に設定する環境変数PYTHON_VERSIONは、ジャンツボ本の環境である3.10.12にしてます。
さぁ、ここまでやって再デプロイしてみると…..

デプロイが完了して
サービスが起動!
そしてRenderにあるURLにアクセスしてみると、登録データはまだありませんが、本棚アプリがRender上で一応動いてるようです。スーパーユーザーも作成されており、ログインできました。管理画面も利用可能です。ま、どっかエラーはあるかもですが、Herokuの代わりにRenderへデプロイするという目的は達成です!やったね、パチパチパチパチ(paizaの霧島さんのノリで =^_^;=)
とはいえ、定年退職者プログラマーの道はまだまだこれからですねぇ。今回痛感したのは、現役時代は色んなインフラを構築したり運用してきましたが、プログラム開発という視点から見ると、とにかく欠けている知識が多いということ。ひとまず、VS Codeについては手ごろな書籍を購入して学習することにします。また、githubも学習優先度が高いです。その先にはDockerも控えていることでしょうね、きっと。
8.おまけ
Renderのドキュメントを参照していて気になったものに、poetryがあります。最新のパッケージ管理ツール?のようで気にはなりましたが、DjangoをRenderにデプロイする方法ではpipで書かれていたので、一応以下のようにインストールはしたものの、使いませんでした。結構便利そうなツールなようで、そのうちトライしてみたいです。
$ curl -sSL https://install.python-poetry.org | python3 - Retrieving Poetry metadata # Welcome to Poetry! This will download and install the latest version of Poetry, a dependency and package manager for Python. It will add the `poetry` command to Poetry's bin directory, located at: /home/penpen/.local/bin You can uninstall at any time by executing this script with the --uninstall option, and these changes will be reverted. Installing Poetry (1.7.1): Done Poetry (1.7.1) is installed now. Great! To get started you need Poetry's bin directory (/home/penpen/.local/bin) in your `PATH` environment variable. Add `export PATH="/home/penpen/.local/bin:$PATH"` to your shell configuration file. Alternatively, you can call Poetry explicitly with `/home/penpen/.local/bin/poetry`. You can test that everything is set up by executing: `poetry --version`
あと、ALLOWED_HOSTSの設定も気になってます。こちらも情報を集めつつ、ステップアップする必要がありそうです。そろそろ、独自にプログラミングしたいところだったのですが、まだまだ修行が必要なようです。