djangoをdockerコンテナで利用(2) – pipでdjangoのパッケージを更新する

◆◆◆

インフラ作業してSSL接続によるロケット画面が表示できるようになったので続きを勉強して試しながら実施。

dockerコンテナ内のコマンドライン

python3とpip3を使っていく。
コンテナのbashに入る。

$ docker ps | grep django
8b95c47cd3b0   sv_django:3.1.5           "supervisord -n"         12 days ago   Up 40 minutes   0.0.0.0:38080->8080/tcp, :::38080->8080/tcp                                            docker_sv_django_1
f7530c88c5ab   mysql:5.7                 "docker-entrypoint.s…"   2 weeks ago   Up 39 minutes   33060/tcp, 0.0.0.0:23306->3306/tcp, :::23306->3306/tcp                                 docker_sv_django-DBServer_1
$ docker exec -it docker_sv_django_1 bash
root@svdjango:/#

コンテナの中ではviすら使えないこともあるので、必要ならaptとかyumとかでインストールしておく。

requirement.txtに書いて管理

パッケージを一括で管理する。
他に依存するものは勝手に取ってきてくれるらしい。
upgradeした後で、バージョンNo書き換えれば最新を維持できる。
phpは5から7に上げるとき苦しんがけど、djangoは楽にバージョン上げていける運用になったらいいなぁ。

### 1st step on Django for me
Django==3.1.5
uwsgi==2.0.19
django-markdownx==3.0.1
Markdown==3.3.3
Pillow==7.0.0
PyMySQL

Dockerfileにpip3 installを書いておき、コンテナ作成することでパッケージがインストールされた状態を作れる。

COPY app/requirements.txt /code/app/
RUN pip3 install -r /code/app/requirements.txt

手動パッケージ管理

djangoにはパッケージ管理の考え方があるらしい。
railsのgemみたいなものか。
DBに接続するPyMySQLってのを書くということは、グラフを描いたりpdf表示させるときここを足すのかも。

インストール済みのパッケージ一覧確認(pip list)

root@svdjango:/# pip3 list
Package          Version
---------------- -------
asgiref          3.4.1
Django           3.1.5
django-markdownx 3.0.1
Markdown         3.3.3
Pillow           7.0.0
pip              21.2.4
PyMySQL          1.0.2
pytz             2021.1
setuptools       57.4.0
sqlparse         0.4.1
supervisor       4.1.0
uWSGI            2.0.19
wheel            0.34.2
root@svdjango:/#

アップデート必要なパッケージ一覧確認(pip list -o)

root@svdjango:/code/app# pip3 list -o
Package    Version Latest Type
---------- ------- ------ -----
Markdown   3.3.3   3.3.4  wheel
Pillow     7.0.0   8.3.2  wheel
pytz       2021.1  2021.3 wheel
setuptools 58.0.4  58.2.0 wheel
supervisor 4.1.0   4.2.2  wheel
wheel      0.34.2  0.37.0 wheel
root@svdjango:/code/app#

インストール済みのパッケージの詳細確認(pip show)

root@svdjango:/# pip3 show pip
Name: pip
Version: 21.2.4
Summary: The PyPA recommended tool for installing Python packages.
Home-page: https://pip.pypa.io/
Author: The pip developers
Author-email: distutils-sig@python.org
License: MIT
Location: /usr/local/lib/python3.8/dist-packages
Requires:
Required-by:
root@svdjango:/#

パッケージのインストール(pip install)

root@svdjango:/# pip3 install uwsgi
Requirement already satisfied: uwsgi in /usr/local/lib/python3.8/dist-packages (2.0.19)
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
root@svdjango:/#

パッケージのアップグレード(pip install –upgrade)

root@svdjango:/# pip3 install uwsgi --upgrade
Requirement already satisfied: uwsgi in /usr/local/lib/python3.8/dist-packages (2.0.19)
Collecting uwsgi
  Using cached uWSGI-2.0.19.1-cp38-cp38-linux_x86_64.whl
Installing collected packages: uwsgi
  Attempting uninstall: uwsgi
    Found existing installation: uWSGI 2.0.19
    Uninstalling uWSGI-2.0.19:
      Successfully uninstalled uWSGI-2.0.19
Successfully installed uwsgi-2.0.19.1
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
root@svdjango:/#

