【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 .
image.png

使用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的启动画面。

image.png

创建多个数据库

为了建立模型而创建应用程序

$ 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
#

查看数据库

image.png
image.png

创建超级用户

用户名和密码设置为”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)

管理网站显示

image.png

无问题地显示,并且可以通过管理网站进行数据添加等操作。

在管理网站的模板中使用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的管理网站变得很酷。

image.png
image.png

使用django-reversion进行更改历史记录管理。

django-reversion導入前的變更記錄頁面看起來像這樣。
文件在這裡。

image.png

编辑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

查看管理网站的变更历史页面

image.png
image.png

最后

既然Django-Jet的管理网站是可以自定义的,所以请随意搜索并进行自定义!

广告
将在 10 秒后关闭
bannerAds