1
3

Djangoの設定するところまで

Last updated at Posted at 2022-10-16

はじめに

この記事の続きです。

設定ファイルを編集するところまで。

dockerコンテナに接続

appcontainer_nameで指定したもの。

ホストサーバー
# docker exec -it app bash

設定ディレクトリを作成

以下のコマンドをプロジェクトディレクトリで実行します。

コンテナ
# django-admin startproject config .

configは任意のプロジェクト名
第二引数に.(カンマ)を入れることで、configという設定ディレクトリを作成する。
第二引数を指定しない場合、configという名前のプロジェクトディレクトリに
configという同じ名前の設定ディレクトリが作成されてしまうので、ややこしくなってしまいます。

設定ファイルの編集

環境変数を使う

設定は環境変数から読ませるようにする。
Dockerコンテナビルド時に、.envファイルに記述した内容がコンテナの環境変数として設定される。
(参考)以下のようにコンテナ内でechoprintenvで確認することができる。

コンテナ
# echo $DJANGO_CONTAINER_NAME
app

環境変数の読み込みは、標準ライブラリのosを使う。

settings.py
+ import os
from pathlib import Path

ベースディレクトリ設定

標準設定のまま。
Path(__file__).resolve()は、settings.pyに対して上の上の階層のディレクトリをベースディレクトリとするという意味。
manage.pyがあるディレクトリを設定している。

settings.py
BASE_DIR = Path(__file__).resolve().parent.parent

シークレットキーの設定

暗号化やハッシュ化で用いられる秘密鍵の指定。

settings.py
- SECRET_KEY = 'django-insecure-hq2(b=+ap$1lg-69i!+5e@a*az2l119uur&83+h6-1xl%3=_iu'
+ SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY")
.env
+ DJANGO_SECRET_KEY = django-insecure-hq2(b=+ap$1lg-69i!+5e@a*az2l119uur&83+h6-1xl%3=_iu

デバッグモードの設定

.envで設定したデバッグモード設定がTrueのときにデバッグモードになる。
デバッグモードでは、エラーなどがあるとデバッグメッセージが表示される。
本番デプロイ時はFalseにすること。

settings.py
- DEBUG = True
+ DEBUG = os.environ.get("DJANGO_DEBUG") == "True"
.env
+ DJANGO_DEBUG = True

許可ホスト設定

許可するIPやドメインを設定する。
ホスト・ヘッダインジェクションに有効。
os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")とすることでリスト化して複数設定可能。
開発時は["*"]でよいが、本番適用する場合はドメイン名を入力すること。

settings.py
- ALLOWED_HOSTS = []
+ ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS").split(" ")
.env
+ DJANGO_ALLOWED_HOSTS = *

自動的にURLにスラッシュを入れてくれる設定

settings.py
+ APPEND_SLASH = True

アプリケーション

Djangoで利用するアプリケーション。
追加する場合はカンマ区切りで追記する。

settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

ミドルウェア

Djangoで利用するミドルウェア。
追加する場合はカンマ区切りで追記する。

settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    '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',
]

ルーティングファイル

最初に呼び出されるルーティングファイル。
ベースディレクトリから見たときの相対パスで記述される。ファイル名は.pyは省略される。
つまり、manage.pyがあるディレクトリから見て、./config/urls.pyのパスのファイルを指す。

settings.py
ROOT_URLCONF = 'config.urls'

HTMLテンプレートディレクトリ

DIRSにHTMLテンプレートを保存するディレクトリのパスを記述する。
ディレクトリは作成しておくこと。

コンテナ
# mkdir templates
settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
-         'DIRS': [],
+         '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ファイル

WSGIファイルの場所を指定。
PythonはWEB用の言語ではないので、ブラウザで見られるように中間処理が必要。
中間処理を担うのがWSGI(ウィズギー)という仕組み。
今回の構成では、WSGIサーバーとしてGunicornを利用している。
設定は特に変更する必要はない。

settings.py
WSGI_APPLICATION = 'config.wsgi.application'

データベース設定