全パッケージのアップグレード(pip3 list -o | tail -n +3 | awk ‘{ print }’ | xargs pip3 install –upgrade)

1個ずつ指定は面倒。
普段は一括でアップデートしたいなって思ったらワンライナー書いておられた。
作者さんありがとう。

pipで更新可能なパッケージを一括でアップデートする - Qiita
次のコマンドを使うと,pipでアップデートがあるパッケージの一覧を表示することができます.pip list -oこのコマンドの出力を使って,パイプでコマンドをつなげることで,一括アップデートのワ…
root@svdjango:/# pip3 list -o | tail -n +3 | awk '{ print $1 }' | xargs pip3 install --upgrade
Requirement already satisfied: asgiref in /usr/local/lib/python3.8/dist-packages (3.4.1)
Collecting asgiref
  Downloading asgiref-3.5.0-py3-none-any.whl (22 kB)
Requirement already satisfied: django-widget-tweaks in /usr/local/lib/python3.8/dist-packages (1.4.11)
Collecting django-widget-tweaks
  Downloading django_widget_tweaks-1.4.12-py3-none-any.whl (8.9 kB)
Requirement already satisfied: fonttools in /usr/local/lib/python3.8/dist-packages (4.28.5)
Collecting fonttools
  Downloading fonttools-4.29.0-py3-none-any.whl (895 kB)
     |████████████████████████████████| 895 kB 7.7 MB/s            
Requirement already satisfied: importlib-metadata in /usr/local/lib/python3.8/dist-packages (4.10.0)
Collecting importlib-metadata
  Downloading importlib_metadata-4.10.1-py3-none-any.whl (17 kB)
Requirement already satisfied: numpy in /usr/local/lib/python3.8/dist-packages (1.22.0)
Collecting numpy
  Downloading numpy-1.22.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (16.8 MB)
     |████████████████████████████████| 16.8 MB 5.0 MB/s            
Requirement already satisfied: pyparsing in /usr/local/lib/python3.8/dist-packages (3.0.6)
Collecting pyparsing
  Downloading pyparsing-3.0.7-py3-none-any.whl (98 kB)
     |████████████████████████████████| 98 kB 12.7 MB/s            
Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.8/dist-packages (from importlib-metadata) (3.7.0)
Installing collected packages: pyparsing, numpy, importlib-metadata, fonttools, django-widget-tweaks, asgiref
  Attempting uninstall: pyparsing
    Found existing installation: pyparsing 3.0.6
    Uninstalling pyparsing-3.0.6:
      Successfully uninstalled pyparsing-3.0.6
  Attempting uninstall: numpy
    Found existing installation: numpy 1.22.0
    Uninstalling numpy-1.22.0:
      Successfully uninstalled numpy-1.22.0
  Attempting uninstall: importlib-metadata
    Found existing installation: importlib-metadata 4.10.0
    Uninstalling importlib-metadata-4.10.0:
      Successfully uninstalled importlib-metadata-4.10.0
  Attempting uninstall: fonttools
    Found existing installation: fonttools 4.28.5
    Uninstalling fonttools-4.28.5:
      Successfully uninstalled fonttools-4.28.5
  Attempting uninstall: django-widget-tweaks
    Found existing installation: django-widget-tweaks 1.4.11
    Uninstalling django-widget-tweaks-1.4.11:
      Successfully uninstalled django-widget-tweaks-1.4.11
  Attempting uninstall: asgiref
    Found existing installation: asgiref 3.4.1
    Uninstalling asgiref-3.4.1:
      Successfully uninstalled asgiref-3.4.1
Successfully installed asgiref-3.5.0 django-widget-tweaks-1.4.12 fonttools-4.29.0 importlib-metadata-4.10.1 numpy-1.22.1 pyparsing-3.0.7
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
root@svdjango:/#

パッケージの依存関係チェック(pip check)

root@svdjango:/# pip3 check
No broken requirements found.
root@svdjango:/#

パッケージの書き出し(pip freeze)

pip install -r で使えるrequirements.txtを書き出す。

root@svdjango:/# pip3 freeze
asgiref==3.4.1
Django==3.1.5
django-markdownx==3.0.1
Markdown==3.3.3
Pillow==7.0.0
PyMySQL==1.0.2
pytz==2021.1
sqlparse==0.4.1
supervisor==4.1.0
uWSGI==2.0.19.1
root@svdjango:/#

