Python の Webアプリフレームワーク Django の始め方 〜導入からモデル定義まで〜

f:id:Naotsugu:20211124230837p:plain

はじめに

MDN で提供されているチュートリアルを元に、Django による Web アプリケーションの作成方法について見ていきます。

github.com

このチュートリアルは、「Locallibrary」という書籍を管理する簡単なウェブアプリケーションを構築するものとなっています。

元ネタのチュートリアルは無駄に長いため、ポイントを絞りつつ補足を加え、Django による Web アプリケーション構築の流れを簡素に説明していきます。


Django とは

Django(ジャンゴ)は、Python による汎用の Web アプリケーションフレームワークです。

もともとは、World Company のニュースサイトを作成・管理する目的で開発されたものを、再利用可能とする形で、2005年7月にオープンソース化されました。2008年9月にバージョン1.0がリリースされ、現在はバージョン3.2がリリースされています(バージョン4もベータ版として開発が進んでいます)。


公式サイトでは以下のように説明されています。

Django は、迅速な開発とクリーンで実用的なデザインを可能にするハイレベルな Python ウェブフレームワークです。 経験豊富な開発者によって作られたDjangoは、ウェブ開発の手間を大幅に省いてくれるので、あなたは車輪の再発明をすることなく、アプリの作成に集中することができます。


Python と Django

Django のバージョンと、それに対応する Python のバージョンは以下となっています。

Django バージョン Pythonバージョン
2.2 3.5 〜 3.9
3.0 3.6 〜 3.9
3.1 3.6 〜 3.9
3.2 3.6 〜 3.10

本記事では、Python 3.10 と Django 3.2 を使っていくこととします。


Python の導入手順

Python がインストールされていない場合は、それぞれの環境に応じた以下の手順を参考にして導入を完了させてください。

Windows の場合はこちら

blog1.mammb.com

Mac の場合はこちら

blog1.mammb.com

以降、環境は Mac での操作として記載します。 Windows の場合は、python コマンドではなく、py コマンドを利用するよう読み替えてください。


Python 仮想環境の作成と Django のインストール

先の導入手順では、Python 仮想環境について説明をしていますが、ここでも仮想環境を作成して Djengo をインストールしていきます。

ここでは、現在の最新版である Python 3.10 を使います。

$ python3 --version
Python 3.10.0


仮想環境を作成するために、任意のディレクトリに仮想環境用ディレクトリを作成します。

$ mkdir python
$ cd python

作成したディレクトリ中に、仮想環境を作成しましょう。

$ python3 -m venv .venv
$ source .venv/bin/activate

.venv という名前で仮想環境を作成して activate により仮想環境に入りました。 念のため pip をアップグレードしておきましょう。

(.venv) $ python -m pip install --upgrade pip

仮想環境で Django をインストールします。

(.venv) $ python -m pip install django==3.2.9

==3.2.9 で明示的にバージョンを指定しましたが、指定しない場合は最新の安定版がインストールされます。

なお、上記では仮想環境を示すため (.venv) $ のプロンプト表記としていますが、以降は単に $ で記載します。

Django がインストールできたので、続いて Django プロジェクトを作成していきましょう。


Django プロジェクトの作成

Django がインストールされれば、Django の管理コマンドである django-admin が利用可能になっています。

django-admin は Django の管理タスクを実行するユーティリティであり、このコマンドで Django プロジェクトの雛形を作成できます。

プロジェクトを作成するには、startproject コマンドでプロジェクト名を指定します。 ここでは、locallibrary という名前のプロジェクトを作成します。

$ django-admin startproject locallibrary
$ cd locallibrary

startproject により以下のようなプロジェクトが作成ます。

locallibrary
 ├── locallibrary
 │   ├── __init__.py
 │   ├── asgi.py
 │   ├── settings.py
 │   ├── urls.py
 │   └── wsgi.py
 └── manage.py

親の locallibrary ディレクトリは任意の名前に変更できます。これは単なるプロジェクト格納用のコンテナディレクトリであり、Django にとっては重要ではありません。

