見出し画像

Djangoでデータベースシステムを作るチュートリアル

Djangoを使ってデータベースシステムの作り方を紹介します。
データベースシステムといっても、難しいアルゴリズムを実装するようなことはせず単純なデータベースを作ります。

対象読者はPythonとMVCなどのWebアーキテクチャーを勉強したことのある人を想定しています。
Djangoは初心者の方でも問題ありません。

題材は環境省が公開しているレッドリストを使って作成します。

データの作成にはCSVインポート機能を実装するので、大量のデータを手動で作成するということはありません。
ご安心ください。
ちなみにインポート機能にはdjango-import-exportというプラグインを使用します。

これを機にDjangoの知識を身に付けつつ、動物に優しい心を持っていただければと思います。

バージョン

バージョンは下記の通りで進めていきますが、適宜バージョンを変更いただいても構いません。

・Python 3.9.2
・Django 3.2.4

Django環境立ち上げ

下記のコマンドを実行してください。

python -m venv env
source env/bin/activate
pip install django
django-admin startproject project .
django-admin startapp red_list
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver

Python -m venv envでPythonの仮想環境を立ち上げられます。
ここでは詳細を割愛しますが、pyenvというPythonのバージョン管理ツールを使うことで複数のバージョンを同じマシンで使うことができます。

source env/bin/activateはPythonの仮想環境を立ち上げるコマンドです。
Windowsはenv/Scripts/activateが起動コマンドとなっています

django-admin startproject project . でDjango環境全体の設定を生成します。

django-admin startappはDjangoのアプリを作るコマンドです。
Djangoは機能ごとにstartappで最小単位のアプリを作成します。アプリはprojectディレクトリと同じ階層に作られます。
この構造は機能同士を疎結合にするので、プロジェクトを進める上で影響範囲を小さくするという効果があります。
今回はレッドリストという一括りでアプリを作成します。
一つのアプリをどれぐらいの規模にするかは自由ですので、その時々に応じて設計は柔軟に変えてください。

最初のpython manage.py migrateはDjangoの初期データベースを作成するのに実行します。
Djangoは嬉しいことにあらかじめ管理画面を提供してくれているので、最初のマイグレート実行でUserテーブルの作成などを行なってくれます。
新しく追加したいテーブルなどは、モデルで定義してマイグレーションファイルの生成コマンドを実行し、マイグレートコマンドを実行することで追加可能です。

python manage.py createsuperuserでスーパーユーザー🦸‍♂️を追加できます。
メールアドレスとユーザー名が求められるので、適宜入力してください。

python manage.py runserverでDjango環境が立ち上がります。
ブラウザでhttp://127.0.0.1:8000/にアクセスすると、このような画面が表示されます。

スクリーンショット 2021-06-14 16.12.05

追加したアプリはDjangoの設定ファイルであるsettings.pyにも追加します。
INSTALLED_APPSにred_listアプリを追加してください。

settings.py

INSTALLED_APPS = [
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'red_list' # red_listを追加
]

ちなみに、red_listというアプリがどこで定義されているかというと、red_list/apps.pyにアプリ名が定義されています。

from django.apps import AppConfig


class RedListConfig(AppConfig):
   default_auto_field = 'django.db.models.BigAutoField'
   name = 'red_list'

name = 'red_list'でアプリ名を定義しています。

モデルの実装

次にモデルでテーブルを定義します。
red_listディレクトリにあるmodels.pyファイルを開き、下記を追記してください。

from django.db import models

class Category(models.Model):

 name = models.CharField(max_length=32, blank=False, null=False)

 def __str__(self):
     return self.name


class Classification(models.Model):

 name = models.CharField(max_length=32, blank=False, null=False)

 def __str__(self):
     return self.name

class Animal(models.Model):

 japanese_name = models.CharField(max_length=256, blank=False, null=False)
 scientific_name = models.CharField(max_length=256, blank=False, null=True)
 category = models.ForeignKey(Category, on_delete=models.DO_NOTHING)
 classification = models.ForeignKey(Classification, on_delete=models.DO_NOTHING)

 def __str__(self):
     return self.japanese_name

追加するテーブルはカテゴリー(Category)、分類(Classification)、動物(Animal)の3つです。
Animalテーブルのjapanese_nameは和名、scientific_nameは学名です。

models.CharFieldでテーブルの型を文字列にしています。
max=lengthは文字数の最大値です。
blankはデータベースへの入力時に空を許容するかの判定です。Falseにすると空に加えてスペースのみなどの場合も弾かれます。
nullは保存するデータにnullを許容するかの判定です。
on_delete=models.DO_NOTHINGは動物が削除されたときに、外部テーブルに紐づくデータをどうするか設定することができます。
models.DO_NOTHINGと指定することで、動物が削除されてもそれまで紐づいていた外部テーブルのデータはそのままになります。
models.CASCADEと指定すると動物が削除されたときに紐づくテーブルのデータも削除されます。

それではマイグレーションファイルを生成し、マイグレートを実行します。
下記を実行してください。

python manage.py makemigrations red_list
python manage.py migrate

これで必要なテーブルが揃いました。

管理画面の設定

http://127.0.0.1:8000/admin/にアクセスすると管理画面のログイン画面が表示されます。

スクリーンショット 2021-06-14 17.23.50

