ホーム >  Python > Django >  投票アプリを作る その2管理サイト上のモデル編集(Django)

投稿日:   |  最終更新日:

投票アプリを作る その2管理サイト上のモデル編集(Django)

DjangoPython

Djangoで簡単な投票アプリを作成します。Djangoの管理サイトからモデルを操作するためにカスタマイズします。

投票アプリ

Webサイトのページから投票できる簡単な投票アプリを作成します。今回は、QuestionテーブルとChoiceテーブルを設定しています。前回はモデルを定義して、管理サイトから編集できるようにしました。今回は、エンティティ等のもう少し細かい設定を行います。

前提

  • 既にDjangoのプロジェクトを作成済み。
  • 投票アプリ用モデル(Choice、Question)作成済み。

仕様

Webページにボタン等のフォームを配置します。ユーザが入力を終え、送信ボタンをクリックしたタイミングでモデル(テーブル)への登録処理を行います。

準備

当サイトでは、Vagrantでゲスト環境(仮想環境)を作ってDjangoを動かいていますが、それ以外の環境でも操作方法はだいたい同じです。

①Djangoプロジェクトを生成します。

VagrantのDjangoで作るWebアプリケーション(その1 プロジェクト生成)

②Djangoアプリケーションを作ります。

VagrantのDjangoで作るWebアプリケーション(その2 プロジェクトの初期設定)

③投票アプリのモデルを定義します。

投票アプリを作る その1モデルの定義、管理サイトの表示(Django)

環境

OS CentOS 7.1.1503
pyenv 1.1.3-5-g7dae197
Anaconda 3-4.3.0
MariaDB 5.5.52-1.el7
Apache 2.4.6
mod_wsgi 4.5.14
Django 1.11.3

投票アプリ概要

①以下のようなDjangoアプリ構成を作ります。プロジェクト名が「pj1」で、アプリケーション名が「users」です。プロジェクトの設定は済ませたものとします。赤字のファイルは、今回変更する部分です。

  • pj1/
  • pj1/
  • __init__.py
  • settings.py
  • urls.py
  • wsgi.py
  • users/
  • __init__.py
  • admin.py
  • apps.py
  • urls.py
  • views.py
  • models.py
  • templates/

並び順のカスタマイズ

管理サイトのモデルのデータの並び順を変更します。

①デフォルトでは登録の降順ようになっています。これを公開日(pub_date)の新しいものから並べるように変更します。「users/models.py」に以下の記述をします。

from django.db import models

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

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

質問内容順で並べ、同じ場合は公開日の降順で並べる場合は以下のように記述します。

ordering = [‘question_text’, ‘-pubdate’]

relationのあるオブジェクト

もう一つのモデルであるChoiceを追加します。Choiceモデルは、ForeignKey(Questionモデルへのリレーション)を持っています。

①管理サイトに表示するモデルの設定やカスタマイズは、「app/admin.py」に記述します。今回はチュートリアルにならってusersアプリのQuestionモデルを追加します。

from django.contrib import admin

from .models import Question
from .models import Choice


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

②以下のURLをブラウザから開いて、Djangoの管理サイトを表示します。

http://localhost:8000/admin/

以下のように追加されます。

※ChoiceモデルはMeta設定などをしてないのでそのまま出ます。

③「Questions」→「QUESTIONを追加する」を押すとデータ追加用のフォームが表示されます。以下のようにテストデータを入力して保存します。

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

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

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

カスタマイズするときはadmin.site.reigster関数の第2引数にAdminサイトでの振る舞いを記述したクラスを渡します。このクラスはadmin.ModelAdminクラスを継承し、必要な箇所だけ自分でオーバーライドして作ります。

Inline項目の追加

ここまでの例では、QuestionとChoiceを追加したい場合以下の手順を踏んでました。

  • まず元になるQuestionを作成する。
  • QuestionをChoiceの追加ページで選択する。

ただ、ChoiceでいちいちQuestionを選択するのは面倒です。

そこで便利なのがInlineFormです。InlineFormを使えば、リレーション元のオブジェクト(Question)とリレーション先のオブジェクト(Choice)を同時に作成できます。adminサイトでは、InlineAdminというInline表示用のクラスが用意されています。

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を渡すように修正します。

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

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

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

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

②管理サイトのQuestionの追加ページ(もしくは編集ページ)を開くと、Choicesを同時に編集できるようになっているのが確認できます。

表示のカスタマイズ

一覧の属性を増やしてみます。

①表示を変えるにはadmin.ModelAdminを継承したクラス(QuestionAdmin)にlist_displayを設定します。

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

②全てのモデルはdjangoが自動的に主キーを付けてくれます。これも表示してみます。

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

引数なしメソッドを表示するカスタマイズ

list_displayには、フィールドの他にも引数なしのメソッドを設定することができます。

①以下のコードは、Questionモデルに質問が1日以内に公開されたものか確認するwas_published_recentlyメソッドを追加しています。(migrateは必要ありません。)

import datetime

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

...

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

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

...

以下の行は、真偽値(True or False)を返します。以下の条件が真(公開日が1日以内)の場合はTrue、1日を超過した場合はFalseをreturnで返します。

return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

「timezone.now() – datetime.timedelta(days=1)」は、現在から1日前の日付を表します。

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

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

以下のようにwas_published_recently属性が追加されます。

表示・オーダ条件のカスタマイズ

list_displayの対象がメソッドの場合、メソッドに属性を追加することで表示の変更やオーダ条件の設定が可能です。

①以下のように、admin_order_field、boolean、short_descriptionを設定します。

import datetime

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

...

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

    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?'

...

以下のような表示に変わります。

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

フィルター・検索フォームの追加

最後にフィルターと検索を追加します。

①以下のようにQuestionAdminにプロパティを設定します。

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

以下のような表示に変わります。

トラックバック用のURL
プロフィール

名前:イワサキ ユウタ 職業:システムエンジニア、ウェブマスター、フロントエンドエンジニア 誕生:1986年生まれ 出身:静岡県 特技:ウッドベース 略歴 20

最近の投稿
人気記事
カテゴリー
広告