プロジェクトの作成

/code/appフォルダはdockerコンテナの永続化領域にしておきsambaで共有指定し、ソース書くときはそこをvscodeで開いて編集するようにしてる。

完全に最初から作るときは、/code/appの中フォルダは退避・削除しておいて実行する。

自動作成されたフォルダやコードはコンテナ内のrootで作られるので、必要ならchown -Rしてvscodeで編集できるようにしておく。

# django-admin.py startproject website /code/app/
# cd /code/app
# /usr/bin/python3 manage.py collectstatic --no-input;/usr/bin/python3 manage.py migrate

アプリケーションの作成

このへんまではdockerでインフラ的な作業やってみたけど、そろそろ最初のロケット画面のリンクにあったdjangoのチュートリアル読みながらやってみる。
ああ、日本語助かる。

Django
The web framework for perfectionists with deadlines.
Djangoとは
Djangoとは何なのかについて知っていきましょう。

そもそものpythonのバージョン確認。このバージョンに依存してdjangoのバージョン範囲も決まるらしい。

root@svdjango:/code/app# python3 -m django --version
3.2.7
root@svdjango:/code/app#

プロジェクト作成との差がまだイマイチわかってない。
チュートリアルには、

プロジェクトとアプリの違いは何でしょうか? 
アプリとは、ウェブログシステム、公的記録のデータベース、
小規模な投票アプリなど、何かを行う Web アプリケーションです。
プロジェクトは、特定のウェブサイトの構成とアプリのコレクションです。
プロジェクトには複数のアプリを含めることができます。 
アプリは複数のプロジェクトに存在できます。

わかったような、わからんような。
まだ実感が湧いてないけど、気にせず先に進む。アプリケーション作ろう。
このアプリケーションを、基礎確認専用に作っていく。

root@svdjango:/# cd /code/app
root@svdjango:/code/app# /usr/bin/python3 manage.py startapp gvisDjango3
root@svdjango:/code/app# exit
$ sudo su -
# cd /docker/nariDockerDat/sv_django-uwsgi-nginx/app
# chown -R nari:nari gvisDjango3/

Hello world

んで、チュートリアル見ながらhello worldいってみるか。

ここまででできた/code/app内のフォルダ構成。

/code/app
|--gvisDjango3
|  |--__init__.py
|  |--__pycache__
|  |--admin.py
|  |--apps.py
|  |--migrations
|  |--models.py
|  |--tests.py
|  |--urls.py ★
|  |--views.py ★
|--manage.py
|--requirements.txt
|--website
|  |--__init__.py
|  |--__pycache__
|  |--asgi.py
|  |--settings.py
|  |--static
|  |  |--admin
|  |--urls.py ★
|  |--wsgi.py

★を編集していく。
まずは、gvisDjango3のurls.pyの編集。

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

次がgvisDjango3のviews.pyの編集。ここでページ表示の文字列書いとく。

from django.shortcuts import render

# Create your views here.
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the gvisDjango3 index.")

最後にルート(website)のurls.pyの編集。これで表示される。
ロケットの初期ページ表示できなくなるけど、最後尾のpathの記述でトップページを奪い取って表示させられる(今でもロケットのページってどうやって表示できてんのかよくわからん)。

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('gvisDjango3.urls')), ## ここ追記
]

表示させたらこんな感じで味気ないけど、templatesを用意してパラメータも渡せるかな。

django-HelloWorld

テンプレートを使ってパラメータも渡してみる

templatesフォルダを追加してhtmlを足した/code/app内のフォルダ構成。

アプリケーションフォルダにtemplatesフォルダを作るようなことが書いてあったけど、なぜかうまくブラウザで表示できず。

アプリケーションごとにtemplatesじゃなくて、同列のフォルダで管理したかったのもあり、こんな感じで作った。

/code/app
|--gvisDjango3
|  |--__init__.py
|  |--__pycache__
|  |--admin.py
|  |--apps.py
|  |--migrations
|  |--models.py
|  |--tests.py
|  |--urls.py 
|  |--views.py ★
|--manage.py
|--requirements.txt
|--templates
|  |--gvisDjango3
|  |  |--gvisDjango3Top.html ★
|--website
|  |--__init__.py
|  |--__pycache__
|  |--asgi.py
|  |--settings.py ★
|  |--static
|  |  |--admin
|  |--urls.py
|  |--wsgi.py

