はじめに
このドキュメントは,もともとはラボの新メンバー向けの入門テキストとして作成したもので,はじめてDjangoにふれる人にざっとその全体像をつかんでもらうことを狙っています.Djangoの日本語での参考資料も充実してきたので今さらという気がしないでもないですが,見直しを機にQiitaに移すことにしました.万が一でもどなたかの参考になれば幸いです.
説明のための具体例として,Djangoのオフィシャルチュートリアルにある投票アプリをとりあげています(が,説明上の都合で少しコードを追加,変更しているところもあります).素人の独学がベースで,特に前半は公式チュートリアルをやってみた感想のような記事です(今回は全7回中の2回目).
全体のコードはまとめてGitHubに置きました.
変更履歴
- [2021/04/26] Djangoのバーションを3.2に更新し,それ基づいて内容を微修正しました.
アプリケーションの作成
アプリケーションを格納する枠組み(プロジェクト)ができたので,その中に自分のアプリケーションを追加してみましょう.外側のmysiteのディレクトリで次のコマンドを打ち込みます.
$ python manage.py startapp polls
pollsはアプリケーションの名称です.この結果,外側のmysiteのディレクトリの中に,次のような構成のpollsというディレクトリが作成されます.
polls/
__init__.py
admin.py (adminサイトの設定ファイル)
apps.py
migrations/
__init__.py
models.py (データモデル用のファイル)
tests.py
views.py (view関数用のファイル)
これがアプリケーションの本体です.ただし,このままではプロジェクトはこのアプリケーションを認識してくれません.
そこで,もう一度プロジェクトの設定ファイルsettings.pyを開いて,INSTALLED_APPS
のリストにこのアプリケーションを追加しておきましょう(polls.apps.PollsConfig
は,pollsディレクトリの中のapps.pyファイルの中のPollsConfigクラスを指します).
INSTALLED_APPS = [
'polls.apps.PollsConfig', # これを追加する
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
データモデルの設計
続いて,このアプリケーションで使うデータをモデル化し,それをデータベースに格納できるようにしていきます.データモデルの構成は,models.pyに記述します.このファイルを開いて下記の内容を書き込みましょう.
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
データは表のような形式でデータベースの中に格納されていきます.データモデルとはその表の列構成だと考えればいいでしょう.
Djangoでは,データモデルをmodels.Model
を継承したクラスで表現します.各クラスが1つの表に対応し,その中のfield(models.****Field()
で指定されている項目)がそれぞれ1つの列を定義しています(モデル名は大文字で始め,フィールド名には小文字のみを用いること).そして,表の各行に対応する具体的なデータは,そのクラスのインスタンスとして扱われます.
上の例では,Questionクラスに対応する表には2つの列(行番号を区別するためのidというfieldが自動的に追加されるので,厳密には3つの列)があり,それらには文字列と日時のデータが格納されます.
Choiceクラスに対応する表には3つの列(同じく,厳密には4つの列)があり,それらにはそれぞれ,対応するQuestionへの参照,文字列,整数のデータが格納されます.
Djangoには他にも多くの種類のfieldが用意されています(詳しくはここに整理されています).
データモデルが定義できたので,それを実際にデータベースの構成に反映させましょう.そのために,外側のmysiteディレクトリで次のコマンドを実行します.
$ python manage.py makemigrations
$ python manage.py migrate
これ以降,データベースの構成を更新したい際には,上記の2つのコマンドを使用することになります.
1つ目のコマンドは,データベースの構成を操作するためのマイグレーションファイルを作成するもので,2つ目のコマンドは,そのマイグレーションファイルを実際に適用してデータベースの構成を更新するものです.
ここで開発用サーバを立ち上げてadminサイトにログインしても,追加したデータモデルはまだ反映されていません.adminサイトでデータモデルを編集できるようにするためには,admin.pyを編集して,それをadminサイトに登録する必要があります.
ひとまずadmin.pyに下記のように書き込んで,上で作成した2つのデータモデルのクラスを登録してみましょう.
from django.contrib import admin
from .models import Choice, Question
admin.site.register(Question)
admin.site.register(Choice)
QuestionとChoiceいう2つの項目がadminサイト上(のPOLLSのタブの下に)に現れたのがわかります.Questionの方をクリックして,試しに質問項目をいくつか追加してみましょう.
adminサイトの簡単なカスタマイズ
追加した質問項目には,Question object (1)
のような味気のない名前がつけられています.これをもう少しわかりやすい名前に変更してみましょう.そのために,models.pyに戻って,データモデルを表すクラスにいくつかメソッドを追加してみます.具体的には,models.pyの中身を次のように更新します.
import datetime
from django.utils import timezone
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text
__str__()
メソッドは,個々のデータ(データモデルのインスタンス)の名前を表記するのに使われます.adminサイトで確認すると,質問項目の名前が質問文自体に変更されていることがわかります.
was_published_recently()
メソッドは,よくみるとわかるように,この質問項目の登録日時が現時点からさかのぼって1日以内(だから最近に追加された)かどうかを判定するブール値を返すメソッドになっています(このように,データモデルのクラスには様々なメソッドを追加することができます).
現状では質問項目に対する回答の選択肢(Choice)は,質問項目(Question)とは独立して表示されていますが,これらは関連付けておいたほうがわかりやすいし,編集も容易です.これは,admin.pyを次のように書き換えることで簡単に実現できます.
from django.contrib import admin
from .models import Choice, Question
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
inlines = [ChoiceInline]
list_display = ('question_text', 'pub_date', 'was_published_recently')
admin.site.register(Question, QuestionAdmin)
また,admin.StackedInline
をadmin.TabularInline
に書き換えると,Choiceの部分がもう少しコンパクトな表形式の表示に変わります.
class ChoiceInline(admin.TabularInline): # ここを変更
model = Choice
extra = 3
おわりに
以上で2回目は終了です.第3回に続きます.