WEBTODESIGN

#3 VSCでDjango開発入門【データベースの設定・管理画面編】

前回 #2 VSCでDjango開発入門【文字を表示してみる編】の、次のステップです。

公式チュートリアルのはじめての Django アプリ作成、その2に沿って、データベースの設定と管理画面の設定を行います。

このステップでは、データベースへのデータの保存・取り出しと管理画面へログインができるようになります。

前提

  • コマンドはVisual Studio Code内のターミナルで実行します。
  • 基本的にコマンドはWindowsの場合となっています。

データベースの作成

データベースとは、様々なデータを保持しておく場所です。例えば、アカウント情報やユーザーが登録したデータなど。動的に情報が変わっていく部分です。データベースに保存した情報から適宜必要なデータを取り出して、サイト上に表示することができます。

動的なサイトには不可欠です。

データベースは管理システムで管理をします。それには様々な種類があり、デフォルトではPythonに標準搭載されているSQLiteが使用されます。「データベースに詳しくなかったり、単に Django を試してみたいだけなら、これが一番簡単な選択です。」と公式より。今回はデフォルトで十分ですね。

変更したい場合はmysite/settings.pyにて設定が変更できます。(詳細はこちら

それでは、ターミナルで以下のように実行してデータベースを作成しましょう!

python manage.py migrate

これで、データベースが作成されました。

モデルの作成

「モデル」って何!

Djangoの仕組みとして「M(モデル)T(テンプレート)V(ビュー)」というものがあると前回学習しました。

  • 「ビュー」でどのページを表示するか指定し
  • 「モデル」からデータを引っ張って
  • 「ビュー」でデータを編集・整理し(しない場合もある)
  • 「テンプレート」でデータを表示する

という流れでDjangoはサイトやアプリを表示しますという話でした。この「モデル」部分です。

モデルはWebアプリとデータベース間のやりとりを担うコンポーネントのことです。

データベースはSQL文で書かれていて複雑です。しかし、モデルを使うとにSQL文を使わずにデータベースの管理ができます

モデルの作成

pollsフォルダの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)

今回は投票アプリを作っているので、質問のモデル(Question)と投票先のモデル(Choice)を作成します。1つのモデルは1つのクラスで表現されます。

  • Questionモデルには「question_text」と「pub_date」という2種の値
  • Choiceモデルには「question」と「choice_text」と「votes」という3種の値

が表としてデータベースに保存されます。

データの種類を設定

各モデル内のデータはフィールド名 = models.フィールドの型(フィールドオプション)の形式で定義します。

フィールドの型はデータをどのような形式で保存するかの指定です。例えば、今回使われているものは以下です。

  • CharField … 文字列が入力できるフィールド
  • DateTimeField … 日付と時間の選択ができるフィールド
  • IntegerField … 整数のフィールド

型それぞれに管理画面でのインターフェースやオプションが用意されているので、自分が保存・出力したいデータに合わせて型を選ぶ必要があります。

すべてのフィールドは下記の公式リファレンスで確認できます。
モデルフィールドリファレンス | Django ドキュメント | Django – フィールドの型

引数ではオプションを指定できます。引数が必須なフィールドもあるので、上記のリファレンスで確認してください。

質問と選択肢の紐づけ

question = models.ForeignKey(Question, on_delete=models.CASCADE)

ForeignKeyによってそれぞれのChoiceが1つのQUestionに紐づいていることをDjangoに伝えています。

モデルの有効化

モデルは作成できましたが、まだデータベースとは結びついていません

前回、mysite/settings.pyのINSTALLED_APPSにpollsアプリケーションを追加しましたよね。その設定が完了してから、次のコマンドを実行します。

python manage.py makemigrations polls

これで、モデルに変更があった事を伝え、データベース用の構造に変換されます。変換された内容はpolls/migrations/0001_initial.pyに記述されています。(手動で変更したい場合のために、人間可読なファイルとして設計されているそうです。)