locallibrary/locallibrary ディレクトリが Webサイト用のディレクトリになり、各種の設定用コードが作成されていることがわかります。

manage.py はアプリケーションの作成や、データベースやwebサーバの操作行う管理用のスクリプトです。このスクリプトから、webサーバの起動であったり、データベースのマイグレーションであったりと、プロジェクトに関する操作を行っていくことになります。


少し脇道にそれますが、manage.py の中身は、以下のようなスクリプトになっています。

#!/usr/bin/env python

import os
import sys

def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'locallibrary.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError("Couldn't import Django. ...") from exc
    execute_from_command_line(sys.argv)

if __name__ == '__main__':
    main()

django.core.managementexecute_from_command_line() で引数を渡すことで、各種の管理タスクが処理されるようになっています。


locallibrary/locallibrary ディレクトリに作成された settings.py は、このWebサイトの設定を定義します。デフォルトで以下のような内容が定義されています。

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = 'django-insecure-ggz@(hu)dq&6)z&)r2!3=98%vwdjidi%w!1slwv0ql!foir+p0'
DEBUG = True

ALLOWED_HOSTS = []

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

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',
]

ROOT_URLCONF = 'locallibrary.urls'

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

WSGI_APPLICATION = 'locallibrary.wsgi.application'

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
STATIC_URL = '/static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

例えば TIME_ZONE でタイムゾーンを定義したり、STATIC_URL でスタティックなファイルの配置場所を定義したり、といった設定を変更することができます。

日本語環境では以下のような設定としておけば良いでしょう。

LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'

その他のファイルについては後ほど見ていくことにしましょう。


サーバの起動

django-admin コマンドでプロジェクトの作成が終われば、その時点でサーバを起動できます。 管理スクリプトで runserver により Django に組み込みの Web サーバを起動してみましょう。

$ python manage.py runserver

migration のエラーメッセージが出力されると思いますが、ここでは無視してかまいません。

runserver により、Django に組み込まれた Web サーバが起動します。http://localhost:8000/ にアクセスすれば以下の初期画面が表示されます。

f:id:Naotsugu:20211115210818p:plain

Web サーバの起動が確認できたら、Ctrl-C で一旦Webサーバを終了しておきましょう。

この Django 組み込みの Webサーバは開発用の Webサーバであり、実際の運用環境では Nginx や Apache などの Webサーバ準備し、WSGI(Web Server Gateway Interface) で Django に繋いで利用します。

以降の作業の中では、アプリケーションを構築しながら、runserver コマンドで Webサーバ起動して、動作を都度確認していきます。


アプリケーションの作成

ここまでで作成したプロジェクトの中に、Djangoアプリケーションを作成していきます。アプリケーションの作成は manage.py を使います。

manage.pystartappコマンドを実行し、catalog という名前のアプリケーションを作成します。このコマンドは、manage.py が存在する locallibrary ディレクトリで実行します。

$ python manage.py startapp catalog

startapp により以下アプリケーション用の以下のファイルが生成されます。

locallibrary
 ├── catalog
 │   ├── __init__.py
 │   ├── admin.py
 │   ├── apps.py
 │   ├── migrations
 │   │   └── __init__.py
 │   ├── models.py
 │   ├── tests.py
 │   └── views.py
 ├── locallibrary
 │   └── ...
 └── manage.py

catalog ディレクトリ内にアプリケーション用の雛形コードが生成されています。アプリケーションの構築には、主にここで作成された雛形コードを編集することで進めていくことになります。


簡単な View の作成

最初の一歩として、簡単なメッセージを返すビューを作成してみましょう。 これには、ビューの作成とURLマッピング定義の2つの作業が必要になります。

はじめに、catalog/views.py を以下のように編集してビューを定義します。

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world.")

続いてURLのマッピングを定義します。新しく catalog/urls.py ファイルを作成して以下のように編集します。

from django.urls import path
from . import views

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

これが、catalog アプリケーション独自の URLconf になります。ここでは、path() の第一引数に URLパターンを表す route を空文字とし、先程作成したビュー views.index と紐付けています。そして、このURLに index という名前を付けました。 これにより、ルートパスへのアクセスで、views.pyindex メソッドが呼び出されることになります。