デフォルトでは、SQLite3を使う設定になっている。
PostgreSQLを使うために設定を変更する。
利用するデータベースおよびログインユーザーやパスワードなどを記述する。
ATOMIC_REQUESTSはトランザクション有効化の設定。

settings.py
DATABASES = {
    'default': {
-         'ENGINE': 'django.db.backends.sqlite3',
+         'ENGINE': 'django.db.backends.postgresql_psycopg2',
-         'NAME': BASE_DIR / 'db.sqlite3',
+         'NAME': os.environ.get('POSTGRES_DB'),
+         'HOST': os.environ.get('POSTGRES_ADDR'),
+         'PORT': os.environ.get('POSTGRES_PORT'),
+         'USER': os.environ.get('POSTGRES_USER'),
+         'PASSWORD': os.environ.get('POSTGRES_PASSWORD'),
+         'ATOMIC_REQUESTS': True,
+         'TIME_ZONE': os.environ.get('TZ'),
    }
}

パスワードのバリデーションルール設定

ユーザー名と似たパスワード、パスワード長、よくあるパスワード、数値のみのパスワードをNGにするなどの設定。

settings.py
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+         'OPTIONS':{"min_length":8},
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

言語設定

英語が標準になってるので日本語に設定。
USE_I18Nは、多言語化機能を有効にするか否かの設定。

settings.py
- LANGUAGE_CODE = 'en-us'
+ LANGUAGE_CODE = 'ja'
+ USE_I18N = True

地域(タイムゾーン)設定

TIME_ZONEは、環境変数で設定しているタイムゾーンで設定する。
USE_TZは、タイムゾーン変換機能を有効にするか否かの設定(Trueにすると、DBに保存する時間がUTC時間になる)
USE_L10NをTrueにすると、日付フォーマットがデフォルト値に設定される。
日付フォーマットを変更したい場合は、USE_L10NをFalseに設定した上で、DATE_FORMATで設定する。

settings.py
- TIME_ZONE = 'UTC'
+ TIME_ZONE = os.environ.get('TZ')
- USE_TZ = True
+ USE_TZ = False

セッション保持設定

SESSION_COOKIE_AGEでセッションを保持する時間を秒単位で設定する。
この設定だけだと、ログインからの秒数で切れる。
SESSION_SAVE_EVERY_REQUESTを有効化すると、ログインした状態で最後にページを表示してからの時間で切れるようになる。
SESSION_EXPIRE_AT_BROWSER_CLOSEを有効にすると、ブラウザを閉じるとセッションが切れる。

settings.py
+ SESSION_COOKIE_AGE = 3600 * 24
+ SESSION_SAVE_EVERY_REQUEST = True
+ SESSION_EXPIRE_AT_BROWSER_CLOSE = True

静的ファイルを保管するディレクトリの設定

静的ファイルを保存する場所は、2種類(staticmediaが)ある。
staticは、アプリケーションに必要なファイルを置く。例えばアプリに必要な画像とか、.jsファイルとか.cssファイルとか。
mediaは、ユーザーがアップロードしたPDFや画像などのファイルを置く。
静的ファイルへのアクセスは、Nginxなどのウェブサーバーから直接アクセスさせることで、Django側の負荷を軽減させることができる。

staticディレクトリとmediaディレクトリを作成します。

コンテナ
# mkdir static media

STATIC_URLは、静的ファイルを保管するディレクトリ。先程作ったやつ。
STATIC_ROOTは、python manage.py collectstaticしたときに静的ファイルを集めてくるディレクトリ。
python manage.py collectstaticは、各アプリにある静的ファイルを集めてくるコマンド。
設定していないが、STATICFILES_DIRSというものがあるが、これは開発環境用のstaticディレクトリの設定らしい。STATIC_ROOTと重複設定不可。
MEDIA_ROOTを設定しない場合、ベースディレクトリにアップロードされるので、必ず記載すること

settings.py
- STATIC_URL = 'static/'
+ STATIC_URL = '/static/'
+ STATIC_ROOT = f'/{BASE_DIR.name}/static'

+ MEDIA_URL = '/media/'
+ MEDIA_ROOT = f'/{BASE_DIR.name}/media'

主キー(PrimaryKey)の設定

