Python Django チュートリアル(2)

  • 14
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

勉強会用資料です.
django1.8のチュートリアルを辿りつつ説明していきます.
https://docs.djangoproject.com/en/1.8/intro/tutorial02/

日本語の公式ドキュメントはバージョン1.4が最新なので若干違いが有りますが大まかな流れは一緒なので一読するのもいいと思います.
http://django-docs-ja.readthedocs.org/en/latest/intro/tutorial02.html

チュートリアル1
チュートリアルまとめ

概要

今回はdjangoの管理サイトについて説明していきます.
djangoには標準で管理サイトが用意されており,スタッフ権限を持つユーザはここからモデルを操作することができます.
djangoが標準で持っているユーザモデルを始め,自分が追加したモデル
(例えばチュートリアルで作成した投票用の2つのモデル)も半自動でそれっぽいページを作ってくれます.

データを登録する,一覧表示する,検索する,のようなデータを扱うだけのwebアプリなら
このページをカスタマイズしていくだけで簡単に作成できます.

スーパーユーザの用意

ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial02/#creating-an-admin-user
ソース→add_app_4_database_migrationタグ (変更なし)

管理サイトを触るにはスタッフ権限を持つユーザが必要です.
django用のスーパーユーザはcreatesuperuserコマンドを使って作成します.

$ ./manage.py createsuperuser
Username (leave blank to use 'shimomura'): admin
Email address:
Password:
Password (again):
Superuser created successfully.

createsuperuserコマンドを実行するとUsername, Email, Passwordを入力するよう求められます.
UsernameはdefaultだとPCのusernameがそのまま入ります.今回はadminにしています.
Emailは空でも大丈夫です.
Passwordは同じ文字列を2回入力してください.

最後に Superuser created successfully. と出ると完了です.

管理サイトにアクセス

ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial02/#start-the-development-server
ソース→add_app_4_database_migrationタグ → 954ba86

スーパーユーザを作ったらテスト用サーバを起動させて管理サイトにアクセスしてみましょう.
サーバの起動はrunserverコマンドです.

$ ./manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
November 05, 2015 - 07:37:15
Django version 1.8.5, using settings 'tutorial.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

この状態でブラウザで
http://localhost:8000/admin/
にアクセスすると以下のようなログイン画面にリダイレクトするはずです.

Kobito.b0bz7R.png

無事ログインできると以下のような画面になります.
デフォルトでは認証用のモデル(GroupsとUsers)だけ表示されています.

Kobito.WQw8Oi.png

--

日本語化

無事サイトは表示できたと思いますが,ご覧のように管理サイトはデフォルトでは英語です.
英語は嫌なので日本語にしましょう.

djangoはもちろん多言語対応してます.
表示する言語はsettings.pyの103行目付近で定義されています.
デフォルトではen-usになっているので,これをjaに変更しましょう.

settings.py_103行目付近
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'ja'

# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Tokyo'

直したら管理サイトにもう一度アクセスしてみてください.
http://localhost:8000/admin/

Kobito.dVaOZw.png

無事日本語化されたようです.

投票モデル追加

ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial02/#make-the-poll-app-modifiable-in-the-admin
ソース→954ba8635ec2c6

無事管理サイトは見えたところで,今度は自前のモデルも表示させましょう.
管理サイトに表示するモデルの設定やカスタマイズはapp/admin.pyに記述します.

今回はチュートリアルにならってpollsアプリのQuestionモデルを追加します.

polls/admin.py
from django.contrib import admin

from .models import Question


admin.site.register(Question)

これで管理サイトで表示されるようになったはずです.

Kobito.Q3fesY.png

データの追加とカスタマイズ

データの追加

データの追加も試してみましょう.
追加リンクを押すとデータ追加用のフォームが表示されます.
Questionモデルはquestion_textpub_dateの2つのフィールドを持っていたので,
フォームの表示にも2つの項目が表示されます.

Kobito.24CSrL.png

Kobito.dMucDK.png

登録するとQuestion objectというデータが1つできているはずです.
もう一回登録するとQuestion objectが2つ表示されます.

Kobito.eBQJpR.png

オブジェクト名のカスタマイズ