URLのマッピングはもう一つステップが必要です。ルートのURL定義 locallibrary/urls.py に、現在のアプリケーションへのルーティングを追加する必要があります。

locallibrary/urls.py を以下のように編集します。

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('catalog/', include('catalog.urls')),
]

catalog というURLパスでのアクセスに、catalogアプリケーションの URLconf をインクルードしました。

これで、catalog というパスでアクセスした場合に、catalogアプリケーションで定義した URL定義 catalog/urls.py が使われるようになります。


準備が完了したので、開発サーバで確認してみましょう。

$ python manage.py runserver

ブラウザで http://localhost:8000/catalog/ にアクセスすれば、以下のように、作成したビューが表示されます。

f:id:Naotsugu:20211115211348p:plain

URLのルーティングについて見たので、続いてアプリケーションで使うモデルの定義に進みましょう。


モデルの定義

最初に、アプリケーションで扱うモデルの全体像を見ておきます。

f:id:Naotsugu:20211115211452p:plain

書籍 Book には、ジャンル Genre と言語 Language、そして著者 Author があり、貸し出し対象の本 BookInstance で、対象の書籍とその貸し出し状態などを管理するモデルとなります。

Django の ORM は ActiveRecord パターン実装となっているため、モデルオブジェクトを作成すればデータベースのテーブルにマッピングされ、モデルを通した操作が透過的にデータベースに反映されます。


手始めに、単純なモデルである、ジャンル Genre と言語 Languageを定義しましょう。

モデルは、アプリケーション生成時に作成された catalog/models.py に定義します。以下のように編集します。

from django.db import models

class Genre(models.Model):
    name = models.CharField(max_length = 200,
        help_text = 'Enter a book genre (e.g. Science Fiction)')

    def __str__(self):
        return self.name

class Language(models.Model):
    name = models.CharField(max_length=200, 
        help_text="Enter the book's natural language (e.g. English, French, Japanese etc.)")

    def __str__(self):
        return self.name

モデルは、django.db.models.Modelのサブクラスとして定義します。 クラス変数によりモデルのデータベースフィールド(Fieldクラスのインスタンス)を定義します。

ここでは、CharField により文字のフィールドを定義し、max_length にてフィールドの値の最大長を指定しています。 さらに help_text により HTML の入力フォームを表示する際のヒントとなるテキストラベルも指定しています。

フィールドの定義には、null=True で nullを可にしたり(デフォルトは False)、 blank=True でブランクを可にしたり(デフォルトはFalse)、primary_key=True でPKしたりといった各種定義が可能です。なお、primary_key を指定しない場合は、自動的にPKフィールドが追加されます。


定義したモデルを Django で使うには、アプリケーションを Django の管理に含める必要があり、これには locallibrary/settings.pyINSTALLED_APPS を以下のように編集します。

INSTALLED_APPS = [
    ...,
    'catalog.apps.CatalogConfig',
]

これでモデルの定義が終わったので、データベースマイグレーションを行い、このモデルをデータベースに反映していきましょう。


データベースマイグレーション

Django では、データベースのマイグレート用に makemigrationsmigrate というコマンドが用意されています。

makemigrations コマンドは、プロジェクトにインストールされた全てのアプリケーションのマイグレーションを作成します。このコマンドでモデルのコードからマイグレーション用のコードを生成し、migrate コマンドで、作成したマイグレーションをデータベースに反映します。

マイグレーションの作成は、manage.pymakemigrations コマンドを指定します。

$ python manage.py makemigrations

makemigrations コマンドを実行すると、以下のような出力が得られます。

Migrations for 'catalog':
  catalog/migrations/0001_initial.py
    - Create model Genre
    - Create model Language

先程作成した GenreLanguage のマイグレーションが catalog/migrations/0001_initial.py というファイルとして生成されました。

作成されたファイルの中身は以下のようになっています。

from django.db import migrations, models