モデルにprimary_key=Trueを定義しない場合、自動でidという名前の主キーのフィールドが追加される。

  • AutoField: IntegerFieldを継承した1~2147483647の範囲
  • BigAutoField: BigIntegerFieldを継承した1~9223372036854775807の範囲
  • SmallAutoField: SmallIntegerFieldを継承した1~32767の範囲
settings.py
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

ログ設定

LOG_BASE_DIRで、ログ保存場所を指定。
versionは、必ず1にします。
disable_existing_loggersは、設定ファイルで定義されていないloggerの無効化設定(True:全て無効化/False:無効化しない)
formattersは、ログフォーマット設定。
handlersは、ハンドラ(ログ出力先)設定。
loggersは、ロガー(ログ出力オブジェクト)の設定。
rootは、ルートロガー(ロガー設定に当てはまらない場合)の設定。
以下、すべて追記です。

settings.py
LOG_BASE_DIR = '/logs/django/'
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'production': {
            'format': '%(asctime)s [%(levelname)s - %(filename)s:%(lineno)d] %(message)s'
        },
    },

    'handlers': {
        # DEBUGログは0.5GBでローテーション(3ファイルまで)
        'debug': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            "filename": os.path.join(LOG_BASE_DIR, "debug.log"),
            'formatter': 'production',
            'maxBytes': 1024 * 1024 * 0.5,
            'backupCount': 3,
        },
        # INFOログは7日で4ファイル(4週間)保管
        'info': {
            'level': 'INFO',
            'class': 'logging.handlers.TimedRotatingFileHandler',
            "filename": os.path.join(LOG_BASE_DIR, "info.log"),
            'formatter': 'production',
            'when': 'D',
            'interval': 7,
            'backupCount': 4,
        },
        # ERRORログは7日で4ファイル(4週間)保管
        'error': {
            'level': 'ERROR',
            'class': 'logging.handlers.TimedRotatingFileHandler',
            "filename": os.path.join(LOG_BASE_DIR, "error.log"),
            'formatter': 'production',
            'when': 'D',
            'interval': 7,
            'backupCount': 4,
        },
        # Djangoログは0.5GBでローテーション(3ファイルまで)
        'django': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            "filename": os.path.join(LOG_BASE_DIR, "django.log"),
            'formatter': 'production',
            'maxBytes': 1024 * 1024 * 0.5,
            'backupCount': 3,
        },
        # コンソール表示
        'console': {
            'level': 'DEBUG',
            "class": "logging.StreamHandler",
            'formatter': 'production',
        },
    },

    'loggers': {
        'debug': {
            'handlers': ['debug'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'info': {
            'handlers': ['info'],
            'level': 'INFO',
            'propagate': True,
        },
        'error': {
            'handlers': ['error'],
            'level': 'ERROR',
            'propagate': True,
        },
        'django': {
            'handlers': ['django'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'console': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': True,
        },
    },

    "root": {
        "handlers": ["console"],
        "level": "DEBUG",
        "propagate": False
    },
}

gunicorn設定

Gunicorn起動用の設定ファイルを作成。

コンテナ
# touch config/gunicorn_settings.py
# chmod 666 config/gunicorn_settings.py 
config/gunicorn_settings.py
wsgi_app = 'config.wsgi:application'
chdir = '/code/'
daemon = False
bind = '0.0.0.0:8080'
workers = 1
accesslog = '/logs/gunicorn/gunicorn_access.log'
errorlog = '/logs/gunicorn/gunicorn_error.log'

コンテナを起動しなおす

コンテナを起動しなおして、.envを再読み込みさせる。

コンテナ
# exit
ホストサーバー
# docker-compose down
# docker-compose up -d

再度接続してGunicornが起動していることを確認する。

ホストサーバー
# docker exec -it app bash

systemctlと同様に、supervisorctl status {プロセス名}で動作確認可能。

コンテナ
# supervisorctl status gunicorn
gunicorn                         RUNNING   pid 8, uptime 0:00:15

ここまでの状態ではコンテンツがないので、ブラウザで何も表示できない。
これから中身を作っていく必要がある。

続き

こちらの記事に続きます。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3