★を編集していく。

gvisDjango3のviews.pyの編集。ここでページ表示の文字列書いとく。

from django.shortcuts import render

# Create your views here.
from django.http import HttpResponse

def index(request):
    # return HttpResponse("Hello, world. You're at the gvisDjango3 index.")
    context = { 
        'message' : '初メッセージ',
        'content' : 'Djangoバンザイ',
    }
    return render(request, 'gvisDjango3/gvisDjango3Top.html',context)

setting.pyの編集。これでtemplatesフォルダを探しにいってくれる。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(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',
            ],
        },
    },
]

実際のテンプレートファイルとして、gvisDjango3Top.htmlを用意。

<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <p>Hello, world. gvisDjango3のトップ画面ですねん。パラメータ受け取ってみましてん。</p>
    <ul>
      <li>{{ message }}</li>
      <li>{{ content }}</li>
    </ul>
  </body>
</html>

templatesを用意したらパラメータ渡ってくれてますなぁ。

django-HelloWorld

バージョン情報とか表示できるか

phpやったらphpinfoみたいなのがある。
dockerコンテナ起動させたとき、基礎稼働確認をするページがほしい。
phpの場合はphpinfoだけじゃなく、既存DB読み込んで内容表示させるページを持ってるので、同じようなものをdjangoでも作りたい。

djangoでもバージョンやら基礎情報を表示できるんかなぁ。
ということでviews.pyのimportとcontext内容に追記してみた。

from django.shortcuts import render
import django,sys,platform

# Create your views here.
from django.http import HttpResponse #追記

def index(request):
    # return HttpResponse("Hello, world. You're at the gvisDjango3 index.")
    context = { 
        'platform_uname': platform.uname, #追記
        'sys_version': sys.version, #追記
        'django_version': django.VERSION, #追記
        'message' : '初メッセージ',
        'content' : 'Djangoバンザイ',
    }
    return render(request, 'gvisDjango3/gvisDjango3Top.html',context)

取得している情報の参考URLは以下。

platform --- 実行中プラットフォームの固有情報を参照する — Python 3.8.17 ドキュメント

gvisDjango3Top.htmlにもパラメータ受け取り箇所を追記してみた。

<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <p>platform_uname</p>
    <ul>
      <li>{{ platform_uname }}</li>
    </ul>
    <p>Sysバージョン(Python インタプリタのバージョン番号の他、ビルド番号や使用コンパイラなど)</p>
    <ul>
      <li>{{ sys_version }}</li>
    </ul>
    <p>Djangoのバージョン</p>
    <ul>
      <li>{{ django_version }}</li>
    </ul>
    <p>Hello, world. gvisDjango3のトップ画面ですねん。パラメータ受け取ってみましてん。</p>
    <ul>
      <li>{{ message }}</li>
      <li>{{ content }}</li>
    </ul>
    <a href="https://docs.python.org/ja/3.8/library/platform.html#platform.python_version_tuple" target="_blank">
      パラメータ意味 - 実行中プラットフォームの固有情報を参照</a>
  </body>
</html>

システムのバージョン情報表示できますなぁ。
基礎稼働確認に使える。

dockerコンテナのシステム情報や、pythonとdjangoのバージョン表示できるようになった。

django-HelloWorld

データベースとの接続について

モデルを追加して、データベースとつながるかやってみる。
https://docs.djangoproject.com/ja/3.2/intro/tutorial02/

普段の業務データが入ったDBMSはmariadb。
この中には自分の業務在庫データやら活動記録が入っているし、証跡みたいなものはjpegやpdfになってblob列に入っている。

mariadbはもちろんdjangoでも扱えるらしい。

Django
The web framework for perfectionists with deadlines.

他にもPostgreSQL、MySQL、Oracle、が書いてある。
SQLserverもつながるらしいけど、まぁ使うことない。

djangoでデータベースを扱うとき、テーブルには単一列の主キーが設定されたものしか扱えないらしい。

Django
The web framework for perfectionists with deadlines.

そのため、既存のテーブルには「id」という名前でオートナンバー型の列をつけて主キーを張っておいた。けっこう面倒だった。