最後に、もう一度migrateします。

python manage.py migrate

これで、今回のモデルがデータベースに反映されました。

データベースをシェルで操作する

試しに、データベースに値を登録したり修正したりしてみます。

ターミナルから以下のコマンドを実行してPython対話シェルを起動します。一行ずつPythonスクリプトを実行します。結果を確認しながらPythonスクリプトと試せるのがPython対話シェルだそうです。

python manage.py shell

Python対話シェルにて、モデルを活用してデータベースを操作してみます。

以下は公式チュートリアルの英語のコメントアウトを日本語に訳したバージョンです。
>>>のあとの部分を入力して順番に実行していきます。同じ結果が返ってくることを確認してください。

# 先ほど書いたモデルクラスをインポートします。
>>> from polls.models import Choice, Question

# まだ質問はありません。
>>> Question.objects.all()
<QuerySet []>

# 新しい質問を作成します。
# タイムゾーンのサポートはデフォルトの設定ファイルで有効になっているので、Django は pub_date に tzinfo を持つ datetime を要求します。datetime.datetime.now() の代わりに timezone.now() を使えば、正しい動作になります。
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# オブジェクトをデータベースに保存します。明示的に save() を呼び出す必要があります。
>>> q.save()

# これでIDがつきました。
>>> q.id
1

# Pythonの属性を使ってモデルフィールドの値にアクセスします。
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# 値を変更するには、属性を変更してからsave()を呼び出します。
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all()は、データベース内のすべての質問を表示します。
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>

ここで注目したいのは、項目名がQuestion object (1)となっていることです。項目を追加していくとQuestion object (2)Question object (3)…と増えていくわけですが、これでは非常に管理しにくく、良くありません。

なので、質問内容を項目名に反映させてみます。

とりあえずCtrl + Zを打ったあとにEnterキーを押してシェルを終了します。

さて、シェルを終了させたら、polls/models.pyQuestionクラスの内容に以下のように追記します。ついでにChoiceクラスにも追加しておきます。

from django.db import models

class Question(models.Model):
    # ...
    def __str__(self):
        return self.question_text

class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text

__str__()は文字列表現を定義する特殊メソッドです。returnで自身のquestion_textを返してデータの名前を指定しています。

また、クラスメソッドを追加してみます。

import datetime

from django.db import models
from django.utils import timezone

class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

再度python manage.py shellでPython対話シェルを起動して、確認してみます。

>>> from polls.models import Choice, Question

# 私たちの __str__() の追加がうまくいったかどうか確認してください。
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

# Django は、完全にキーワード引数によって駆動される豊富なデータベース検索 API を提供します。
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>

# 今年公開された質問を入手します。
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# 存在しないIDを要求すると、例外が発生します。
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# primary key による検索は最も一般的なケースなので、 Django は primary key の正確な検索をするためのショートカットを提供します。以下は Question.objects.get(id=1) と同じです。
>>> Question.objects.get(pk=1)
<Question: What's up?>

# 私たちのカスタムメソッドが機能したことを確認します。
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

# 質問には2つの選択肢を与えましょう。
# create 呼び出しは、新しい Choice オブジェクトを構築し、 INSERT 文を実行し、利用可能な選択肢のセットに選択肢を追加し、新しい Choice オブジェクトを返します。Django は ForeignKey 関係の「向こう側」(例えば質問の選択肢) を保持するセットを作成し、API 経由でアクセスできるようにします。
>>> q = Question.objects.get(pk=1)

# 関連するオブジェクトセットから任意の選択肢を表示します。 -- 今のところありません。
>>> q.choice_set.all()
<QuerySet []>

# 3つの選択肢を作ります。
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

# Choiceオブジェクトは、関連するQuestionオブジェクトにAPIアクセスすることができます。
>>> c.question
<Question: What's up?>

# また、その逆も同様です。QuestionオブジェクトはChoiceオブジェクトにアクセスすることができます。
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3