このままだとなんのデータかわからないので,objectを表す文字列を変更しましょう.
変更の仕方は,変更したいモデルの__str__メソッド(python2系の場合は__unicode__)をオーバーライドするだけです.
今回は質問内容を表示させるように修正します.

polls/models.py
class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text

Kobito.ilTlCf.png

モデル名のカスタマイズ

モデル自体を表す文字列(この場合はQuestion)を変えたい場合はMetaクラスで設定します.
verbose_nameでそのモデルを表す名前,
verbose_name_pluralでそのモデルの複数形を表す名前を設定できます.

polls/models.py
class Question(models.Model):
    class Meta:
        verbose_name = '質問'
        verbose_name_plural = '質問の複数形'

    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text

Kobito.r2Xvyz.png

Question, Questions質問, 質問の複数形 に変わってるのを確認してください.

並び順のカスタマイズ

デフォルトでは登録の降順(新しいものが上に来る)ようになっていますがこれを公開日(pub_date)の新しいものから並べるように変更してみましょう.

変更はモデルのMetaクラスのorderingプロパティで設定します.
設定値はフィールド名,降順にしたい場合は頭に-をつけます.

class Question(models.Model):
    class Meta:
        verbose_name = '質問'
        verbose_name_plural = '質問の複数形'
        ordering = ['-pub_date']

    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text

まず質問内容順で並べ,同じ場合は公開日の降順で並べる場合は
ordering = ['question_text', '-pubdate']
のように書きます.
実際に並び変わることを確認してみてください.

--

追加時のフォーム自体をカスタマイズすることも可能です.(2つ下の節で説明します)
本家のチュートリアルではこの後Questionオブジェクトを追加する際の
Formのデザインの変え方を説明していますが,今回は説明を割愛します.
興味のある方は本家のチュートリアルを見てください.
https://docs.djangoproject.com/en/1.8/intro/tutorial02/#customize-the-admin-form

relationのあるオブジェクト

ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial02/#adding-related-objects
(途中からInline項目の追加で説明)
ソース→ 35ec2c684f1086

pollsアプリが持っているもう一つのモデルであるChoiceを追加していきます.
このモデルはForeignKey(Questionモデルへのリレーション)を持っていますが,どのように表示されるでしょうか?

まずはadminに表示させるためにpolls/admin.pyを編集してChoiceを追加します.

polls/admin.py
from django.contrib import admin

from .models import Question
from .models import Choice  # ここを追加


admin.site.register(Question)
admin.site.register(Choice)  # ここを追加

Kobito.yD8Cfw.png

無事追加されたようです.
ChoiceモデルはMeta設定などをしてないのでそのまま出てますね.
続いて追加画面を見ていきます.

Kobito.dfblb5.png

ForeignKeyフィールドの場合,Formではこのようにセレクトリストで表示されます.
右側にある緑色のプラスボタンを押すことでQuestionオブジェクトを新しく作ることもできます.

Kobito.DcXGUI.png

内容はこんな感じで先ほど作成したQuestionモデルのオブジェクトが入っています.
__str__を設定していない場合はここで3つともQuestion objectと表示されて悲しいことになります.
もちろんこの選択肢も何を出すかも自由にカスタマイズできます.
並び順はモデルのMetaクラスに設定されているorderingで並び替えられます.

Adminサイト用モデルカスタマイズ

このようにadmin.site.register関数でモデルを登録するだけで自動的に色々やってくれますが,
少し手を加えるだけでFormの内容変更やリストの表示,検索項目の追加など色々カスタマイズすることができます.

カスタマイズするときはadmin.site.reigster関数の第2引数にAdminサイトでの振る舞いを記述したクラスを渡します.
このクラスはadmin.ModelAdminクラスを継承し,必要な箇所だけ自分でオーバーライドして作ります.
文章だけだとわかりにくいので実際にそれぞれのカスタマイズ例を示していきます.

Inline項目の追加

ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial02/#adding-related-objects
ソース→ 84f1086e4bacf7

ここまでの例ではQuestionとChoiceを追加したい場合,まず元になるQuestionを作成し,
それをChoiceの追加ページで選択する必要がありました.
ChoiceでいちいちQuestionを選択するのはめんどうですし,選択間違いをする可能性もあります.