オートナンバー型って、大昔にMS-access使い始めたときに初めて使ったっけ。今更って感じ。

普段の業務データが入ったDBMSはdockerで動かしているので、開発環境にいったん永続化データを持ってきておき、A5sqlで列追加をした後で本番に反映。
また別のページでメモ書いとかないと・・・。

MariaDBとの接続連携について

settings.pyに追記

最初にテスト用のMySQLコンテナを作ってあるから、テスト用DBはもうある。
djangoに業務DB接続を追加して複数DB扱えるか試す。

Django
The web framework for perfectionists with deadlines.

settings.pyに別DB(gvis-mariadb)があることを書き、実際に接続してみる。

DATABASES = {
    # テスト用データベース
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'djangodb',
        'USER': 'root',
        'PASSWORD': 'booboo',
        'HOST': 'nafslinux.intra.gavann-it.com',
        'PORT': '23306',
        'OPTIONS': {
                'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
                },
    },

    # 業務用データベース
    'gvis-mariadb': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'gvisdb',
        'USER': 'nari',
        'PASSWORD': 'password',
        'HOST': 'nafslinux.intra.gavann-it.com',
        'PORT': '3306',
        'OPTIONS': {
                'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
                },
    }
}

modelsを自動生成して連携させる

初期データベースと、業務用データベースは作ってあるので、既存DBに対して連携させる必要がある。

その方法を探してみた。書いてくれた方ありがとう。

[Django]既存のデータベースを利用する方法 - Qiita
この記事についてDjangoから既存のデータベースを利用する方法のメモです。既存システムの管理ツールをDjangoで開発するという状況を想定しています。参考:公式 レガシーなデータベースと D…
既存データベースをDjangoで利用しようとしたら簡単すぎて拍子抜けた話 - Qiita
#目的先日の記事を読んでくれた知人から「じゃあ既に運用しているDBがあったとして、後からDjangoをくっつけてくることはできるのか?」なんていう勝手なリクエストがあったので、こちらも検証して…

既存DBとの連携調整を行う方法があるらしい。

Django
The web framework for perfectionists with deadlines.
Django
The web framework for perfectionists with deadlines.

自分でもやってみる。inspectdbっていうのを使ってmodels.pyを出力させてる。

$ docker exec -it docker_sv_django_1 bash
root@svdjango:/# cd /code/app
root@svdjango:/code/app# /usr/bin/python3 manage.py inspectdb >> /code/app/gvisDjango3/models.py

初期データベースとして作成したmysqlのテーブル10個分のクラスが追加されてる。
ただし、業務データベースはmodelsに追記されてない。

inspectdbはsettings.pyに書いたデータベース名を指定しないとき、defaultという名前のものだけを処理するため、a5sqlのテーブル一覧を左に並べて差分を見るとこうなってた。

django-DBMS

settings.pyに追記したもう1つのデータベースを指定して追加してみる。

root@svdjango:/code/app# /usr/bin/python3 manage.py inspectdb --database gvismariadb >> /code/app/gvisDjango3/models.py

おお、ちゃんとmodels.pyの続きに追記されてる。これもa5sqlのテーブル一覧と並べてチェックしたら全部あった。

django-DBMS

inspectdbする都度以下の記述が増えるので削除しておく。

# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
#   * Rearrange models' order
#   * Make sure each model has one field with primary_key=True
#   * Make sure each ForeignKey and OneToOneField has `on_delete` set to the desired behavior
#   * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.
from django.db import models

モデルができたので有効にする

DB追加したので、いったんmigrateしておく。ここまでで管理テーブルは既存のmysqlにのみ存在し、追加したmariadbの業務DBは何も変わってなかった。管理テーブルはdjangoからみたdefaultのデータベースにあるから、そっちだけが変更されるみたい。

チュートリアルのDB利用を読み続ける。

Django
The web framework for perfectionists with deadlines.

settings.pyを編集する。

/code/app
|--gvisDjango3
|  |--__init__.py
|  |--__pycache__
|  |--admin.py
|  |--apps.py
|  |--migrations
|  |--models.py
|  |--tests.py
|  |--urls.py 
|  |--views.py
|--manage.py
|--requirements.txt
|--templates
|  |--gvisDjango3
|  |  |--gvisDjango3Top.html
|--website
|  |--__init__.py
|  |--__pycache__
|  |--asgi.py
|  |--settings.py ★
|  |--static
|  |  |--admin
|  |--urls.py
|  |--wsgi.py