class Migration(migrations.Migration):
    initial = True
    dependencies = [
    ]
    operations = [
        migrations.CreateModel(
            name='Genre',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(help_text='Enter a book genre (e.g. Science Fiction)', max_length=200)),
            ],
        ),
        migrations.CreateModel(
            name='Language',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(help_text="Enter the book's natural language (e.g. English, French, Japanese etc.)", max_length=200)),
            ],
        ),
    ]

migrate コマンドでマイグレーションを実行すると、このコードによりモデルがデータベースに反映されます。

では、実際のマイグレーションを実行しましょう。

$ python manage.py migrate

マイグレーションの実行により settings.pyINSTALLED_APPS に定義されたアプリケーションで必要となるマイグレーションが実行されます。

Operations to perform:
  Apply all migrations: admin, auth, catalog, 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 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 auth.0012_alter_user_first_name_max_length... OK
  Applying catalog.0001_initial... OK
  Applying sessions.0001_initial... OK

先程作成したモデルは catalog.0001_initial という出力でマイグレーションが実行されたことが確認できます。 それ以外にも、デフォルトでインストールされているアプリケーションのマイグレーションが実行されていることがわかります。


Django は、初期生成時のデフォルトのデータベースとして sqlite3 が組み込まれており、必要なテーブルやデータが sqlite3 に登録されます。

その他のデータベースを利用する場合は、settings.py の以下の設定を変更することで対応できます。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

ここでは、そのまま sqlite3 を使っていくことにします。


Django は、データベース内の django_migrations というテーブルで、適用済みのマイグレーションを管理しています。 モデルを変更したら、makemigrations コマンドでマイグレーションを作成し、migrate コマンドで作成したマイグレーションをデータベースに適用します。 モデルを変更するたびに、この手順を繰り替えすことで、モデルの変更点をデータベースに適用していくことができます。


現在の状態でマイグレーションを新しく作成する場合は、catalog/migrations/ に作成されたマイグレーションファイルを削除し、データベースを初期化(sqlite3 の場合には、プロジェクトフォルダのsb.dqlite3ファイルを削除)してから、makemigrationsmigrate することもできます。

なお、migrate で実行される SQLは以下のようにして確認することができます。

$ python manage.py sqlmigrate catalog 0001

0001 はマイグレーション名で、対応するマイグレーションを指定します。

今回の例では以下のような出力が得られます。

BEGIN;
--
-- Create model Genre
--
CREATE TABLE "catalog_genre" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(200) NOT NULL);
--
-- Create model Language
--
CREATE TABLE "catalog_language" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(200) NOT NULL);
COMMIT;


Django 管理サイト

モデルが作成できれば、Django 管理サイトから CRUD 操作が可能となっています。

最初に Django 管理サイト用の superuser を作成します。

$ python manage.py createsuperuser

createsuperuser コマンドを実行すると、スーパーユーザの登録が求められます。

任意のユーザ名とパスワードでスーパーユーザを登録しましょう。

Username (leave blank to use 'xxxx'): user
Email address: user@example.com
Password:
Password (again):
Superuser created successfully.

この操作により、データベースにスーパーユーザの情報が登録され、Django 管理サイトにログイン可能となります。


Django 管理サイトで先程登録したモデルの編集を可能とするために、catalog/admin.py を以下のように編集します。

from django.contrib import admin
from .models import Genre, Language

admin.site.register(Genre)
admin.site.register(Language)

admin.site.register() により GenreLanguage を管理サイトに登録しました。

これで準備は完了です。開発サーバを起動してDjango 管理サイトにアクセスしましょう。

$ python manage.py runserver

ブラウザで http://localhost:8000/admin/ にアクセスすれば、Django 管理サイトのログイン画面が表示されます。

f:id:Naotsugu:20211115220923p:plain

先程作成したスーパーユーザでログインできます。

管理サイトでは、認証認可のための、Group と User の編集に加え、catalog アプリケーションで先程定義したモデルの編集が可能になっています。

f:id:Naotsugu:20211115222306p:plain

Genre と Language のCRUD操作が可能です。

f:id:Naotsugu:20211115222601p:plain

