バージョン情報
Python:3.7.2
Django:2.2.5
pyenvで仮想環境の準備・適用
仮想環境作成
$ pyenv virtualenv 3.7.2 sample_project_env
仮想環境適用
$ cd /~省略~/sample_project
$ pyenv local sample_project_env
Djangoプロジェクトの作成
Djangoをインストール
$ pip install django==2.2.5
プロジェクト作成
$ mkdir sample_project ※sample_projectフォルダの直下にさらにsample_projectフォルダを作成
$ cd sample_project
$ django-admin startproject config .
dockerで各種コンテナ立ち上げ
docker-compose.yml
dbコンテナを2つ(db1, db2)立てていますが、CREATE DATABASE文を2つ記載したDDLをdocker-entrypoint-initdb.dにマウントすればdbコンテナ1つで複数データベースの構築はできますし、むしろそっちのが良いですw
(db_dataフォルダの中にDDLを入れればdocker-entrypoint-initdb.dにマウントされるようになってます。)
version: '2'
services:
web:
build:
context: ../
dockerfile: sample_project/Dockerfile
container_name: sample_project
volumes:
- '../:/src'
environment:
- LC_ALL=ja_JP.UTF-8
ports:
- '8000:8000'
depends_on:
- db1
- db2
- redis
entrypoint: sample_project/wait-for-it.sh db1 user user
command: python3 sample_project/manage.py runserver 0.0.0.0:8000 --settings=config.settings
tty: true
redis:
image: 'redis:4.0.8'
restart: always
ports:
- "6379:6379"
volumes:
- './redisdata:/data'
db1:
image: mariadb:latest
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
environment:
- MYSQL_ROOT_USER=root
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=sample_project_1
- MYSQL_USER=user
- MYSQL_PASSWORD=user
volumes:
- db1_data:/var/lib/mysql
- ./db1_data:/docker-entrypoint-initdb.d
ports:
- '3307:3306'
db2:
image: mariadb:latest
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
environment:
- MYSQL_ROOT_USER=root
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=sample_project_2
- MYSQL_USER=user
- MYSQL_PASSWORD=user
volumes:
- db2_data:/var/lib/mysql
- ./db2_data:/docker-entrypoint-initdb.d
ports:
- '3308:3306'
volumes:
db1_data:
driver: local
db2_data:
driver: local
Dockerfile
FROM ubuntu:18.04
RUN apt-get -y update \
&& apt-get install -y locales python3-pip python3.7 libmysqlclient-dev mysql-client\
&& mkdir /src \
&& rm -rf /var/lib/apt/lists/* \
&& echo "ja_JP UTF-8" > /etc/locale.gen \
&& locale-gen
WORKDIR /src
ADD ./ /src/
RUN LC_ALL=ja_JP.UTF-8 pip3 install -r sample_project/requirements.txt
wait-for-it.sh
# !/bin/sh
set -e
host="$1"
shift
user="$1"
shift
password="$1"
shift
cmd="$@"
echo "Waiting for mysql"
until mysql -h "$host" -u "$user" -p"$password" &> /dev/null
do
>$2 echo -n "."
sleep 1
done
>&2 echo "MySQL is up - executing command"
exec $cmd
requirements.txt
celery==4.2.1
cryptography==2.1.4
Django==2.2.5
django-celery-results==1.0.4
django-debug-toolbar==1.9.1
django-environ==0.4.5
django-jet==1.0.8
django-lint2==0.1
django-redis==4.10.0
django-reversion==3.0.4
mysqlclient==1.3.13
redis==3.2.0
requests==2.22.0
sqlparse==0.2.4
urllib3==1.25.3
vine==1.3.0
python-dateutil==2.8.0
コンテナ立ち上げ
$ docker-compose up --build -d
.
..
...
Successfully built aa2166b8e593
Successfully tagged sample_project_web:latest
Creating sample_project_db1_1 ... done
Creating sample_project_db2_1 ... done
Creating sample_project_redis_1 ... done
Creating sample_project ... done
Djangoの起動画面確認
複数データベースの作成
モデル作成用にアプリケーション作成
$ python3 manage.py startapp app1
$ python3 manage.py startapp app2
モデル作成
from django.db import models
# Create your models here.
class Db1Table1(models.Model):
column1 = models.CharField(max_length=10)
def __str__(self):
return self.column1
from django.db import models
# Create your models here.
class Db2Table1(models.Model):
column1 = models.CharField(max_length=10)
def __str__(self):
return self.column1
Database routerを作成
データベースルーター(Database router)を設定すると、アプリケーション毎にデータベースを切り替えることができます。
(app1がdb1、app2がdb2といった感じに。)
class DbRouter:
def db_for_read(self, model, **hints):
if model._meta.app_label == 'app1':
return 'db1'
if model._meta.app_label == 'app2':
return 'db2'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == 'app1':
return 'db1'
if model._meta.app_label == 'app2':
return 'db2'
return None
def allow_relation(self, obj1, obj2, **hints):
return True
def allow_migrate(self, db, app_label, model=None, **hints):
if app_label == 'app1':
return db == 'db1' or db == 'default'
if app_label == 'app2':
return db == 'db2'
return None
.envにDB接続情報を記載
DEBUG=True
DATABASE_URL_1=mysql://user:user@db1:3306/sample_project_1
DATABASE_URL_2=mysql://user:user@db2:3306/sample_project_2
settings.pyを編集
.
..
...
import os
from config import environ # 追加
.
..
...
# 追加
env_file = os.path.join(BASE_DIR, '.env')
env = environ.Env()
env.read_env(env_file)
.
..
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app1', # 追加
'app2', # 追加
]
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',
]
.
..
...
DATABASES = {
'default': env.db_url(var='DATABASE_URL_1'),
'db1': env.db_url(var='DATABASE_URL_1'),
'db2': env.db_url(var='DATABASE_URL_2'),
}
# 作成したDatabase routerを設定
DATABASE_ROUTERS = ['config.db_router.DbRouter']
.
..
...
# ついでにLANGUAGE_CODE、TIME_ZONE、USE_I18N、USE_L10N、USE_TZも書き換える
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'
USE_I18N = True
USE_L10N = True
USE_TZ = False
.
..
...
マイグレーションファイル作成
ホストマシンからはマイグレーション操作が失敗するので、一旦dockerで立ち上げたwebコンテナに潜ってからマイグレーションファイルを作成。
$ docker exec -it sample_project /bin/bash
# cd sample_project/
# python3 manage.py makemigrations
Migrations for 'app1':
app1/migrations/0001_initial.py
- Create model Db1Table1
Migrations for 'app2':
app2/migrations/0001_initial.py
- Create model Db2Table1
#
マイグレート実行(DBに各種テーブル作成)
マイグレートは2回に分けて実行します。
▼1回目
→db1にapp1のモデルに定義したテーブルとDjangoの管理テーブルを作成します。
# python3 manage.py migrate
▼実行結果
# python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, app1, app2, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying app1.0001_initial... OK
Applying app2.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
#
▼2回目
→db2にapp2のモデルに定義したテーブルとDjangoの管理テーブルを作成します。
→ここではマイグレートを実行するデータベースを指定しています。
(データベースを指定しない場合、settings.pyの'default'に指定したデータベースが使用されてしまいます。)
# python3 manage.py migrate --database=db2
▼実行結果
# python3 manage.py migrate --database=db2
Operations to perform:
Apply all migrations: admin, app1, app2, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying app1.0001_initial... OK
Applying app2.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying sessions.0001_initial... OK
#
データベース確認
データベースごとに作成するテーブルを分けることができました。
スーパーユーザーの作成
ユーザー名とパスワードは「root」にしました。
(adminとかにしたら管理サイトには入れなくなったりしたのでrootが良さげ(原因不明))
# python3 manage.py createsuperuser
ユーザー名 (leave blank to use 'root'): root
メールアドレス: root@root.jp
Password:
Password (again):
このパスワードは ユーザー名 と似すぎています。
このパスワードは短すぎます。最低 8 文字以上必要です。
このパスワードは一般的すぎます。
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
もう一個のデータベースにも作成したいなら同様にデータベースを指定してあげればOK
# python3 manage.py createsuperuser --database=db2
Django管理サイト確認
管理サイトに表示するテーブルを指定する
from django.contrib import admin
from app1.models import Db1Table1
# Register your models here.
admin.site.register(Db1Table1)
from django.contrib import admin
from app1.models import Db2Table1
# Register your models here.
admin.site.register(Db2Table1)
管理サイト表示
http://localhost:8000/admin
に接続
問題なく表示され、管理サイトからテーブルへのデータ追加等も行うことができました。
管理サイトのテンプレートにdjango-jetを使用する
settings.pyを編集
.
..
...
INSTALLED_APPS = [
'jet.dashboard', # django.contrib.adminとjetより前に記載する
'jet', # django.contrib.adminより前に記載する
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app1',
'app2',
]
...
..
.
urls.pyを編集する
from django.conf.urls import url, include # 追加
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^jet/', include('jet.urls', 'jet')), # 追加
url(r'^jet/dashboard/', include('jet.dashboard.urls', 'jet-dashboard')), # 追加
]
jetとdashboardのマイグレートを実行する
例のごとく一度dockerで立ち上げたwebコンテナに潜ってから
$ docker exec -it sample_project /bin/bash
# cd sample_project/
jetのマイグレート
# python3 manage.py migrate jet
Operations to perform:
Apply all migrations: jet
Running migrations:
Applying jet.0001_initial... OK
Applying jet.0002_delete_userdashboardmodule... OK
dashboardのマイグレート
# python3 manage.py migrate dashboard
Operations to perform:
Apply all migrations: dashboard
Running migrations:
Applying dashboard.0001_initial... OK
Djangoの管理サイトがかっこよくなります。
django-reversionで変更履歴管理
django-reversion導入前の変更履歴ページはこんな感じ
ドキュメントはココ
settings.pyを編集
.
..
...
INSTALLED_APPS = [
'jet.dashboard',
'jet',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'reversion', # 追加
'app1',
'app2',
]
...
..
.
マイグレート実行
# python3 manage.py migrate
Operations to perform:
Apply all migrations: admin, app1, app2, auth, contenttypes, dashboard, jet, reversion, sessions
Running migrations:
Applying reversion.0001_squashed_0004_auto_20160611_1202... OK
app1とapp2のadmin.pyを編集
from django.contrib import admin
from reversion.admin import VersionAdmin
from app1.models import Db1Table1
# Register your models here.
@admin.register(Db1Table1)
class Db1Table1Admin(VersionAdmin):
pass
from django.contrib import admin
from reversion.admin import VersionAdmin
from app2.models import Db2Table1
# Register your models here.
@admin.register(Db2Table1)
class Db2Table1Admin(VersionAdmin):
pass
管理サイトの変更履歴ページを確認
最後に
django-jetの管理サイトはカスタマイズできるようなので適当にググってカスタマイズしてみてください!