gvisDjango3っていうアプリケーションのフォルダにapps.pyがあるからその中の定義を見ると何て書けばいいかわかる。

class定義に「Gvisdjango3Config」って書いてある。

from django.apps import AppConfig


class Gvisdjango3Config(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'gvisDjango3'

追記してみる。

INSTALLED_APPS = [
    'gvisDjango3.apps.Gvisdjango3Config', ### 追記
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

モデルが追加されたことをdjangoに伝えるためにmakemigrations実行する。

root@svdjango:/# cd /code/app
root@svdjango:/code/app# /usr/bin/python3 manage.py makemigrations gvisDjango3
Migrations for 'gvisDjango3':
  gvisDjango3/migrations/0001_initial.py
    - Create model AuthGroup
    - Create model AuthGroupPermissions
    - Create model AuthPermission
    - Create model AuthUser
    - Create model AuthUserGroups
    - Create model AuthUserUserPermissions
    - Create model DjangoAdminLog
    - Create model DjangoContentType
    - Create model DjangoMigrations
    - Create model DjangoSession
    - Create model GvisHwcheckresult
    - Create model GvisKeihi
    - Create model GvisLog
    - Create model GvisLogon
    - Create model GvisMstCustomer
    - Create model GvisMstKamoku
    - Create model GvisMstKeihishubetsu
    - Create model GvisMstKshisanshokyaku
    - Create model GvisMstKshisanshokyakurit
    - Create model GvisMstNohin
    - Create model GvisTransaction
    - Create model GvisWork
    - Create model GvisZaiko
root@svdjango:/code/app#
root@svdjango:/code/app# /usr/bin/python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, gvisDjango3, sessions
Running migrations:
  Applying gvisDjango3.0001_initial... OK
root@svdjango:/code/app# 
root@svdjango:/code/app# /usr/bin/python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, gvisDjango3, sessions
Running migrations:
  No migrations to apply.
root@svdjango:/code/app#

ここまでで、アプリケーションのmigrationsフォルダに「0001_initial.py」ってファイルが作られてる。初期化に使われる雰囲気の怖そうなファイル。番号がついてるってことは、テーブル定義を変更したらインクリメントされて作るってことか。

# Generated by Django 3.2.7 on 2021-09-04 21:28

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='AuthGroup',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=150, unique=True)),
            ],
            options={
                'db_table': 'auth_group',
                'managed': False,
            },
        ),
        :(中略)

追加されたフィールドを見てみる

チュートリアル見ると「django.db.models.Modelのサブクラスです」ってサラっと書いてある。テーブルをクラス定義して扱いますってことか。(クラスが苦手)

  • models.pyには各テーブルの1つ目のフィールドにある「id」はクラス定義に存在しない。

a5sqlで見えるcreate tableのsqlには、

CREATE TABLE `GVIS_work` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `workPeriod` datetime DEFAULT NULL COMMENT '業務期間-開始日',
 :(中略)
CREATE TABLE `GVIS_zaiko` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `SerialShubetsu` varchar(4) NOT NULL COMMENT 'シリアル種別',
 :(中略)

models.pyは1つ目の列であるidがなくて、

class GvisWork(models.Model):
    workperiod = models.DateTimeField(db_column='workPeriod', blank=True, null=True)  # Field name made lowercase.
 :(中略)
class GvisZaiko(models.Model):
    serialshubetsu = models.CharField(db_column='SerialShubetsu', max_length=4)  # Field name made lowercase.
 :(中略)

13個しか業務テーブルないので目視確認全部やってみたけど、id以外は全部もれなく列を拾ってくれてた。

makemigrationsしたときにできてた「0001_initial.py」ってファイルにはidの定義があった。これでいいのかはまだわからない。

  • 型はある程度引き継がれる。

integerとdecimalは区別されているけど、blobの列はTextFieldになってる。まぁ、バイナリはある意味文字列やしね。まずはよしとしとこう。

  • 定義は全部小文字に変換される。

テーブル上は大文字小文字を自分の好きなように混ぜてるけど統一されるみたい。
読みにくい。

  • インデックスは無視か