f:id:Naotsugu:20211115222628p:plain


モデルの追加

残りのモデルについても同様に定義を追加していきましょう。

catalog/models.pyAuthor を追加します。

from django.urls import reverse

class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    date_of_birth = models.DateField(null=True, blank=True)
    date_of_death = models.DateField('Died', null=True, blank=True)

    class Meta:
        ordering = ['last_name', 'first_name']

    def get_absolute_url(self):
        return reverse('author-detail', args=[str(self.id)])

    def __str__(self):
        return f'{self.last_name}, {self.first_name}'

GenreLanguage には無かった Meta クラスの定義と、メソッドを定義しています。

モデルに Meta クラスを定義することで、モデルレベルのメタデータを宣言できます。ここでは、ordering によりレコードのデフォルトのソート順を指定しています。ソートキーとしてlast_name first_name を指定しています。逆順にする場合は、-first_name のようにマイナス記号を付けます。その他のオプションについてはModel metadata options を参照してください。

get_absolute_url() メソッドでは、モデルのレコードを表示するための URL を定義しています。このメソッドを定義すると、自動的に Django 管理サイトのレコード編集画面に "View on Site" ボタンが追加されます。author-detail というURL名(これは後ほど定義します)からURLを生成しています。


同様に、BookBookInstance の定義も追加しましょう。

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
    summary = models.TextField(max_length=1000, help_text="Enter a brief description of the book")
    isbn = models.CharField('ISBN', max_length=13,
                            unique=True,
                            help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn'
                                      '">ISBN number</a>')
    genre = models.ManyToManyField(Genre, help_text="Select a genre for this book")
    language = models.ForeignKey('Language', on_delete=models.SET_NULL, null=True)
    
    class Meta:
        ordering = ['title', 'author']

    def get_absolute_url(self):
        return reverse('book-detail', args=[str(self.id)])

    def __str__(self):
        return self.title
import uuid

class BookInstance(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4,
                          help_text="Unique ID for this particular book across whole library")
    book = models.ForeignKey('Book', on_delete=models.RESTRICT, null=True)
    imprint = models.CharField(max_length=200)
    due_back = models.DateField(null=True, blank=True)

    LOAN_STATUS = (
        ('d', 'Maintenance'),
        ('o', 'On loan'),
        ('a', 'Available'),
        ('r', 'Reserved'),
    )

    status = models.CharField(
        max_length=1,
        choices=LOAN_STATUS,
        blank=True,
        default='d',
        help_text='Book availability')

    class Meta:
        ordering = ['due_back']

    def __str__(self):
        return '{0} ({1})'.format(self.id, self.book.title)

今まで見てきたモデルとだいたい同じですが、リレーションフィールドが追加されています。 リレーションフィールドには、ForeignKey OneToOneField ManyToManyField があり、それぞれ、多対一, 一対一, 多対多, に該当します。 ManyToManyField の場合には、リレーション用の中間テーブルが自動的に作成されます。


先程までと同様に、Django 管理サイトで登録したモデルの編集を可能とするために、catalog/admin.py を以下のように変更します。

from django.contrib import admin
from .models import Genre, Language, Author, Book, BookInstance

admin.site.register(Genre)
admin.site.register(Language)
admin.site.register(Book)
admin.site.register(Author)
admin.site.register(BookInstance)


それでは、モデルの変更からマイグレートを作成しましょう。

$ python manage.py makemigrations

Migrations for 'catalog':
  catalog/migrations/0002_author_book_bookinstance.py
    - Create model Author
    - Create model Book
    - Create model BookInstance

モデルのマイグレーションが作成されました。

続いてマイグレートの実行です。

$ python manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, catalog, contenttypes, sessions
Running migrations:
  Applying catalog.0002_author_book_bookinstance... OK

モデル反映ができたので、続けて初期データを投入しましょう。


dumpdata と loaddata

Django では、dumpdata コマンドでデータベースのダンプデータを抽出し、loaddata コマンドでダンプデータをデータベースに反映することができます。 ダンプデータは JSON 形式となっています。