そこで便利なのがInlineFormです.これを使えばリレーション元のオブジェクト(この場合はQuestion)と
リレーション先のオブジェクト(この場合はChoice)を同時に作成することができます.

adminサイトの場合,InlineAdminというInline表示用のクラスが用意されています.
今回はStackedInlineクラスを使用します.

修正したソースコードは以下のようになります.

polls/admin.py
from django.contrib import admin

from .models import Question
from .models import Choice


class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3


class QuestionAdmin(admin.ModelAdmin):
    inlines = [ChoiceInline]

admin.site.register(Question, QuestionAdmin)
admin.site.register(Choice)

ChoiceInline, QuestionAdminの定義を追加し,Questionを登録する際の第2引数に
QuestionAdminを渡すように修正しています.

admin.StackedInlineはStacked形式のInlineを作成するためのベースクラスで,
対象となるモデル(この場合はChoice)と表示数(extra=3)を設定します.
他にも最大数,削除可能かどうかなどを設定できます.

admin.ModelAdminは管理サイトでのモデルの振る舞いをカスタマイズするためのクラスです.
今回はinlinesを設定し,オブジェクトの追加,編集時の振る舞いを変更しています.

ここまで変更して,再度管理サイトのQuestionの追加ページ(もしくは編集ページ)にいくと
Choicesを同時に編集できるようになっているのが確認できると思います.

Kobito.3GQrd4.png

オブジェクト表示のカスタマイズ

ドキュメント→https://docs.djangoproject.com/en/1.8/intro/tutorial02/#customize-the-admin-change-list
ソース→e4bacf77f5128a

登録や編集はいい感じになってきたので,今度は一覧表示をカスタマイズしましょう.
表示を変えるにはadmin.ModelAdminを継承して作ったクラス(QuestionAdmin)にlist_displayを設定します.

polls/admin.py
...
class QuestionAdmin(admin.ModelAdmin):
    inlines = [ChoiceInline]
    list_display = ('question_text', 'pub_date')
...

Kobito.2sV4uA.png

殺風景だったリストが少し賑やかになりました.
全てのモデルはdjangoが自動的に主キーを付けてくれます.
ついでなのでそれもつけてみましょう.

polls/admin.py
...
class QuestionAdmin(admin.ModelAdmin):
    inlines = [ChoiceInline]
    list_display = ('pk', 'question_text', 'pub_date')
...

Kobito.MR1ddC.png

いい感じですね.

もっとカスタマイズ

本家チュートリアルにならって少し特殊なこともしてみましょう.
list_displayにはフィールドの他にも引数なしのメソッドを設定することができます.

Questionモデルに質問が1日以内に公開されたものか確認するwas_published_recentlyメソッドを追加します.

polls/models.py
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)
...

次にlist_displayにこのメソッドを追加します.

polls/admin.py
...
class QuestionAdmin(admin.ModelAdmin):
    inlines = [ChoiceInline]
    list_display = ('pk', 'question_text', 'pub_date', 'was_published_recently')
...

Kobito.gpHA62.png

ちゃんと見えてますね.
Questionに紐付いているChoiceの数を返すメソッドなどを作ってみるとおもしろいかもしれません.

さらにカスタマイズ

list_displayの対象がメソッドの場合,メソッドに属性を追加することで表示の変更やオーダ条件の設定が可能です.
本家チュートリアルに習ってadmin_order_field, boolean, short_descriptionを設定してみましょう.

polls/models.py
...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'
...

Kobito.qOD9IC.png

とても良い感じになりました.
admin_order_fieldは並び替えをする時にどのフィールドを見るかを設定しています.
この例ではpub_dateフィールドで並び替えています.
この属性を設定することでテーブルのヘッダをクリックできるようになり,並び替えができるようになります.

フィルター,検索追加

最後にフィルターと検索を追加してみます.
例のごとくQuestionAdminにプロパティを設定するだけです.

polls/admin.py
...
class QuestionAdmin(admin.ModelAdmin):
    inlines = [ChoiceInline]
    list_display = ('pk', 'question_text', 'pub_date', 'was_published_recently')
    list_filter = ['pub_date']
    search_fields = ['question_text']
...

Kobito.SrObQZ.png

こんな感じで簡単にフィルター,検索を追加することができます.

--
次のチュートリアルへ

チュートリアルまとめ