テーブルにはインデックスをつけてあるけど、djangoのクラス定義にはまったく反映されない。

データを参照するmodels.pyに追記

初期テーブルはdjangoが勝手に作る。
でも接続したいのは、既存テーブル。

既存テーブルへの接続設定を作っておき、モデルの中にクラス定義もできた。
ただ、それだけではビューを介してデータの表示はできないらしい。
(なんやねん、面倒やなぁ)

クラス定義には追記が必要で、テーブルに入っている項目を返すようにしなきゃいけないらしい。

そこで、クラスに追記してみる。
1個ずつ入力していくの結構たいへんやから今はテーブル1つだけやっておくか。

例えばこんな具合。

django-DBMS

コードとしては、「return」の中にテーブルの列名を入れておく。
列がintegerだったら文字にキャストしなきゃいけないらしいからstrで囲んでおく。

datetimeの列があと一歩で表示できるんやけど、また次のときに追記。
キャストのやり方が悪いのか「’str’ object has no attribute ‘tzinfo’」って出る。

def __str__(self):
    return str(self.keihitaisho)

※あとでわかったのは、日付にnullや’0000-00-00’が入っているとこのエラーが出ることがわかった。データ取ってくるときに条件絞ることで回避できた。

データを参照するテンプレートを変更

テンプレートは表示させるひな形なので、他に表示させたい内容も含めて一覧にしてみる。
システム変数めいたものやバージョン情報を表示させ、試しに既存テーブルの内容一覧を表示させてみる。

既存テーブルの一覧表示はなかなか時間かかった。動的にページを表示させるから、「for item in data」で「dataを1レコードずつitemに受け取る」みたいな感じか。チュートリアルだけじゃわからなかったのでいくつかググった。

データベースの一覧というか、スキーマの一覧の表示させ方がまだ見つけられてない。djangoの構造上、無理なのかもしれないけどmariadbへ「show databases」発行できるんかな。