先ほど作成したスーパーユーザーでログインしてください。
ログイン後、こちらのような画面が表示されます。

スクリーンショット 2021-06-14 17.36.35

GroupsとUsersテーブルがあると思いますが、先ほど追加したAnimalsテーブルやCategoriesテーブルがありません。
自分で追加したテーブルは、別途、管理画面用の設定ファイルで設定する必要があります。

red_listディレクトリにadmin.pyというファイルがあります。
このファイル内で、下記を追加してください。

from django.contrib import admin

from red_list.models import Category
admin.site.register(Category)

from red_list.models import Classification
admin.site.register(Classification)

from red_list.models import Animal
admin.site.register(Animal)

モデルからテーブルを読み込み、admin.site.registerでテーブルを登録しています。

設定後管理画面をリロードすると、red_listアプリに登録したテーブルが表示されているのが分かります。

スクリーンショット 2021-06-14 18.07.40

データの登録

試しにレッドリストを環境省のサイトからダウンロードし、Djangoアプリに登録します。
こちらのサイトからインストールしてください。

スクリーンショット 2021-06-14 18.11.12

「レッドリスト2020について(令和2年)」というのがあるので、哺乳類のリストをダウンロードしてください。

ファイルの中身はこのようになっています。

スクリーンショット 2021-06-14 18.12.23

まずは、カテゴリーを入れてみましょう。
RED_LISTのCategorysを選択し、ADD CATEGORYを押下してください。

スクリーンショット 2021-06-14 18.16.53

カテゴリーの登録フォームが表示されるので、まずは「絶滅(EX)」を入力してみましょう。

スクリーンショット 2021-06-14 18.19.38

もしエラーが表示されるようなことがある場合は、models.pyを見直してみましょう。

続いて他のカテゴリーや分類も登録してみてください。

動物の登録は数がそれなりにあり大変だと思うので、CSVインポート機能を管理画面に実装します。
実装にはdjango-import-exportというプラグインを使います。

CSVのインポート機能実装

まずはプラグインをインストールします。

pip install django-import-export

settings.pyのINSTALLED_APPSに下記を追加してください。

INSTALLED_APPS = [
   ...
   'import_export',
   ...
]

管理画面にインポート機能を実装していくので、admin.pyに下記を追加します。

from django.contrib import admin
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field
from import_export.widgets import ForeignKeyWidget

from red_list.models import Category
admin.site.register(Category)

from red_list.models import Classification
admin.site.register(Classification)

from red_list.models import Animal

class AnimalResource(resources.ModelResource):

 category = Field(attribute='category', column_name='category', widget=ForeignKeyWidget(Category, 'name'))
 classification = Field(attribute='classification', column_name='classification', widget=ForeignKeyWidget(Classification, 'name'))

 class Meta:
   model = Animal
   fields = ('id', 'japanese_name', 'scientific_name', 'category', 'classification', )
   import_id_fields = ('id', )

class AnimalAdmin(ImportExportModelAdmin):
  list_display = ('japanese_name', 'scientific_name','category', 'classification', )
  resource_class = AnimalResource

admin.site.register(Animal, AnimalAdmin)

categoryclassificationは外部のテーブルのidAnimalテーブルとリレーションを持っているので、そのままだと外部テーブルにあるデータのidをCSVで指定しなければなりません。
idに置き換える作業が手間になるので、名称からidを探しにいき登録できるようにします。

category = Field(attribute='category', column_name='category', widget=ForeignKeyWidget(Category, 'name'))
classification = Field(attribute='classification', column_name='classification', widget=ForeignKeyWidget(Classification, 'name'))

ForeignKeyWidgetを使用することで、nameを検索しにいきidの取得ができます。

fieldsはインポート対象のカラムを指定します。

import_id_fieldsはidを明示的に指定できます。

list_displayは一覧に表示するカラムを指定します。
指定しない場合は、
def __str__(self):
で返している値のみが一覧に表示されます。

追加後はAnimalの一覧画面の右上にIMPORTとEXPORTの2つのボタンが表示されます。
今回はCSVのインポートを行いたいので、IMPORTをクリックしてください。
こちらのような画面が表示されるので、ここでファイルを選択してフォーマットにCSVを選択するのですが、一点注意点があります。

CSVファイルにはidのカラムだけを入れる必要があるので、CSVエディタなどで追加します。
また、カラム名はadmin.pyのfieldsで設定したカラム名と同じにする必要があります。

特に使い慣れているCSVエディタがなければ、こちらのエディタがおすすめです。

ブラウザ上で使用できるのと、UIもすっきりしているので非常に扱いやすいです。

カラムには
id,category,classification,japanese_name,scientific_name
を指定してください。
idのデータは、自動で追加されるので空のままで大丈夫です。

スクリーンショット 2021-06-14 23.15.26

CSVの準備ができたら、インポートを実行しましょう。
インポートが完了するとAnimalテーブルのリストはこのように表示されます。

スクリーンショット 2021-06-15 10.59.28

以上でチュートリアルは終了です。
おつかれさまでした!

最後までご覧いただきありがとうございます。
誤字脱字や間違いなどはご指摘いただけると幸いです。

Djangoの開発がなんとなく分かってきたら、今度はレンタルサーバーを使ってDjangoの環境を作ってみてください。



この記事が気に入ったらサポートをしてみませんか?