ここでは、初期データとして catalog/fixtures というディレクトリの中に、init.jsonという名前で以下のファイルを作成します。

[
  {
    "model": "catalog.genre",
    "pk": 1,
    "fields": { "name": "Fantasy"}
  },
  {
    "model": "catalog.genre",
    "pk": 2,
    "fields": { "name": "Science" }
  },
  {
    "model": "catalog.genre",
    "pk": 3,
    "fields": { "name": "Poetry" }
  },
  {
    "model": "catalog.language",
    "pk": 1,
    "fields": { "name": "English" }
  },
  {
    "model": "catalog.language",
    "pk": 2,
    "fields": { "name": "Japanese"}
  },
  {
    "model": "catalog.author",
    "pk": 1,
    "fields": { "first_name": "Patrick", "last_name": "Rothfuss", "date_of_birth": "1960-06-06", "date_of_death": null }
  },
  {
    "model": "catalog.author",
    "pk": 2,
    "fields": { "first_name": "Ben", "last_name": "Bova", "date_of_birth": "1961-02-24", "date_of_death": null }
  },
  {
    "model": "catalog.book",
    "pk": 1,
    "fields": { "title": "The Name of the Wind", "author": 1, "summary": "Told in Kvothe's own voice ...", "isbn": "9781473211896", "language": 1, "genre": [1] }
  },
  {
    "model": "catalog.book", "pk": 2,
    "fields": { "title": "The Dueling Machine", "author": 2, "summary": "Dueling as a means of settling disputes ...", "isbn": "9780425064665", "language": 1, "genre": [2] }
  },
  {
    "model": "catalog.bookinstance",
    "pk": "8ebec09b-bc7d-49f4-9855-d1b77f29ccea",
    "fields": { "book": 1, "imprint": "DAW", "due_back": "2008-04-01", "status": "a" }
  },
  {
    "model": "catalog.bookinstance",
    "pk": "9c262b44-efc3-4717-9ba6-b2a92ff8b33c",
    "fields": { "book": 2, "imprint": "Berkley", "due_back": "2021-04-27", "status": "a" }
  },
  {
    "model": "catalog.bookinstance",
    "pk": "da908a10-ba83-4fd1-a7fb-a9bb16ac0882",
    "fields": { "book": 2, "imprint": "Berkley", "due_back": "2021-04-27", "status": "a" }
  }
]

この初期データをデータベースに反映するには、loaddata コマンドを実行します。

$ python manage.py loaddata init.json

Installed 9 object(s) from 1 fixture(s)

loaddata コマンドにより、作成したJSONの内容がデータベースに初期データとして反映されました。


反対に、データベースの内容から JSON ファイルを作成するには以下のように dumpdata コマンドを使うことができます。

$ python manage.py dumpdata catalog > catalog/fixtures/init.json

通常は、開発の中で Django 管理サイトで操作しつつ、dumpdata コマンドでデータ抽出し、loaddata で反映するという流れになるでしょう。


では、サーバを起動して追加したモデルを確認しましょう。

$ python manage.py runserver

http://localhost:8000/admin/ にアクセスすれば、作成したモデルが操作できます。

f:id:Naotsugu:20211123110804p:plain


ModelAdmin による管理サイトのカスタマイズ

Django 管理サイトの内容は、ModelAdmin クラスを使うことでカスタマイズすることができます。

ModelAdmin の登録は、catalog/admin.py にて admin.site.register(Author) のように登録した箇所を以下のように変更することで行います。

@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    pass

上記は pass として空定義としていますが、例えば一覧の表示項目を変更する場合は以下のようにしてカスタマイズを行うことができます。

@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    list_display = ('last_name', 'first_name', 'date_of_birth')

なお、@admin.register ではなく、admin.site.register(Author, AuthorAdmin) のように登録することもできます。

ここでは、ModelAdmin について深追いはしません。詳細は The Django Admin site を参照してください。



まとめ

今回は、Django の導入から、モデルの操作までを見てきました。

次回は、ここで作成したモデルを操作するビューを扱っていきます。

blog1.mammb.com