<html>
  <head>
    <meta charset="utf-8">
    <title>GVIS イントラDjango</title>
    <img src="http://nafslinux.intra.gavann-it.com:20080/image/gavann_logo_blue.png" />
    <p>GavannITサービス イントラDjango</p>
  </head>
  <body>
    <table border=4 align=left>
      <tr bgcolor="#cccccc">
      <th>項目</th>
      <th>値</th>
      </tr>
      <tr align=left>
        <td>platform_uname</td>
        <td>{{ platform_uname }}</td>
      </tr>
      <tr align=left>
        <td>Sysバージョン(Python インタプリタのバージョン番号の他、ビルド番号や使用コンパイラなど)</td>
        <td>{{ sys_version }}</td>
      </tr>
      <tr align=left>
        <td>Djangoのバージョン</td>
        <td>{{ django_version }}</td>
      </tr>
    </table>
    <br>

    <a href="https://docs.python.org/ja/3.8/library/platform.html#platform.python_version_tuple" target="_blank">
      パラメータ意味 - 実行中プラットフォームの固有情報を参照</a>

    <p> --- データベース一覧 --- </p>
    <p align=left> --- MySQL 参照テスト ---</p>

    <a href="https://docs.djangoproject.com/ja/3.2/intro/tutorial01/" target="_blank">
      参考URL1</a>
    <br>

    <a href="https://docs.djangoproject.com/ja/3.2/intro/tutorial02/" target="_blank">
      参考URL2</a>
    <br>

    <a href="https://docs.djangoproject.com/ja/3.2/intro/tutorial03/" target="_blank">
      参考URL3</a>
    <br>

    <a href="https://qiita.com/ekzemplaro/items/9a9986da55204de62f94" target="_blank">
      参考URL4</a>
    <br>

    <a href="https://codor.co.jp/django/comment" target="_blank">
      参考URL5</a>
    <br>

    <p> django内表示 : data = GvisMstKamoku.objects.db_manager("gvismariadb").all()</p>
    <table border=4 align=center>
      <tr>
      <th>科目No</th>
      <th>科目名</th>
      <th>科目説明</th>
      <th>表示order</th>
      <th>keihitaisho</th>
      </tr>
      {% for item in data %}  {# dataを受け取ってitemに入ったレコードを表示させる #}
      <tr>
      <td>{{item.kamokuno}}</td>
      <td>{{item.kamokuname}}</td>
      <td>{{item.kamokusetsumei}}</td>
      <td>{{item.hyojiorder}}</td>
      <td>{{item.keihitaisho}}</td>
      </tr>
      {% endfor %}  ## お決まり
      </table>
    </body>
</html>

データを参照するviews.pyを変更

最初はhttpresponseだけでページ表示を戻してたけど、データをあれこれ取れる方法とパラメータで渡す方法がわかった。

既存データベースの参照は「db_manager」を使って指定する。これでそのオブジェクトを参照してくれるらしい。

「all()」って指定を入れるとデータ取ってくる。たぶんorder byみたいな指定もできるんやろな。

案外viewの指定は簡単にできた。

from django.shortcuts import render
import django,sys,platform          ## システム情報を表示させるため

# Create your views here.
from django.http import HttpResponse

## from datetime import date                     ## テーブルの日付フィールドを表示させるため
## from django.utils import timezone   ## テーブルの日付フィールドを表示させるため
from .models import GvisMstKamoku       ## テーブル内容を表示させるため

def index(request):
    # return HttpResponse("Hello, world. You're at the gvisDjango3 index.")

    data = GvisMstKamoku.objects.db_manager("gvismariadb").all()

    context = { 
        'platform_uname': platform.uname,
        'sys_version': sys.version,
        'django_version': django.VERSION,
        'data': data,
    }
    return render(request, 'gvisDjango3/gvisDjango3Top.html',context)

実際に参照

models.pyとviews.pyとテンプレートを書き換えたら、いったんdockerコンテナの再起動。
runserverをやりなおすのと同じかな。

docker-compose restart sv_django

ついでにマイグレーションもやっておく。

cd /code/app
/usr/bin/python3 manage.py makemigrations gvisDjango3
/usr/bin/python3 manage.py migrate
/usr/bin/python3 manage.py migrate --database=gvismariadb

チュートリアルにコマンドラインから扱うサンプルみたいなのがあった。
最初に複数DBの参照ができてないとき、いくつか試した。ここでdb_managerの指定を使うことを見つけてさっきのviews.pyは作った。

/usr/bin/python3 manage.py shell
from gvisDjango3.models import GvisMstKamoku
GvisMstKamoku.objects.db_manager("gvismariadb").all()
  :(中略)

exit()

表示できるようになった内容がコレ。
ああ、長かった。

django-DBMS

SQLの直接発行

selectとかupdateはすぐにできそうやけど、まだできてないのは、mariadbで「show databases」を発行した結果を取りたい。

素のSQLを発行する方法を調べてやってみた。

まずはインポートでconnectionを使うらしい。
DBを複数使ってるので、connectionsのほうを使ってcursorで取り込むみたいな感じか。

views.pyの最初のほうに追記。

from django.db import connections               ## モデルを使わずSQL発行のため

実際に使ってみる。

connectionsに利用指定するのは、settings.pyに定義した既存DBの定義名。
ここではgvismariadbって名前のこと。

    # 業務用データベース
    'gvismariadb': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'nariDB_1st',  # 実際に作ってあるDB名を設定する
      :(中略)

ここでconnectionsに既存DB名を指定したら、カーソルを使う。
executeに実行したいSQLを書いて結果を戻させる。

## モデルを使わずにsql発行
con = connections['gvismariadb']
cursor = con.cursor()

cursor.execute("show databases")
ichiran = cursor.fetchall()

cursor.execute("select count(*) from GVIS_zaiko")
kensuu = cursor.fetchall()

ichiranとkensuuをパラメータでテンプレートに渡すように追記する。

context = { 
    'platform_uname': platform.uname,
    'sys_version': sys.version,
    'django_version': django.VERSION,
    'data': data,
    'dataZ': dataZ, 
    'dataGoukei': dataGoukei,
    'ichiran': ichiran,
    'kensuu': kensuu,
}

テンプレート側にも、受け取ったパラメータを表示するように設定入れると表示されるようになる。

<p> --- データベース一覧 --- </p>
<p>{{ ichiran }}</p>
<p>総件数={{ kensuu }}件</p>

表示はされるようになったけど、「総件数=((113,),)件」とか不要なカッコとカンマがついてるー。

どないして外したらええねん・・・。
たぶんリストみたいな戻り値を何かに変換するんやろけど。

タイトルとURLをコピーしました