# APIは必要な範囲まで自動的にリレーションシップを追従します。
# リレーションシップを区切るには、ダブルアンダースコアを使用します。
# これは、あなたが望む限り、何段階でも動作します。
# pub_date が今年の問題のすべての Choices を検索します。
# (上記で作成した 'current_year' 変数を再利用します)。
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

# 選択肢の一つを削除してみましょう。それにはdelete()を使いましょう。
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

以上で、対話シェルでのモデルをつかったデータベースの操作チュートリアルは終了です。

なんとなく、データベースへの登録・修正のしくみと流れがわかりましたか?

無事、質問「What’s up?」に選択肢「Not much」と「The sky」を追加することができました。

データベースの管理画面からの操作

さて、コマンドでデータベースを操作できることがわかりましたが…これを毎度行うのは大変です。

安心してください。Djangoでは、最初から管理画面が用意されています。

管理画面のインターフェースは殆どのプロジェクトで共通のものであることから、管理画面の自動生成をしてくれています。誠にありがたい。

ユーザーの作成

まずは、ログインユーザーの作成をします。

python manage.py createsuperuser

ユーザー名、メールアドレス、パスワード(2回)が聞かれるので入力します。

パスワードは入力しても表示されませんが、ちゃんと入力されてるので焦らず。

ログインしてみる

ユーザーが追加できたら、ログインを試してみましょう!まずはサーバーを起動します。

python manage.py runserver

http://127.0.0.1:8000/admin/ にアクセスします。adminディレクトリに接続するのがポイントです。

すると、このようなログイン画面が現れます。

ログイン画面

先程設定したユーザー名とパスワードを入れてみると…

管理画面

ログインに成功して、管理画面が表示されました!

pollsアプリケーションを管理画面で編集可能にする

質問を管理画面で追加したいので、管理画面に質問(Question)モデルを認識させましょう!

pollsフォルダのadmin.pyの内容を以下に書き換えます。

from django.contrib import admin

from .models import Question

admin.site.register(Question)

保存してページを再読込すると、管理画面にQuestionの項目が追加されました!

Questionの追加された管理画面

Questionの中身を見てみると、時間が日本時間になっていませんでした。

ファイルを日本仕様に修正

言語と時間を日本仕様に変更します。

mysiteフォルダのsettings.pyの内容を修正します。

LANGUAGE_CODE = 'ja' #「en-us」から「ja」へ
TIME_ZONE = 'Asia/Tokyo' #「UTC」から「Asia/Tokyo」へ

私は107行あたりでした。ファイルを保存してリロードしてみます。

日本語&日本時間になったことが確認できます。

様々な機能を試してみる

管理画面には、様々な機能が標準搭載されています。

詳しくは公式チュートリアルのadmin の機能を探究してみる を確認してください。

 
 

さて、今回はデータベースへのデータの保存・取り出しと管理画面へのアクセスができるようになりました!

以上でこのステップは完了です。

次は#4 VSCでDjango開発入門【ページ制御・テンプレート編】です。

シリーズ一覧

#1 VSCでDjango開発入門【環境構築・プロジェクト生成編】
#2 VSCでDjango開発入門【文字を表示してみる編】
#3 VSCでDjango開発入門【データベースの設定・管理画面編】(今ココ)
#4 VSCでDjango開発入門【ページ制御・テンプレート編】

参考元

Djangoを始めよう! 〜チュートリアル①〜 – Qiita
【図解Python初心者向け】Django基本的な使い方 | CodeCampus
【Django】Model(モデル)とは:models.pyの書き方とデータベース連携(テーブル作成) | OFFICE54
【Django】モデルの操作・データベース作成・削除|PythonによるWebアプリ開発(models.py)#6
Pythonのselfとかinitを理解する – Qiita
【Django】models.py:def str(self)とは?使用方法と管理画面での表示について | OFFICE54