【Docker】在Django中使用多个数据库(MySQL)& 使用django-jet管理网站& 使用django-reversion进行表格变更历史管理
版本信息
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文件
我正在搭建两个数据库容器(db1和db2),但如果将包含两个CREATE DATABASE语句的DDL文件挂载到docker-entrypoint-initdb.d目录中,就可以在一个数据库容器中构建多个数据库,而且这样更好w(只需将DDL文件放入db_data文件夹中,它会被挂载到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
Docker文件
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
等待它.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
要求的文件.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
创建数据库路由器
在设置数据库路由器之后,可以根据每个应用程序切换数据库(例如,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文件记录数据库连接信息。
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
#
执行迁移操作(在数据库中创建各种表)
迁移将分两次执行。
▼第一次
→在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
#
只需一种选择:
▼第二步
→在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.
如果需要在另一个数据库中创建,只需指定相应的数据库即可。
# 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)
管理网站显示
无问题地显示,并且可以通过管理网站进行数据添加等操作。
在管理网站的模板中使用django-jet
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/
喷气式飞机的迁移
# 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
仪表盘的迁移
# 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的管理网站是可以自定义的,所以请随意搜索并进行自定义!