Django ドキュメント 目次

revision-up-to:11321 (1.1)

Django ドキュメント

revision-up-to:17812 (1.4)

Django を使いこなすための全てがここにあります。

和訳について

このドキュメントは、 Django の標準ドキュメント の和訳です。和訳は日 本 Django ユーザ会の有志の手でメンテナンスされています。和訳に関する問 い合わせは、 Django プロジェクトのトラッカではなく 、 django-ja メ ーリングリストにお寄せください。

助けを求める

困り事ですか?手を貸しましょう!

最初のステップ

テンプレート層

オープンソースプロジェクトとしての Django

さあ始めましょう

revision-up-to:17812 (1.4)

Django は初めてですか? Web 開発全般も?なら、ここに来て正解ですね。ここに あるドキュメントを読んで、行動に移してみましょう。

Django の概要

revision-up-to:17812 (1.4)

Django は変転の激しいニュースルーム環境で開発された経緯から、よくある Web 開発タスクを迅速かつ簡単化するように設計されました。ここでは Django による データベース中心の Web アプリケーション開発をざっと見てみましょう。

このドキュメントの目的は、 Django の技術的な仕様について述べ、どのように動 作するかを理解してもらうことにあり、チュートリアルやリファレンス用ではあり ません。(とはいえ、チュートリアルもリファレンスも別に用意していますよ!) プロジェクトを作成する準備ができたら、 チュートリアルをはじめる か、 より詳細なドキュメントに読み進んで みてください。

モデルの設計

Django はデータベースなしでも使えます。とはいえ、 Django にはオブジェクト- リレーショナルマッパが付属していて、 Python コードでデータベースのレイアウ ト記述できるようになっています。

Django の データモデルシンタクス はモデルを表現 するための色々な方法を提供しています。この API には、 2 年間にわたって様々 なデータベーススキーマの問題を解決してきた実績があります。 mysite/news/models.py ファイル内に保存されるような、簡単な例を示しまし ょう:

class Reporter(models.Model):
    full_name = models.CharField(max_length=70)

    def __unicode__(self):
        return self.full_name

class Article(models.Model):
    pub_date = models.DateTimeField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter)

    def __unicode__(self):
        return self.headline

モデルのインストール

次に、Django コマンドラインユーティリティを実行し、データベース上にテーブル を自動的に生成します:

manage.py syncdb

syncdb コマンドは利用可能な全てのモデルを探し、まだ作成されてい ないテーブルがあれば作成します。

自動生成される API で楽しむ

これだけで、制約のない充実した Python API を使っ て自分のデータにアクセスできます。API はオンザフライで生成され、コードを作 成する必要はありません:

.. # Import the models we created from our "news" app

# "news" アプリで作成したモデルを import します。
>>> from news.models import Reporter, Article

.. # No reporters are in the system yet.

# まだシステム上に Reporter はひとつもありません。
>>> Reporter.objects.all()
[]

.. # Create a new Reporter.

# 新しい Reporter を作成します。
>>> r = Reporter(full_name='John Smith')

.. # Save the object into the database. You have to call save() explicitly.

# オブジェクトをデータベースに保存します。
# 明示的に save() を呼ばねばなりません。
>>> r.save()

.. # Now it has an ID.

# オブジェクトに ID が割り当てられました。
>>> r.id
1

.. # Now the new reporter is in the database.

# 作成した Reporter はデータベース上にあります。
>>> Reporter.objects.all()
[<Reporter: John Smith>]

.. # Fields are represented as attributes on the Python object.

# 各フィールドは Python オブジェクトの属性として表現されています。
>>> r.full_name
'John Smith'

.. # Django provides a rich database lookup API.

# Django は充実したデータベース検索 API を提供しています。
>>> Reporter.objects.get(id=1)
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__startswith='John')
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__contains='mith')
John Smith
>>> Reporter.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Reporter matching query does not exist.

.. # Create an article.

# Article を作成します。
>>> from datetime import datetime
>>> a = Article(pub_date=datetime.now(), headline='Django is cool',
...     content='Yeah.', reporter_id=1)
>>> a.save()

.. # Now the article is in the database.

# これで Article はデータベースに入りました。
>>> Article.objects.all()
[<Article: Django is cool>]

.. # Article objects get API access to related Reporter objects.

# Article オブジェクトから、リレーションを張っている Reporter にアクセ
# スできる API を使えるようになります。
>>> r = a.reporter
>>> r.full_name
'John Smith'

.. # And vice versa: Reporter objects get API access to Article objects.

# 逆も可能です: Reporter オブジェクトから Article オブジェクトにアクセスできます。
>>> r.article_set.all()
[<Article: Django is cool>]

.. # The API follows relationships as far as you need, performing efficient
   # JOINs for you behind the scenes.
   # This finds all articles by a reporter whose name starts with "John".

# API は必要に応じてリレーションを辿ります。背後では効率的に JOIN を
# 行います。
# "John" ではじまる Reporter の全ての Article を検索してみましょう。
>>> Article.objects.filter(reporter__full_name__startswith="John")
[<Article: Django is cool>]

.. # Change an object by altering its attributes and calling save().

# 属性値を変更して save() すればオブジェクトを変更できます。
>>> r.full_name = 'Billy Goat'
>>> r.save()

.. # Delete an object with delete().

# delete() でオブジェクトを削除できます。
>>> r.delete()

作業場 (scaffold) ではなく完成品 (whole house) の、動的な管理インタフェース

モデルを定義したら、 Django は玄人向きの実運用に耐える 管理インタフェー ス (admin interface) を自動的に生成します。 管理インタ フェースとは、認証をパスしたユーザがオブジェクトを追加、変更、削除できる Web サイトです。管理インタフェースの作成は簡単で、モデルクラスを admin に追 加するだけです:

.. # In models.py...

# models.py には以下のように書きます

from django.db import models

class Article(models.Model):
    pub_date = models.DateTimeField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter)

.. # In admin.py in the same directory...

# 同じディレクトリの admin.py には以下のように書きます

import models
from django.contrib import admin

admin.site.register(models.Article)

サイトの編集はスタッフ、顧客、もしくはあなた自身の手で行われるものであり、 コンテンツの管理だけのためにバックエンドインタフェースを作りたくはない、 という思想がここにはあります。

作者たちが Django アプリケーションを作成するときの典型的なワークフローは、 モデルを作成し、 admin サイトを組み上げてできるだけ早期に立ち上げ、スタッフ (や顧客) がデータを投入できるようにしておいてから、データを公開するための方 法を開発してゆくというものです。

自由な URL 設計

すっきりとして洗練された URL スキームは、高品質な Web アプリケーションを実 現する上で重要な要素です。 Django は美しい URL の設計を助け、 .php.asp のようなお粗末なゴミを URL に入れさせません。

特定のアプリケーション用の URL を設計するには、 URLconf と呼ばれる Python モジュールを一つ作成します。 URLconf はいわばアプリケーションの目次にあたり、 URL のパターンを Python のコールバッ ク関数に対応づけています。 URLconf はまた、 URL を Python コードと脱カップ リングする働きを持っています。

Reporter/Article の例では、 URLconf は以下のようになります:

from django.conf.urls import patterns, url, include

urlpatterns = patterns('',
    (r'^articles/(\d{4})/$', 'news.views.year_archive'),
    (r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
    (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)

上のコードは簡単な正規表現で書かれた URL を Python コールバック関数 (ビュー: view) に対応づけています。正規表現の中で丸括弧を使い、 URL から値を「取り込 み」ます。ユーザがあるページをリクエストすると、 Django は全ての正規表現に わたって順に調べてゆき、最初に URL にマッチするパターンで止まります。 (マッ チする正規表現がなければ Django は独自の 404 ビューを呼び出しします)。 正規 表現をロード時にコンパイルしておくので、この処理は極めて高速です。

正規表現が URL にマッチすると、 Django は指定されているビューを import して 呼び出します。ビューは単純な Python の関数です。各ビューにはリクエストオブ ジェクトが渡されます。リクエストオブジェクトにはリクエストのメタデータと、 正規表現で取り込んだ値が渡されます。

例えば、ユーザが “/articles/2005/05/39323/” という URL をリクエストすると、 Django は news.views.article_detail(request, '2005', '05', '39323') のような関数呼び出しを行います。

ビューの自作

各ビュー (view) には二つの役割があります: 一つはリクエストされたページのコ ンテンツを含む HttpResponse オブジェクトを返すこと、 もう一つは Http404 のような例外の送出です。それ以外の 処理はユーザ次第です。

一般的に、ビューはパラメタに従ってデータベースからデータを取り出し、テンプ レートをロードして、取り出したデータでテンプレートをレンダリングします。 上の year_archive のビューを例に示しましょう:

def year_archive(request, year):
    a_list = Article.objects.filter(pub_date__year=year)
    return render_to_response('news/year_archive.html',
                              {'year': year, 'article_list': a_list})

この例では Django の テンプレートシステム を使っ ています。テンプレートシステムは、強力な機能をいくつも備えながらも、非プロ グラマが使いこなせる程度に簡単な仕組みです。

テンプレートの設計

上のコードでは news/article_detail.html という名前のテンプレートをロー ドしています。

Django にはテンプレート検索パスという概念があり、テンプレートが冗長になるの を防いでいます。 Django の設定で、テンプレートを探すディレクトリのリストを 設定しておきます。あるディレクトリにテンプレートが見つからなければ、Django は次のディレクトリ、また次のディレクトリとテンプレートを探します。

さて、 news/year_archive.html が見つかったとしましょう。テンプレート は以下のように書かれています:

{% extends "base.html" %}

{% block title %}{{ year }}年の記事{% endblock %}

{% block content %}
<h1>{{ year }}年の記事</h1>

{% for article in article_list %}
<p>{{ article.headline }}</p>
<p>By {{ article.reporter.full_name }}</p>
<p>作成日: {{ article.pub_date|date:"F j, Y" }}</p>
{{ article.article }}
{% endfor %}
{% endblock %}

変数は二重の波括弧で囲まれています。 {{ article.headline }} は、 「article の headline という属性の出力」を表しています。とはいえ、ドット表 記は属性の検索に使われるだけではありません。辞書の検索や、インデクス指定、 関数呼び出しも行えます。

{{ article.pub_date|date:"F j, Y" }} で、 Unix スタイルの「パイプ」 (文字 “|”) を使っていることに注意して下さい. これはテンプレートフィルタ と呼ばれ、変数の値にフィルタをかけるためのものです。この例では、フィルタに よって Python の datetime オブジェクトを指定の形式にフォーマットしています (PHP の date 関数に似ていますね。そう、これは PHP の便利なところです)。

フィルタは好きなだけ連鎖させられます。カスタムのフィルタも実装できます。 カスタムのテンプレートタグを設計でき、背後で自作の Python コードを実行でき ます。

最後に、Django にはテンプレートの継承という概念があります: 継承を宣言してい るのは {% extends "base.html" %} の部分です。このタグは「まず ‘base.html’ というテンプレートをロードせよ。このテンプレートにはいくつかの ブロックが定義されているが、それらのブロックの中身を以下のブロック定義で埋 めよ」という命令です。要するに、テンプレートを継承すると、各テンプレートご とに固有の定義だけを記述すればよくなり、テンプレート間の冗長性が劇的に減る のです。

“base.html” テンプレートは以下のように書けます:

<html>
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <img src="sitelogo.gif" alt="Logo" />
    {% block content %}{% endblock %}
</body>
</html>

このテンプレートはサイトのルック & フィール (とサイトのロゴ) を定義するだけ にまで、極度に単純化されています。また、子テンプレートで埋めるための「穴」 を提供しています。これによって、ベーステンプレート一つを変更するだけでサイ ト全体のデザインを簡単に変更できます。

また、子テンプレートを変えずにベーステンプレートだけを変えた複数バージョン のサイトも作成できます。 Django の作者たちはこのテクニックを使い、新しい テンプレートを作成するだけで携帯電話向けのまったく見栄えの違うサイトを 作成してきました。

他のシステムを使いたければ、必ずしも Django のテンプレートシステムを使う必 要はないということに注意してください。 Django のテンプレートシステムは Django のモデルレイヤと部分的にしっかり組み合わさっていますが、絶対に使わね ばならないということではありません。さらに言えば、 Django のデータベース API を使う必然性もありません。別のデータベース抽象化レイヤを使っても構いま せんし、 XML ファイルやディスク上のファイルを読み込んでも構いません。何でも やりたいことをできるのです。Django の構成要素 – モデル、ビュー、テンプレー ト – は、互いに切り離して利用できるのです。

これらはほんの一部にすぎません

以上、 Django の機能についてざっと紹介してきました。 Django は他にもまだま だ便利な機能を備えています:

  • 自動生成される admin のセクシーな機能の数々。ここで紹介したのはほんの 表層の一部でしかありません。

次は、あなたが Django をダウンロード して、 チュートリアル を読み、 コミュニティ に参加す る番です。ご精読ありがとうございました!

インストールガイド

revision-up-to:17812 (1.4)

Django を動かすには、まずインストールせねばなりません。ここでは、 Django を 学んでみるにあたって必要な、簡単で最小限のインストール方法を示します。 色々なインストール方法をカバーしている 詳細なインストールガイド も用意してあります。

Python のインストール

Django は Python の Web フレームワークなので Python が必要です。 Django は バージョン 2.5 から 2.7 までの Python で動作します (Python 3.0 には以前のバー ジョンと互換性のない変更が加わっているので、 Django は現在のところ Python 3.0 で動作しません。サポートされている Python のバージョンと、 3.0 への移行 に関する情報は FAQ を参照してください)。 Python 2.5 から は、 SQLite という軽量なデータベースが付属していて、すぐにデータベースの セットアップをすることなく開発できます。

http://www.python.org から Python を取ってきましょう。 Linux や Mac OSX を 動かしているのなら、おそらくインストール済みのはずです。

Jython で Django を動かす

Jython (Java プラットフォームで動く Python 実装) を使っているなら、他 にもいくつかステップを踏む必要があります。詳しくは Jython 上で Django を動かす を参照してください。

インストールされている Python のバージョンを調べるには、シェル上で python と入力します。出力は以下のようになるでしょう:

Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>

データベースをセットアップする

バージョン 2.5 以降の Python をインストールしていれば、この節は読み飛ばして もかまいません。

バージョン 2.5 よりも前の Python を使っているか、 PostgreSQL や MySQL, Oracle といった、SQLite 以外の「大掛かりな」データベースエンジンを扱いたけ れば、 データベースのインストールに関する情報 を参照してください。

旧バージョンの Django の除去

以前のバージョンからアップグレードする形で Django をインストールする場合、 新しいバージョンをインストールする前に、まず旧バージョンをアンインス トールしておく 必要があります。

Django のインストール

3 通りの簡単な方法で、Django をインストールできます:

常に使用している Django のバージョンと一致するドキュメントを 参照するようにしてください。

上に挙げた選択肢のうち、最初の二つを選んだ場合は、ドキュメントを読む際 に「 開発版で登場した機能です 」とマークされた部分に気をつけてくだ さい。この文は、開発版の Django でのみ利用可能な機能をマークしています。 そうした機能は、公式リリースでは動かないでしょう。

確認

Django が Python から使用できるか確認するために、シェル上で python と 入力します。 Python プロンプトの中で、 Django を import してみます:

>>> import django
>>> print django.get_version()
1.4

以上です!

これだけです。さあ、 チュートリアルをやってみましょう.

はじめての Django アプリ作成、その 1

revision-up-to:17812 (1.4)

さあ、例を交えながら学んでゆきましょう。

このチュートリアルでは、簡単な投票 (poll) アプリケーションの作成に取り組ん でもらいます。

Poll アプリケーションは、

  • ユーザが投票したり結果を表示したりできる公開用サイト
  • 投票項目の追加、変更、削除を行うための管理 (admin) サイト

の二つの部分に分かれています。

Django は既にインストール済み として、説明を進めます。 Django がインストールされているかどうかは、Python 対話シェルを起動して import django を実行してみればわかります。エラーなく import できるなら、 Django はインストールされています。

困ったときは:

このチュートリアルを進めてゆく上で困ったことがあったら、 django-usersirc.freenode.net#djangoチャネル で誰か助けてくれそ うな人と話してみてください。

プロジェクトの作成

初めて Django を使うのなら、最初のセットアップを行う必要があります。通常は、 Django の プロジェクト (project) を構成するコードを自動生成 します。プロジェクトとは、データベースの設定や Django 固有のオプション、ア プリケーション固有の設定などといった、個々の Django インスタンスの設定をあ つめたものです。

コマンドラインから、コードを置きたい場所に cd して、以下のコマンドを 実行してください。

django-admin.py startproject mysite

現在のディレクトリに mysite ディレクトリが作成されます。

ディストリビューションパッケージでスクリプトの名前が違うかも

もし apt-get や yum のような Linux ディストリビューションのパッケージ マネージャを使って Django をインストールした場合、 django-admin.pydjango-admin に名前が変更されている場合があります。その場合は、 これ以降のドキュメント内で出てくるそれぞれのコマンドから .py を削除 して操作を続けてください。

Max OS X でのパーミッションに関するエラー

Mac OS X を使っている場合、 django-admin.py startproject を実行しよ うとすると、 “permission denied” というメッセージが出ることがあります。 OS X のような Unix ベースのシステムでは、ファイルをプログラムとして実行 したい場合に、ファイルに「プログラムとして実行可能」というマークをつけて おく必要があるためです。ファイルに実行可能マークをつけるには、 Terminal.app を起動して、 django-admin.py を収 めているディレクトリに ( cd コマンドで) 移動して、 sudo chmod +x django-admin.py を実行してください。

Note

プロジェクトの名前を付けるとき、組み込みの Python モジュールや Django のコンポーネントの名前を使わないようにしてください。とりわけ、 django (Django 自体と名前が衝突します) や test (組み込みの Python パッケージ名と名前が衝突します) を使わないようにしましょう。

python setup.py ユーティリティで Django をインストールしたのなら、 django-admin.py はシステムパスのどこかにあるはず です。パス上になければ、 site-packages/django/bin にあります。 site-packages は Python インストールディレクトリの中にあります。パス上 のどこか、例えば /usr/local/bindjango-admin.py へのシンボリックリンクを張って おきましょう。

コードはどこに置くの?

PHP の経験があるなら、これまでは Web サーバのドキュメントルート下 (/var/www といった場所) にコードを配置してきたことでしょう。 Django ではそうする必要はありません。むしろ Python コードをドキュメントルート 下に置くのは賢明ではありません。コードをドキュメントルート下に置くと、 誰かがコードを Web を介して読めるようになってしまうからです。これは安全 上よろしくありません。

コードはドキュメントルートの 、例えば /home/mycode の ような場所に置きましょう。

startproject が何を作成したかをみてみましょう:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py

自分のレイアウトと違う場合

デフォルトのプロジェクトのレイアウトが最近変わりました。もし、フラットな レイアウトの場合 (内側の mysite/ ディレクトリがない場合) は、この チュートリアルのバージョンとは違う Django のバージョンを使用していること でしょう。古いチュートリアルを参照するか、新しいバージョンの Django を 入手してください。

ファイルはそれぞれ以下のような役割を持っています:

  • 外側の mysite/ ディレクトリは、このプロジェクトのただの入れ物です。 名前は Django に関係しませんので、好きな名前に変更できます。
  • manage.py: Django プロジェクトに対する様々な操作を行うための コマンドラインユーティリティです。詳しくは django-admin.py と manage.py を参照してください。
  • 内側の mysite/ ディレクトリは、このプロジェクトの本当の Python パッケージです。この名前が Python パッケージの名前であり、 import の際に 使用する名前です (例えば import mysite.settings) 。
  • mysite/__init__.py: このディレクトリが Python パッケージであることを Python に知らせるための空のファイルです。(Python の初心者は、 Python の公式 ドキュメントの パッケージの詳しい説明 を読んで下さい。)
  • mysite/settings.py: Django プロジェクトの設定ファイルです。 設定の仕組みは Django の設定 を参照してください。
  • :file:mysite/urls.py: Django プロジェクトの URL 宣言、いうなれば Django サイトにおける「目次」に相当します。詳しくは URL ディスパッチャ を参照 してください。
  • mysite/wsgi.py: WSGI互換のある Web サーバでプロジェクトを動かすための エントリーポイントです。詳しくは WSGI 環境にデプロイする方法 を参照 してください。
開発用サーバ

プロジェクトがうまく動作するか確かめましょう。外側の mysite ディレク トリに移り、 python manage.py runserver を実行してください。以下のような メッセージが表示されるはずです:

Validating models...
0 errors found.

Django version 1.4, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

これで、 Django 開発サーバを起動しました。 Django 開発サーバは Python だけ で書かれた軽量な Web サーバです。このサーバは、開発を迅速に行い、運用に適し た状態になるまで Apache のような運用サーバの設定をいじらなくても良いように するためのものです。

ここでちょっと注意しておきましょう。このサーバは開発中の利用だけを考えて作 られているため、絶対に運用環境では使わないようにしてください (筆者たちの専 門は Web フレームワークであって、 Web サーバではありません)。

さあ、これでサーバが起動したので、ブラウザで http://127.0.0.1:8000/ にアク セスしてみてください。 “Welcome to Django” と表示された、明るいパステル調の ライトブルーのページが出るはずです。やったね!

ポート番号の変更

デフォルトでは、 runserver コマンドを実行すると、開発用サー バはポート番号 8000 で起動します。サーバのポート番号を変更したければ、 コマンドライン引数で指定します。例えばポート番号を 8080 にしたければ以 下のようにしてください:

python manage.py runserver 8080

サーバの IP を指定するときには、ポート番号も一緒に指定します。従って、 全ての IP からのリクエストを受け付ける (サーバを他のコンピュータから可 視にする) には、以下のようにします:

python manage.py runserver 0.0.0.0:8000

開発サーバの詳細な説明は runserver のリファレンスを参照して ください。

Database の設定

それでは、 mysite/settings.py を編集しましょう。 mysite/settings.py は Django の設定を表現する通常の Python モジュール です。 DATABASES 'default' の中の以下のキーを書き換えて、お使 いのデータベースへの接続パラメタに合わせましょう:

  • ENGINE'django.db.backends.postgresql_psycopg2', 'django.db.backends.mysql', 'django.db.backends.sqlite3' または 'django.db.backends.oracle' のいずれかです。 他にも いくつか あります。

  • NAME` – データベースの名前です。 SQLite を使っている場合には データベースファイルのフルパス (絶対パス) にします。 指定したパスのファイルが存在しなければ、 Django は最初にデータベースの同期 を実行したときにファイルを生成します (後で解説します)。

    パスを指定するときには、 Windows 環境でも必ずスラッシュ (/) を区切り文字 に使ってください (例: C:/homes/user/mysite/sqlite3.db)

  • USER – データベースのユーザ名です (SQLite では使いません)。

  • PASSWORD – データベースのパスワードです。 (SQLite では使いません)。

  • HOST – データベースのあるホストです。データベースサーバが物理的に 同じマシン上にあるのなら空文字列にしておきます。(SQLite では使いません)。

データベースをあまり扱ったことがないのなら、 ENGINE'django.db.backends.sqlite3' を指定して SQLite を使用することをお勧めしま す。 SQLite はバージョン 2.5 以降の Python に組み込まれているので、特にインス トールする必要がありません。

Note

PostgreSQL や MySQL を使っている場合、この時点でデータベースを作成して おいてください。データベースを作成するには、データベースの対話プロンプ トで “CREATE DATABASE database_name;” を実行します。

SQLite を使う場合には、予め何か作成しておく必要はありません。データベー スファイルは、必要に応じて自動的に生成されます。

settings.py を編集する際、 TIME_ZONE にタイムゾーンをセット してください。デフォルト値はアメリカのセントラルタイムゾーン (シカゴ) になり ます。また、ファイルの末尾近くにある INSTALLED_APPS 設定に注意して ください。この変数には、現在の Django インスタンスで有効な全ての Django アプリ ケーションの名前が入ります。アプリケーションは複数のプロジェクトで利用でき、 配布もできます。

デフォルトでは INSTALLED_APPS には以下のアプリケーションが入って います。これらのアプリケーションはいずれも Django に付属のものです:

これらの機能はよく使われるのでデフォルトで付属しています。

上に挙げたアプリケーションは、必ず少なくとも一つのデータベーステーブルを使 います。そこで、アプリケーションを使う前にテーブルを作成しておく必要があり ます。テーブルを作成するには以下のコマンドを使います:

python manage.py syncdb

syncdb コマンドは INSTALLED_APPS 設定を探し、 settings.py のデータベース設定に従ってデータベース上に必要なテーブ ルを作成します。コマンドが生成したデータベースを示すメッセージが表示され、 認証システムで使うスーパユーザアカウントを作成したいかどうか尋ねるプロンプ トが出ます。アカウントを作成しておきましょう。

Django がどんなテーブルを作成したか興味があるなら、データベースのコマンドラ インクライアントを使って、 \dt (PostgreSQL), SHOW TABLES; (MySQL), あるいは .schema (SQLite) と入力してみましょう。

ミニマリストのために

上で述べたように、デフォルトのアプリケーションはよくあるケースに対応す るために入っているにすぎず、誰もが必要としているわけではありません。デ フォルトアプリケーションの一部なり全部なりが必要なければ、 syncdb を実行する前に該当する行をコメントアウトするか削除し てかまいません。 syncdb コマンドは INSTALLED_APPS にあるアプリケーションのテーブルを生成しているにすぎません。

モデルの作成

さあ、これで自分用の環境、すなわちプロジェクトが立ち上がり、作業にとりかか る準備ができました。

Django で書いたアプリケーションは Python パッケージからなり、 ある規約に従っ て Python パス のどこかに置かねばなりません。Django にはアプリケーション の基本的なディレクトリ構造を作成するためのユーティリティがついてくるので、 ディレクトリの作成は気にせずコードの記述に集中できます。

プロジェクトとアプリケーション

プロジェクトとアプリケーションの違いとは何でしょうか?アプリケーション とは、実際に何らかの処理を行う Web アプリケーションを指します。例えばブ ログシステムや公開レコードのデータベース、単純な投票アプリといった具合 です。プロジェクトとは、あるウェブサイト向けに設定とアプリケーションを 集めたものです。一つのプロジェクトには複数のアプリケーションを入れられ ます。また、一つのアプリケーションは複数のプロジェクトで使えます。

このチュートリアルでは、簡単のため、投票アプリケーションを mysite ディレクトリの中に作ります。その結果、アプリケーションはプロジェクトとカッ プリングします。すなわち、 poll アプリケーション内の Python コードは mysite.polls のように参照されることになります。チュートリアルの後半では、 アプリケーションを配布用に脱カップリングする方法について議論する予定です。 アプリケーションは、 Python パス のどこにでも置くことができます。この チュートリアルでは、投票アプリケーションを manage.py ファイルのすぐ 隣に作り、 mysite のサブモジュールというより、自身のトップレベルのモジュ ールとして import できるようにします。

アプリケーションを作成するには、 manage.py と同じディレクトリに入っ て、以下のようなコマンド:

python manage.py startapp polls

を入力します。このコマンドは polls というディレクトリを作成し、その 中に以下のようにファイルを配置します:

polls/
    __init__.py
    models.py
    tests.py
    views.py

このディレクトリ構造こそが、 poll アプリケーションの全体像です。

Django でデータベース Web アプリケーションを書くための最初のステップは、モ デルの定義です。本質的には、データベースのレイアウトと、追加のメタデータの 定義です。

設計哲学

モデルは、手持ちのデータに対する唯一 (single) の決定的な (definitive) ソースです。モデルには自分が格納したいデータにとって必要不可欠なフィー ルドと、そのデータの挙動を収めます。 Django は DRY 則 に従っ ています。Django のモデルの目的は、ただ一つの場所でデータモデルを定義し、 そこから自動的にデータを取り出すことにあります。

これから開発する簡単な poll アプリケーションでは、投票項目 (poll) と選択肢 (choice) の二つのモデルを作成します。 poll には質問事項 (question) と公開日 (publication date) の情報があります。 choice には選択肢のテキストと投票数 (vote) という二つのフィールドがあります。各 choice は一つの poll に関連づけ られています。

Django では、こうした概念を簡単な Python クラスで表現できます。 polls/models.py ファイルを以下のように編集してください:

from django.db import models

class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(max_length=200)
    votes = models.IntegerField()

コードは単純明解ですね。各モデルは一つのクラスで表現され、いずれも django.db.models.Model のサブクラスです。各モデルには複数のクラス 変数があり、個々のクラス変数はモデルのデータベースフィールドを表現していま す。

各フィールドは Field クラスのインスタンスとして 表現されています。例えば、 CharField は 文字のフィールドで、 DateTimeField は日時フィー ルドです。こうしたクラスは、各フィールドにどのようなデータ型を記憶させるか を Django に教えます。

models.*Field` インスタンスの名前 (questionpub_date) はフィールドの名前で、計算機にとって扱いやすい名前を付けます。この名前は Python コードの中で使いますし、データベースではカラム名に使います。

django.db.models.Field の第一固定引数には、オプションとして人間可 読なフィールド名も指定できます。このフィールド名は Django の二つの内省 (introspection) 機能で使う他、ドキュメントとしての役割も果たします。人間可 読なフィールド名を指定しない場合、 Django は機械可読な名前を使います。上の 例では、 Poll.pub_date にだけ人間可読なフィールド名を指定しました。モデ ルの他のフィールドでは、フィールドの機械可読な名前は人間可読な名前としても 十分なので定義していません。

Field クラスの中には必須の引数を持つものがありま す。例えば CharField には max_length を指定する必要があります。この引 数はデータベーススキーマで使われる他、後で述べるバリデーションでも使われま す。

最後に、 ForeignKey を使ってリレーションが定義さ れていることに注意して下さい。このリレーションは、各 Choice が一つの Poll に関連づけられていることを Django に教えます。 Django は多対一、多対多、一 対一といった、広く使われているリレーション全てをサポートしています。

モデルを有効にする

前述のようなほんのわずかなコードをモデルに書くだけで、 Django はたくさんの 情報を手にします。このコードを使って、 Django は:

  • アプリケーションのデータベーススキーマを作成 (CREATE TABLE 文を実 行) できます。
  • Poll や Choice オブジェクトに Python からアクセスするためのデータベー ス API を作成できます。

ただし、その前に polls アプリケーションをインストールしたことをプロジェ クトに教えてやる必要があります。

設計哲学

Django アプリケーションは「プラガブル (pluggable)」です。アプリケーショ ンは特定の Django インストールに結び付いていないので、アプリケーション を複数のプロジェクトで使ったり、単体で配布したりできます。

再度 settings.py ファイルを編集して、 INSTALLED_APPS 設 定を変更し、 'polls' を入れます。以下のようになるはずです:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    # 'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'polls',
)

これで Django は polls アプリケーションが入っていることを知りました。 もう一つコマンドを実行してみましょう:

python manage.py sql polls

以下のような (polls アプリケーション用の CRATE TABLE SQL 文) が表示されるは ずです:

BEGIN;
CREATE TABLE "polls_poll" (
    "id" serial NOT NULL PRIMARY KEY,
    "question" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL
);
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id") DEFERRABLE INITIALLY DEFERRED,
    "choice" varchar(200) NOT NULL,
    "votes" integer NOT NULL
);
COMMIT;

以下の点に注意してください:

  • 実際に出力される SQL 文は、使っているデータベースによって変わります。
  • テーブル名はアプリケーションの名前 (polls) とモデルの小文字表記 (poll および choice) を使って自動的に生成されます (この挙動は オーバライドできます。)
  • 主キー (primary key, ID) は自動的に生成されます (この挙動もオーバライ ド可能です)
  • 便宜上、 Django は外部キーのフィールド名に "_id" を追加します。も ちろんこの挙動もオーバライド可能です。
  • 外部キーのリレーションは REFERENCES 文で明示的に作成されます。
  • SQL 文は使っているデータベースに応じて細かく調整されます。従って、 auto_increment (MySQL)、 serial (PostgreSQL)、 integer primary key (SQLite) といったデータベース固有のフィールド タイプは自動的に指定されます。クオートの仕方、すなわち一重と二重のど ちらの引用符を使うか、といったことも自動で調整します。このチュートリ アルの作者は PostgreSQL を使っており、例題での出力は PostgreSQL の文 法に準じています。
  • sql コマンドを実行しても、実際にデータベースで SQL を実行 するわけではありません。 sql コマンドは、ユーザが Django の挙動を 知りたいと考えたときのため、単に SQL 文をスクリーンに表示しているだけ です。必要なら、この SQL 文をコピーしてデータベースクライアントのプロ ンプトにペーストできますが、後ですぐ述べるように、 Django では SQL を データベースに commit させる簡単な方法を提供しています。

興味があるなら、以下のコマンドも実行してみてください:

  • python manage.py validate – モデルの構成にエ ラーがないか調べます。
  • python manage.py sqlcustom polls – 各アプリケー ション向けに定義しておいた、カスタマイズ (テーブル形式の変更や制約) 用の SQL 文を出力します。
  • python manage.py sqlclear polls – アプリケーショ ン用のテーブルのうち、データベース上に存在するものについて必要に応じ て DROP TABLE 文を出力します。
  • python manage.py sqlindexes polls – アプリケー ション用の CREATE INDEX 文を出力します。
  • python manage.py sqlall polls – ‘sql’, ‘sqlcustom’, ‘sqlindexes’ コマンドを合わせたものです。

これらのコマンドの出力を見れば、水面下で実際に行われていることを理解する助 けになるでしょう。

syncdb を再度実行して、モデルテーブルをデータベース上に作成しま しょう:

python manage.py syncdb

syncdb コマンドは INSTALLED_APPS に登録されているアプ リケーションのうち、データベース上にまだ存在しないものに対して sqlall で生成した SQL を生成します。これによって、最後に syncdb を実行した時以後に新たにプロジェクトに追加されたアプリケー ションのテーブルと初期データ、インデクスを生成します。 syncdb はその都度存在しないテーブルだけを生成するので、繰り返し実行してもかまいま せん。

manage.py ユーティリティでできることについては django-admin.py のドキュメント を読んで下さい。

API で遊んでみる

さて、Python 対話シェルを起動して、 Django が提供する API で遊んでみましょ う。 Python シェルを起動するには、以下のコマンドを実行します:

python manage.py shell

単に “python” を実行しないのは、 Django に settings.py ファイルへの import パスを与える DJANGO_SETTINGS_MODULE の環境変数を manage.py で設定しているからです。

manage.py を使わずに済ませる方法

manage.py を使いたくなくても、問題はありません。環境変数 DJANGO_SETTINGS_MODULEmysite.settings に設定して、 manage.py と同じディレクトリで python を実行してください (または import mysite が通るように、ディレクトリが Python のパス上 にあるようにしてください) 。

詳しくは django-admin.py のドキュメント を参 照してください。

シェルに入ったら、 データベース API の世界を探検 してみましょう:

>>> from polls.models import Poll, Choice # モデルクラスを import します。

# まだ Poll は一つもできていません。
>>> Poll.objects.all()
[]

# 新たな Poll を作成しましょう。
# デフォルト設定ファイルでタイムゾーンへのサポートが使用可能になって
# いるので、 Django は pub_date に対して tzinfo を伴った datetime を
# 期待します。 datetime.datetime.now() の代わりに timezone.now() を使用
# してください。
>>> from django.utils import timezone
>>> p = Poll(question="What's new?", pub_date=timezone.now())

# 出来たオブジェクトをデータベースに保存します。 save() は明示的に呼ば
# ねばなりません。
>>> p.save()

# これでオブジェクトに ID が割り当てられました。お使いのデータベースに
# よっては、この値は "1" ではなく "1L" のときもあります。心配することは
# ありません。単にデータベースバックエンドが Python 長整数型で値を返す
# ようになっているだけのことです。
>>> p.id
1

# データベースの各カラムに Python の属性としてアクセスします。
>>> p.question
"What's new?"
>>> p.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# 属性を変更して save() を呼び出すとカラムの値を変更します。
>>> p.question = "What's up?"
>>> p.save()

# objects.all() はデータベース上の全ての Poll を返します。
>>> Poll.objects.all()
[<Poll: Poll object>]

おっと、ちょっと待って下さい。 <Poll: Poll object> なんて全然親切な表現 ではありませんね。そこで (polls/models.py ファイルに定義されている) polls 関係のモデルを少し修正して、 PollChoice__unicode__() メソッドを追加しましょう:

class Poll(models.Model):
    # ...
    def __unicode__(self):
        return self.question

class Choice(models.Model):
    # ...
    def __unicode__(self):
        return self.choice

__unicode__() をモデルに追加しておく重要性は、 対話プロンプトで扱うときに精神的によいだけでなく、Django が自動生成する管理 インタフェースのいたるところでオブジェクトの表現 (representation) が使われ ているという点にもあります。

なぜ __str__() ではなく __unicode__() を使うの?

Python に詳しければ、普段は __str__() で はなく __unicode__() を実装していることで しょう。 __unicode__() を使うのは、Django のモデルがデフォルトで Unicode を扱うからです。 Django では、データベー ス上に保存された文字列の情報は、取り出すときに全て Unicode 型に変換され ます。

Django のモデルは、デフォルトで __str__() メソッドを実装していて、中で __unicode__() を呼び出して、得た結果を UTF-8 のバイト文字列に変換しています。従って、 unicode(p) は Unicode 文字列を返し、 str(p) は UTF-8 でエンコードされた通常の文字 列を返します。この仕様がよくわからなければ、とにかく __unicode__() をモデルに追加するのだと覚 えておいてください。なにはともあれ、それでうまく動作します。

__unicode__() は通常の Python メソッドという ことに注意してください。デモ用にカスタムのメソッドを追加してみましょう:

import datetime
from django.utils import timezone
# ...
class Poll(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

import datetimefrom django.utils import timezone で Python の 標準モジュール datetime と Django のタイムゾーン関連ユーティリティの django.utils.timezone を参照していることに注意してください。もし Python でタイムゾーンを取り扱うことに不慣れな場合は、 タイムゾーン で勉強できます。

python manage.py shell を実行して、Python 対話シェルに戻りましょう:

>>> from polls.models import Poll, Choice

# __unicode__() がきちんと働いていることを確認します。
>>> Poll.objects.all()
[<Poll: What's up?>]

# Django は様々なデータベース照合 API を提供しています。 API はキーワー
# ド引数で隅々まで操作できます。
>>> Poll.objects.filter(id=1)
[<Poll: What's up?>]
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]

# 2012 年の Poll を取り出しましょう。
>>> Poll.objects.get(pub_date__year=2012)
<Poll: What's up?>

>>> Poll.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Poll matching query does not exist.
>>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>]

# 主キーの照合はよくあることなので、 Django は主キーの厳密一致を照合
# するショートカットを提供しています。
# 以下の実行文は Poll.objects.get(id=1) と同じです。
>>> Poll.objects.get(pk=1)
<Poll: What's up?>

# カスタムメソッドが動作するか確かめてみましょう。
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_recently()
True

# Poll に二つの Choice を指定しましょう。 create を呼び出すと、新たな
# Choice オブジェクトを生成し、 INSERT 文を実行し、 Poll からアクセス可
# 能な Choice オブジェクトの集合に追加して、新たに作成された Choice オ
# ブジェクトを返します。 Django は API を通してアクセス出来る "あちら側"
# の外部キー (例えば poll の choice) を保持する set を作ります。
>>> p = Poll.objects.get(pk=1)

# 関連するオブジェクトの set から choice を表示します。現在は空です。
>>>> p.choice_set.all()
[]

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

# Choice オブジェクトは自分に関連づけされた Poll オブジェクトに
# アクセスするための API を備えています。
>>> c.poll
<Poll: What's up?>

# 逆も行えます: Poll オブジェクトから Choice オブジェクトにアクセスでき
# ます。
>>> p.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> p.choice_set.count()
3

# API は必要に応じて自動的にリレーションを追跡します。リレーションを辿
# るには二重アンダースコアを使います。この表記法には制限がなく、何段階
# でも連鎖できます。以下の例では、 pub_date が 2012 の全ての Poll に関
# 連づけられている Choice を返します。
>>> Choice.objects.filter(poll__pub_date__year=2012)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]

# choice を一つ削除しましょう。 delete() を使います。
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
>>> c.delete()

リレーションモデルの詳細は、 リレーションオブジェクトリファレンス を 参照してください。 API を通じたフィールドの照合のためのダブルアンダースコア の使い方の詳細は、 フィールドの照合 を参照してください。 データベース API の詳細は、 データベース API リファレンス を参照してください。

API を使いこなせるようになったら、 チュートリアルその 2 に進んで、Django が自動生成 する管理インタフェースを動かしてみましょう。

はじめての Django アプリ作成、その 2

revision-up-to:17812 (1.4)

このチュートリアルは チュートリアルその 1 の続き です。ここでは、引続き Web 投票アプリケーションの開発を例にして、Django が 自動生成する管理サイト (admin) を中心に解説します。

設計哲学

コンテンツの追加や変更、削除を行うためのスタッフや顧客向けの管理サイト 構築は、創造性の欠けた退屈なものです。そこで、 Django ではモデルを管 理するためのインタフェース生成を完全に自動化しています。

Django はニュースルーム環境で開発されました。ニュースルーム環境では、 「コンテンツの作成者 (content publisher) 用」と「公開用 (public) 」サイ トをきわめて明確に区別しています。サイト管理者は新たな話題やイベント、 スポーツのスコアなどの入力に使い、コンテンツは公開用サイト上で表示され ます。 Django は、サイト管理者向けの一元化されたコンテンツ編集インタフェー スの提供という問題を解決しているのです。

admin は一般のサイト訪問者に使ってもらうためのものではなく、サイト管理 者のためのものです。

管理サイトの有効化

デフォルトでは、 Django の管理サイトは無効化されていて、自分で選択して有効 にせねばなりません。 admin を有効にするには、以下の 3 つの作業が必要です:

  • INSTALLED_APPS 設定の "django.contrib.admin" をコメント アウトを解除します。

  • python manage.py syncdb を実行します。新たなアプリケーションを INSTALLED_APPS に追加したので、データベースを更新せねばな りません。

  • mysite/urls.py ファイルを編集し、 admin に関連する3行のコメントアウト を解除します。このファイルは URLconf といいます。 URLconf についてはチュー トリアルの次の部で解説します。今はただ、この設定が URL をアプリケーション に対応づけていることだけを覚えておきましょう。最終的に、 urls.py は 以下のようになるはずです:

    from django.conf.urls import patterns, include, url
    
    # Uncomment the next two lines to enable the admin:
    from django.contrib import admin
    admin.autodiscover()
    
    urlpatterns = patterns('',
        # Examples:
        # url(r'^$', '{{ project_name }}.views.home', name='home'),
        # url(r'^{{ project_name }}/', include('{{ project_name }}.foo.urls')),
    
        # Uncomment the admin/doc line below to enable admin documentation:
        # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
    
        # Uncomment the next line to enable the admin:
        url(r'^admin/', include(admin.site.urls)),
    )
    

    (太字の行はコメントを外した部分です)

開発サーバの起動

開発用サーバを起動して、管理サイトを探検してみましょう。

チュートリアルその 1 で、開発サーバを以下のように起動したのを思い出してくだ さい:

python manage.py runserver

次はブラウザを起動して、ローカルドメインの “/admin/” 、つまり http://127.0.0.1:8000/admin/ にアクセスします。以下のような admin のログイ ン画面が表示されるはずです:

Django 管理サイトのログイン画面

自分の画面と違う場合

もしこの時点で、上のログイン画面の代わりに以下のようなエラーの画面が 表示された場合は:

ImportError at /admin/
cannot import name patterns
...

おそらくこのチュートリアルのバージョンとは違う Django のバージョンを 使用していることでしょう。古いチュートリアルを参照するか、新しいバー ジョンの Django を入手してください。

管理サイトに入る

さあログインしてみましょう。(チュートリアルその 1 で、スーパユーザのアカウ ントを作成したはずです。覚えていますか?) ログインしたら、管理サイトのインデ クスページが表示されるはずです:

Django 管理サイトのインデクスページ

「グループ (Groups)」や「ユーザ (Users)」、「サイト (Sites)」といった編集 可能なコンテンツが表示されるはずです。これらはデフォルトで Django に付属し ているコアの機能です。

Poll モデルを admin 上で編集できるようにする

ところで、 polls アプリケーションはどこにあるんでしょう? admin のインデ クスページを見ても表示されていませんね。

実は、まだ一つやるべきことが残っていました。 admin に Poll モデルがイ ンタフェースを持つことを教える必要があるのです。 polls ディレクトリに admin.py ファイルを追加して、以下のように編集してください:

from polls.models import Poll
from django.contrib import admin

admin.site.register(Poll)

admin のページをリロードして、どんな変化が起きたか見てみましょう。通常、 開発サーバはプロジェクトを自動的にリロードしてくれるので、コードに加えた変 更はただちにブラウザで確認できます。

admin の機能を探究してみる

Poll モデルを登録したので、 Django は Poll を管理サイトに表示するよ うになりました:

Django 管理サイトに Poll が表示されるようになった

「Polls」 をクリックしてみてください。 チェンジリスト (change list) のペー ジに入ります。このページはデータベース上の全ての Poll オブジェクトを表 示していて、変更したいオブジェクトを選択できます。前のチュートリアルで作成 した 「What’s up」という Poll オブジェクトがありますね。

Poll のチェンジリストページ

「What’s up?」をクリックして編集してみましょう:

Poll オブジェクトの編集

以下の点に注意してください:

  • フォームは Poll モデルをもとに自動的に生成されています。
  • モデルのフィールドの型によって ( DateTimeField, CharField などの) 適切な HTML 入力ウィジェッ トが対応しています。各タイプのフィールドには、 Django 管理サイトでデー タを表示する方法が定義されています。
  • DateTimeField には JavaScript のショートカッ トがついています。日付 (Date) のカラムには「今日 (Today)」へのショート カットと、カレンダーのポップアップボタンがあります。時刻 (Time) のカラ ムには「現在 (Now)」へのショートカットと、よく入力される時間のリストを 表示するポップアップボタンがあります。

ページの末尾の部分には操作ボタンがいくつか表示されています:

  • 保存 (Save) – 変更を保存して、このモデルの変更リストのページに戻ります。
  • 保存して編集を続ける (Save and continue editing) – 変更を保存して、こ のオブジェクトの編集ページをリロードします。
  • 保存してもう一つ追加 (Save and add another) – 変更を保存して、このモデ ルのオブジェクトを新規追加するための空の編集ページをロードします。
  • 削除 (Delete) – 削除確認ページを表示します。

もし「Date published」の値がチュートリアル 1 で作成した時間と違う場合は、 TIME_SONE に現在のタイムゾーンの設定をし忘れた可能性があります。 変更し、リロードして正しい値が表示されるか確認してください。

「今日」や「現在」ショートカットをクリックして、「Date published」を変更し てみましょう。変更したら、「保存して編集を続ける」を押します。次に、右上に ある「履歴 (History)」をクリックしてみましょう。ユーザが管理サイト上でオブ ジェクトに対して行った全ての変更履歴を、変更時刻と変更を行ったユーザの名前 つきでリストにしたページを表示します:

Poll オブジェクトの変更履歴

管理サイトフォームのカスタマイズ

しばらく操作してみましょう。これだけの機能をコードを書かずに実現したこ とに驚くはずです。 admin.site.register(Poll) の呼び出しによって、 Django はオブジェクトの表示方法を「推測」し、管理サイトでモデルの編集を行え るようにします。管理サイトの表示や挙動を少し変えたい場合には、モデルを登録 するときにオプションを指定します。

試しに、編集フォームでのフィールドの並び順を並べ替えてみましょう。 admin.site.register(Poll) の行を以下のように置き換えてみてください:

class PollAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question']

admin.site.register(Poll, PollAdmin)

このように、 admin のオプションを変更したいときには、モデルごとに admin オブジェクトを生成して、 admin.site.register() の 2 番目の引数に渡すと いうパターンを使ってください。

上の例では、「Publication date」フィールドの表示位置を「Question」フィール ドよりも前に変更しています。

フィールドの並び順を変えた場合

二つしかフィールドがないので、あまりぱっとした変化ではありませんね。しかし admin フォームで何ダースものフィールドを操作するような場合には、直感的なフィー ルドの並び順というものはユーザビリティ上重要な要素です。

同じく何ダースもフィールドがある場合、フォームを複数のフィールドセットに分 割したいこともあるでしょう:

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date']}),
    ]

admin.site.register(Poll, PollAdmin)

fieldsets の各タプルの先頭の要素はフィールドセットのタイトルです。 フォームは以下のように表示されます:

フィールドセットでフォームを表示

各フィールドセットには任意の HTML クラスを指定できます。 Django では "collapse" というクラスを提供していますが、このクラスを指定すると、フィー ルドセットは最初折り畳まれた状態で表示されます。これは普段は使わないフィー ルドがたくさんあるようなフォームを使っている場合に便利です:

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
フィールドセットが最初は折畳みで表示されている

リレーションを張ったオブジェクトの追加

OK、 Poll の管理サイトページはできました。しかし Poll は複数の Choice を持つのに、管理サイトページには表示されていませんね。

今のところは。

この問題の解決法は二つあります。一つ目は、 Poll と同様、以下のようにし

Choice モデルを管理サイトに登録するというものです:

from polls.models import Choice

admin.site.register(Choice)

これで、 Django の管理サイト上で「Choice」 を選べます。「Choice の追加」フォーム は以下のようになります:

管理サイトでの Choice の表示

このフォームでは「Poll」フィールドは選択ボックスで、データベース上の全ての Poll オブジェクトを選ます。 Django は ForeignKey を表示する時には <select> ボックスを使わねばならないということを知って いるのです。今の時点では、 Poll はデータベース上に一つしかないはずですね。

Poll フィールドの隣に「もう一つ追加 (Add Another)」リンクがあるのに注意して ください。 ForeignKey の関係にあるオブジェクトなら、何もしなくてもこのリン クが表示されます。「もう一つ追加」をクリックすると、「Poll を追加 (Add Poll)」というポップアップウィンドウを表示します。このウィンドウで Poll を追 加して「保存」を押すと、 Django は Poll をデータベースに保存して、もとの 「Choice の追加」フォームに選択済みの項目として動的に追加します。

しかし、この方法は Choice オブジェクトをシステムに追加するには効率的ではあ りません。むしろ、 Poll オブジェクトを追加する時に Choice をひと揃い追加出 来た方が便利ですよね。そうしてみましょう。

Choice モデルに対する register() を削除して、 Poll を登録する部分を 以下のように書き換えてください:

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

class PollAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]

admin.site.register(Poll, PollAdmin)

この行は Django に対して、「Choice オブジェクトは Poll の管理ページから編集 する。デフォルトでは、 3 つの Choice を表示するのに十分なフィールドを用意す ること」と指示しています。

「Poll を追加」ページをロードして、どんな表示になったか見てみましょう。開発 サーバをリスタートする必要があるかもしれません:

「Poll を追加」ページに選択肢が表示された

変わった点をみてみましょう。リレーション相手である Choice を表示するために 3 つのスロットがあります (extra に指定した数ですね)。また、作成済みのオ ブジェクトを「編集する」ページに行けば、いつでも 3 つ余分のスロットが表示さ れるはずです。

さて、このコードにはちょっと問題があります。というのも、 Choice オブジェク トを入力するためのフィールドを全部表示しようとすると、相当な広さのスクリー ンが必要だからです。そこで、 Django にはテーブルを使ってインラインでリレー ション相手のオブジェクトを表示するもう一つの方法があります。以下のように、 ChoiceInline の宣言を変更してください:

class ChoiceInline(admin.TabularInline):
    #...

StackedInline に変わって TabularInline を使うと、 リレーション相手のオブジェクトはよりコンパクトなテーブル形式で表示されます:

「Poll を追加」ページの選択肢がコンパクトになった

管理サイトのチェンジリストページをカスタマイズする

さあ、これで Poll の管理ページはだいぶよくなってきました。今度は「チェンジ リスト」ページをすこしいじりましょう。チェンジリストは、システム上の全ての Poll を表示するページです。

作業前のチェンジリストのページは以下のように表示されています:

Poll のチェンジリストページ

デフォルトでは、 Django はオブジェクトの str() を表示しますが、各フィー ルドの値も表示されていると便利でしょう。表示させるには list_display オ プションを使います。 このオプションには、カラム表示したいフィールドの名前を タプルにして指定します:

class PollAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question', 'pub_date')

おまけとして、チュートリアル 1 で定義したカスタムメソッド was_published_recently も追加してみましょう:

class PollAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question', 'pub_date', 'was_published_recently')

これで、 Poll のチェンジリストのページは以下のようになります:

カスタムメソッドのカラムを追加した Poll のチェンジリスト

カラムのヘッダをクリックすると、カラムの値に応じてエントリを並べ換えできま す。ただし was_published_recently ヘッダは例外で、これはメソッドの戻り値を 使った並べ換えをサポートしていないからです。 was_published_recently のカラ ムヘッダのデフォルト値がメソッドの名前になっている (アンダースコアは空白に 置き換わっている)こと、各行が戻り値の文字列となっていることにも注意して下さい。

以下の属性を (models.py の中の) メソッドに与えることで、これを改良出来ま す:

class Poll(models.Model):
    # ...
    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.py ファイルを編集し、もう一点、 Poll のチェンジリストを改良して、フィル タをを加えます。以下の行を PollAdmin の中に入れます:

list_filter = ['pub_date']

これで、「フィルタ (Filter)」サイドバーができ、チェンジリストを pub_date フィールドの値に従ってフィルタできるようになります:

Poll のチェンジリストをさらに改良

表示されるフィルタのタイプは、フィルタに使うフィールドのタイプによって変わ ります。 pub_dateDateTimeField なので、 Django はデフォルトのフィルタのオプションとして 「すべての日 (Any date)」、「今日 (Today)」、「過去 7 日間 (Past 7 days)」、 「今月 (This month)」そして「今年 (This year)」を与えればよいと考えます。

細工は隆々ですね。こんどは検索機能を追加してみましょう:

search_fields = ['question']

これで変更リストの上部に検索ボックスが表示されます。ユーザが検索語を入力 すると、 Django は question フィールドを検索します。フィールドはいくつ でも使えますが、舞台裏では LIKE クエリを使っているので、データベースに 負荷をかけないためには常識的な検索語を指定しましょう。

最後に、 Poll オブジェクトには日付データがあるので、日付を使って絞り込める と便利なはずです。以下の一行を追加しましょう:

date_hierarchy = 'pub_date'

これで、日付を使った階層的なナビゲーションが変更リストページの上部に追加さ れます。トップレベルでは、エントリのある年を表示します。その下は月になって いて、最後は日ごとにエントリを表示します。

さて、変更リストには何もしなくてもページ分割機能がある、ということをここで お知らせしておいた方がよいでしょう。デフォルトではページあたり 100 個の要素 を表示します。ページ分割、検索ボックス、フィルタ、日付による階層化、カラム ヘッダを使った並べ換えといった変更リストの機能は、すべてが協調して思いのま まに動作するのです。

管理サイトのルック & フィールをカスタマイズする

管理サイトの上部には「Django 管理 (Django adminstration)」と表示されてい ますが、これはいささか滑稽ですね。これは単なるプレースホルダテキストにすぎ ません。

変更するのは簡単で、 Django のテンプレートシステムを使います。 Django の 管理サイトは、それ自身 Django で作られているので、インタフェースは Django のテンプレートシステムを使っているのです。

設定ファイル (mysite/settings.py でしたよね) を開いて、 TEMPLATE_DIRS という設定を探して下さい。 TEMPLATE_DIRS はファイルシステム上のディレクトリ名からなるタプル で、 Django テンプレートをロードするときに探す場所を指定します。つまり検索 パスです。

デフォルトでは、 TEMPLATE_DIRS には何も指定されていません。一行 追加して、Django に自作テンプレートの置き場所を教えましょう:

TEMPLATE_DIRS = (
    '/home/my_username/mytemplates', # 自分の環境に合わせて変更してください。
)

Django のソースコードの中にある admin アプリケーションのデフォルトのテンプ レート置場 (django/contrib/admin/templates) から、 admin/base_site.html というテンプレートをコピーして、 TEMPLATE_DIRS 上の admin というディレクトリ下に置きます。例え ば、 TEMPLATE_DIRS"/home/my_username/mytemplates" と設定 していれば、 django/contrib/admin/templates/admin/base_site.html/home/my_username/mytemplates/admin/base_site.html にコピーします。 admin というサブディレクトリを作るのを忘れないようにして下さい。

ファイルを編集して、 Django と書かれた部分を自分のサイトに合わせて変更して ください。

テンプレートファイルは、 {% block branding %}{{ title }} といっ たテキストを多く含みます。 {%{{ タグは Django のテンプレート言語 のうちの一つです。 Django が admin/base_site.html を読み込んだ時、この テンプレート言語が評価され、最終的な HTML ページが作られます。今の時点でテ ンプレートについて理解できなくても心配しないでください。テンプレート言語に ついてはチュートリアルその 3 で詳しく掘り下げていきます。

admin アプリケーションのデフォルトのテンプレートはどれもオーバライド可能で す。テンプレートをオーバライドするには、 base_site.html と同じ、つまり デフォルトのディレクトリからカスタムディレクトリにコピーして編集するという 手順をとってください。

賢明な読者はこう疑問に思うでしょう:「 TEMPLATE_DIRS はデフォルト で何も指定していないのに、 Django はどうしてデフォルトのテンプレートを捜し 当てられるのだろう?」答えは、「デフォルトでは、 Django はテンプレートが見 つからない場合、自動的に各アプリケーションパッケージの templates/ サブ ディレクトリ下を探すようフォールバックるようになっている」です。詳しくは テンプレートローダタイプの解説 を参照してください。

管理サイトインデクスページのカスタマイズ

もしかすると、同じようにして Django admin サイトのインデクスページのルック & フィールをカスタマイズしたくなるかもしれませんね。

デフォルトでは、インデクスページは INSTALLED_APPS 設定に登録され ていて、 admin アプリケーションに登録されている全てのアプリケーションをアル ファベット順に表示します。レイアウトはどのようにも変更できます。なんにせよ、 インデクスページというものは admin で最も重要なページであり、簡単に使えなけ ればならないはずです。

カスタマイズすべきテンプレートは admin/index.html です (前節の admin/base_site.html の場合と同じように、デフォルトのディレクトリからカ スタムテンプレート置場のディレクトリにコピーしてください)。ファイルを開くと、 app_list というテンプレート変数が見つかるはずです。この変数に、インス トール済みの全てのアプリケーションが入っています。この変数の代りに、特定の オブジェクトごとに admin ページのリンクをハードコードすれば、自分の思い通り に変更できます。繰り返しますが、もしテンプレート言語について理解できなくて も心配しないで下さい。チュートリアルその 3 でテンプレート言語について扱って いきます。

admin サイトを使いこなせるようになったら、 チュートリアルその 3 に進んで、 poll アプリケーショ ンの公開用ビュー作成にとりかかりましょう。

はじめての Django アプリ作成、その 3

revision-up-to:17812 (1.4)

このチュートリアルは チュートリアルその 2 の続き です。ここでは、引続きWeb 投票アプリケーションの開発を例にして、公開用のイ ンタフェース、ビュー(view) の作成を焦点に解説します。

ビューの設計哲学

ビューとは、 Django のアプリケーションにおいて特定の機能を提供するウェブペー ジの「型 (type)」であり、独自のテンプレートを持っています。例えばブログアプ リケーションなら、以下のようなビューがあるでしょう:

  • Blog ホームページ – 最新のエントリをいくつか表示します。
  • エントリの「詳細」ページ – 一つのエントリへの恒久リンク (permalink) ページです。
  • 年ごとのアーカイブページ – エントリのある年を表示します。
  • 月ごとのアーカイブページ – ある年のエントリのある月を表示します。
  • 日ごとのアーカイブページ – ある月のエントリのある日を表示します。
  • コメント投稿 – あるエントリに対するコメントの投稿を受け付けます。

Poll アプリケーションの場合には、以下の 4 つのビューを作成します:

  • Poll の「アーカイブ」ページ – 最新の調査項目 (poll) をいくつか表示し ます。
  • Poll の「詳細」ページ – 調査項目と投票用フォームを表示します。開票結 果は表示しません。
  • Poll の「開票結果」ページ – ある調査項目に対する結果を表示します。
  • 投票ページ – ある調査項目のある選択肢に対する投票を受け付けます。

Django では、各ビューは簡単な Python の関数として表現されます。

URL スキームの設計

ビューを書く上での最初のステップは、 URL 構造の設計です。 URL 構造を定義す るには、 URLconf と呼ばれる Python モジュールを作成します。 Django は URLconf を使ってどの URL をどの Python コードに関連づけるかを決めています。

ユーザが Django で作られたページをリクエストすると、システムは ROOT_URLCONF 設定を探します。この設定には Python モジュールをドッ ト表記で表した文字列が入っています。 Django は指定されたモジュールをロード して、 urlpatterns という名前のモジュールレベル変数を探します。 urlpatterns は以下のような形式のタプルからなるシーケンスです:

(正規表現, Pythonのコールバック関数,  [, オプションの辞書オブジェクト])

Django は先頭のタプルから順に、リクエストされた URL とタプル内の正規表現が マッチするまでテストしてゆきます。

マッチする正規表現が見つかると、Django は該当するタプルに指定されているコー ルバック関数を呼び出します。コールバック関数には HttpRequest オブジェクトを第一引数として渡します。 さらに、正規表現内で「キャプチャした (captured)」値をキーワード引数として渡 します。(タプルの三番目の要素である) オプションの辞書オブジェクトが指定され ていれば、その内容も追加のキーワード引数として渡します。

HttpRequest` オブジェクトの詳細は リクエストオブジェクトとレスポンスオブジェクト を参照してください。 URLconf の詳細は URL ディスパッチャ を参照してください。

チュートリアルその 1 の冒頭で python django-admin.py startproject mysite を実行していれば、URLconf が mysite/urls.py にできているはずです。また、(settings.py の) ROOT_URLCONF 設定にも、自動的に値が入ります:

ROOT_URLCONF = 'mysite.urls'

さて、例題を使って練習する時が来ました。 mysite/urls.py を編集して、 以下のような内容にしましょう:

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^polls/$', 'polls.views.index'),
    url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
    url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
    url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
    url(r'^admin/', include(admin.site.urls)),
)

復習しておいたほうがよいですね。だれかが Web サイトのあるページ、例えば “/polls/23” をリクエストすると、 Django は ROOT_URLCONF に書かれている この Pythonモジュールをロードします。Django はモジュール内の urlpatterns という変数を探し、その中に入っている正規表現を順に検査して ゆきます。マッチする正規表現が見つかった (r'^polls/(?P<poll_id>\d+)/$' ですね) ところで、 Django はこの正規表現に関連づけられている Python パッケー ジ/モジュールである detail()polls/views.py からロードし ます。これは最後に、 Django は以下のような引数で detail() を呼び出し ます:

detail(request=<HttpRequest object>, poll_id='23')

poll_id='23' の部分は、 (?P<poll_id>\d+) からきています。パターンを 丸括弧で囲うと、パターンにマッチしたテキストを「キャプチャ」して、ビュー関 数の引数として送り込みます。 ?P<poll_id> はマッチしたパターンを識別する ための名前をつけています。 \d+ は数字の列 (すなわち番号) にマッチする正 規表現です。

URL パターンは正規表現なので、正規表現で実現できる限り無制限の URL を表現で きます。また、 .php のようなくだらない文字列を URL に追加する必要もあり ません。ただし、病的なユーモアの持ち主のために、以下のようにすれば実現でき ることは示しておきましょう:

(r'^polls/latest\.php$', 'polls.views.index'),

とはいえ、こんな阿呆なことはやめましょう。

これらの正規表現では GET や POST のパラメタ、またドメイン名を検索しないこと に注意してください。例えば、 http://www.example.com/myapp/ というリクエ ストが来ると、 URLconf は /myapp/ を探します。 http://www.example.com/myapp/?page=3 の場合にも、 URLconf は /myapp/ を探します。

正規表現をよく理解できないなら、 Wikipedia のエントリre モジュ ールのドキュメントを参照してください。また、オライリーから出版されている本、 「詳説 正規表現」 (Jeffrey Friedl 著、 訳注: 田和 勝 訳) に秀逸な解説が あります。

最後に、パフォーマンスについての注意です: 正規表現は URLconf モジュールをロー ドする時にコンパイルされ、極めて高速に動作します。

はじめてのビュー作成

さてと、まだビューを作っていませんね。まだ URLconf しかありません。しかし、 まずは Django が URLconf を正しく理解できているか調べておきましょう。

Django 開発サーバを起動してください:

python manage.py runserver

Web ブラウザで “http://localhost:8000/polls/” に行ってみましょう。以下のよ うなメッセージの入った綺麗に彩られたエラーページが表示されるはずです:

ViewDoesNotExist at /polls/

Could not import polls.views.index. View does not exist in module
polls.views.

このエラーは、まだ index() という関数を polls/views.py に書いていな いために発生しています。

“/polls/23/” や “/polls/23/results/” 、 “/polls/23/vote/” も試して下さい。 エラーメッセージから、 Django がどのビューを試した (そしてまだビューを書い ていないので失敗した) かがわかります。

いよいよ最初のビューを書きましょう。 polls/views.py というファイ ルを開いて、以下のような Python コードを書いてください:

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the poll index.")

最も単純なビューです。ブラウザで “/polls/” にアクセスすると、テキストが表示 されるはずです。

もう少しビューを追加しましょう。これらのビューはさきほどと少し違って、引数 をとります (この引数には、URLconf の正規表現内でキャプチャされたものが渡さ れます):

def detail(request, poll_id):
    return HttpResponse("You're looking at poll %s." % poll_id)

def results(request, poll_id):
    return HttpResponse("You're looking at the results of poll %s." % poll_id)

def vote(request, poll_id):
    return HttpResponse("You're voting on poll %s." % poll_id)

ブラウザを使って “/polls/34/” を見てください。これは detail() メソッドを 呼びだし、 URL に指定した ID を表示します。 “/polls/34/results/” と “/polls/34/vote/” を見てください。それぞれ開票結果ページと投票ページを表示 します。

実際に動くビューを作成する

各ビューは、リクエストされたページのコンテンツが入った HttpResponse オブジェクトを返すか、 Http404 のような例外を送出するかの 2 つの動作のうち、い ずれかを実行せねばなりません。それ以外の処理は全てユーザにゆだねられていま す。

ビューはデータベースからレコードを読みだしても、読み出さなくてもかまいませ ん。 Django のテンプレートシステム (あるいはサードパーティの Python テンプ レートシステム) を使ってもよいですし、使わなくてもかまいません。 PDF ファイ ルを生成しても、 XML を出力しても、 ZIP ファイルをオンザフライで生成しても かまいません。 Python ライブラリを使ってやりたいことを何でも実現できます。

Django にとって必要なのは HttpResponse か、あるいは 例外です。

簡単のため、 チュートリアルその 1 で解説した Django のデータベース API を使ってみましょう。 index() ビューを、システ ム上にある最新の 5 件の質問項目をカンマで区切り、日付順に表示させてみます:

from polls.models import Poll
from django.http import HttpResponse

def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    output = ', '.join([p.question for p in latest_poll_list])
    return HttpResponse(output)

残念ながらこのコードには問題があります。ページのデザインがビュー中にハード コードされているのです。これでは、ページの見栄えを変えたくなるたびに Python コードをいじらねばなりません。というわけで、 Django のテンプレートシステム を使って、デザインと Python コードを分離しましょう:

from django.template import Context, loader
from polls.models import Poll
from django.http import HttpResponse

def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    t = loader.get_template('polls/index.html')
    c = Context({
        'latest_poll_list': latest_poll_list,
    })
    return HttpResponse(t.render(c))

このコードは “polls/index.html” とい名前のテンプレートをロードし、テンプレー トにコンテキストを渡します。コンテキストとは、テンプレート変数名を Python のオブジェクトに対応づけている辞書です。

ページをリロードしましょう。エラーが出るようになったはずです:

TemplateDoesNotExist at /polls/
polls/index.html

そうそう、まだテンプレートを作ってませんね。まず、ファイルシステム上の Django がアクセス出来る場所にディレクトリを作成します (Django はサーバを実 行しているユーザと同じユーザ権限で動作します)。ただし、Web サーバのドキュメ ントルートには置かないようにしましょう。セキュリティへの配慮として、テンプ レートを公開するべきではないと思います。次に、 settings.pyTEMPLATE_DIRS を編集して、どこでテンプレートを探せばよいか Django に教えます。チュートリアルその 2 の「admin サイトのルック & フィール をカスタマイズする」でやったのと同じ作業です。

設定がおわったら、テンプレートディレクトリに polls というディレクトリを 作成します。このディレクトリの中に、 index.html という名前のファイルを 作成してください。 loader.get_template('polls/index.html') というコード は、ファイルシステム上の “[template_directory]/polls/index.html” に対応する ことに注意して下さい。

テンプレートには以下のようなコードを書きます:

{% if latest_poll_list %}
    <ul>
    {% for poll in latest_poll_list %}
        <li><a href="/polls/{{ poll.id }}/">{{ poll.question }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

ブラウザでページをロードすると、チュートリアル 1 で作った “What’s up” とい う投票項目の入ったブレットリストを表示します。リンクは詳細ページを指します。

ショートカット: render_to_response()

テンプレートをロードしてコンテキストに値を入れ、テンプレートをレンダリング した結果を HttpResponse オブジェクトで返す、というイ ディオムは非常によく使われます。 Django はこのイディオムのためのショートカッ トを提供しています。ショートカットを使って index() ビューを書き換えてみ ましょう:

from django.shortcuts import render_to_response
from polls.models import Poll

def index(request):
    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
    return render_to_response('polls/index.html',
                              {'latest_poll_list': latest_poll_list})

この作業によって、 loaderContextHttpResponse を import する必要はなくなりました。

render_to_response() 関数は第一引数にテンプレートの 名前をとり、オプションの第二引数に辞書をとります。 render_to_response() はテンプレートを指定のコンテキ ストでレンダリングし、 HttpResponse オブジェクトにし て返します。

404 の送出

さて、今度は Poll の詳細ページを片付けましょう。このページは Poll の質問文 (question フィールド) を表示します。ビューは以下のようになります:

from django.http import Http404
# ...
def detail(request, poll_id):
    try:
        p = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404
    return render_to_response('polls/detail.html', {'poll': p})

新しい概念がでて来ました。このビューはリクエストした ID を持つ Poll が存在 しないときに Http404 を送出します。

polls/detail.html テンプレートに何を書けばよいかは後で解説しますが、さ しあたって上の例題を動かしたければ、単に:

{{ poll }}

と書いておいてください。

ショートカット: get_object_or_404()

get() を実行し、該当オブジェクトがな い場合には Http404 を返す、という作業は非常によく使われ るイディオムです。 Django はこのイディオムのためのショートカットを提供してい ます。ショートカットを使って detail() ビューを書き換えてみましょう:

from django.shortcuts import render_to_response, get_object_or_404
# ...
def detail(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    return render_to_response('polls/detail.html', {'poll': p})

get_object_or_404() は Django のモデルクラスを第一 引数にとり、任意の個数のキーワード引数をとります。キーワード引数はそのまま get() メソッドに渡ります。オブジェク トが存在しなければ Http404 を送出します。

設計哲学

なぜ ObjectDoesNotExist 例外を高水準で自 動的にキャッチせず、ヘルパー関数 get_object_or_404() を使うのでしょうか、また、 なぜモデルAPI に ObjectDoesNotExist では なく Http404 を送出させるのでしょうか?

答えは、「モデルレイヤとビューレイヤをカップリングしてしまうから」です。 Django の最も大きな目標の一つは、ルーズカップリングの維持にあります。

get_list_or_404() という関数もあります。この関数は get_object_or_404() と同じように働きますが、 get() ではなく filter() を使います。リストが空の 場合は Http404 を送出します。

404 応答 (ページを見つけられません) 用のビューを作る

ビュー内で Http404 を送出すると、 Django は 404 エラー 処理用の特殊なビューをロードします。このビューは URLconf にある handler404 という変数 ( URLconf にあるもののみ有効です。その他に設定さ れたものは影響がありません) を参照して見つけます。変数は URLconf のコール バックで使っているのと同じ、 Python のドット表記法で表した関数名の文字列で す。 404 ビュー自体に特殊なところはありません。単なる普通のビューです。

普通はわざわざ苦労して 404 ビューを書く必要はありません。もし handler404 を設定しなかった場合は、ビルトインビューである django.views.defaults.page_not_found() がデフォルトで使用されます。 この場合、 404.html テンプレートをテンプレートディレクトリのルートに 作成する必要があります。デフォルトの 404 ビューはこのテンプレートを全ての 404 エラーに対して使用します。もし (設定モジュールで) DEBUGFalse に設定していて、なおかつ 404.html を作成しなかった場合、 Http500 が代わりに送出されます。 404.html を作成することを覚えて おいてください。

404 ビューに関するいくつかの注意すべき点:

  • (設定モジュールで) DEBUGTrue に設定している場合、 Django は 404 ビューを使わず、トレースバックを表示します (404.html も使われません)。
  • 404 ビューは、 Django が URLconf の全ての正規表現をチェックして、一致 するものがなかった場合にも呼び出されます。

500 応答 (サーバエラー) 用のビューを作る

404 と同じように、ルートの URLconf で handler500 を定義できます。 handler500 はサーバエラーが生じたときに呼び出されるビューを指します。 サーバエラーになるのは、ビューコードに実行時エラーが生じた場合です。

テンプレートシステムを使う

detail() ビューに戻りましょう。コンテキスト変数を poll とすると、 polls/detail.html テンプレートは以下のように書けます:

<h1>{{ poll.question }}</h1>
<ul>
{% for choice in poll.choice_set.all %}
    <li>{{ choice.choice }}</li>
{% endfor %}
</ul>

テンプレートシステムはドットを使った表記法で変数の属性にアクセスします。 {{ poll.question }} を例にとると、まず Django は poll オブジェクト を辞書とみなして question の値を探します。これには失敗するので、今度は 属性として照合を行い、この場合は成功します。仮に属性の照合に失敗すると、 Django は リストインデックスでの照合を行おうとします。

メソッド呼び出しは {% for %} ループの中で行われています。 poll.choice_set.all は、 Python のコード poll.choice_set.all() に解 釈されます。その結果、 Choice オブジェクトからなるイテレーション可能オブジェ クトを返し {% for %} タグで使えるようになります。

テンプレートの詳しい動作は テンプレートガイド を 参照してください。

URLconf の単純化

しばらくビューとテンプレートシステムをいじってみてください。 URLconf を編集 していくうちに、実はかなり冗長な部分があることに気づくかもしれません:

urlpatterns = patterns('',
    url(r'^polls/$', 'polls.views.index'),
    url(r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
    url(r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
    url(r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
)

明らかに、どのコールバックにも polls.views が入っています。

これはよくあることなので、 URLconf フレームワークではプレフィクスを共有する ためのショートカットがあります。共通のプレフィクスを切り出して、以下のよう に patterns() の最初の引数に追加してくださ い:

urlpatterns = patterns('polls.views',
    url(r'^polls/$', 'index'),
    url(r'^polls/(?P<poll_id>\d+)/$', 'detail'),
    url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
    url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'),
)

機能的には前の形式と全く同じです。でもとてもすっきりしましたね。

普通、一つのアプリに対してのプレフィクスを URLconf にある全てのコールバック に適用させたくはないので、複数の patterns() を結合 させることが出来ます。 mysite/urls.py は以下のようになるでしょう:

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('polls.views',
    url(r'^polls/$', 'index'),
    url(r'^polls/(?P<poll_id>\d+)/$', 'detail'),
    url(r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
    url(r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'),
)

urlpatterns += patterns('',
    url(r'^admin/', include(admin.site.urls)),
)

URLconf の脱カップリング

ところで、すこし時間を割いて polls アプリケーションの URL 設定を Django プ ロジェクトの設定から切り離しましょう。 Django アプリケーションはプラグ可能、 つまりあれこれ設定しなくても、特定のアプリケーションを別の Django インストー ルに移動できるようになっています。

今のところ、 python manage.py startapp で作成した厳密なディレクトリ構成 のおかげで polls アプリケーションはかなりうまく脱カップリングできていますが、 一点だけ現在の Django の設定とカップリングしている場所があります: それは URLconf です。

これまでは URL 設定を mysite/urls.py で編集してきましたが、本来アプリケー ションの URL 設計はアプリケーション固有のものであって、特定の Django インス トールとは関係のないものです。そこで、 URL 設定をアプリケーションディレクト リ内にもってきましょう。

mysite/urls.py ファイルを polls/urls.py にコピーしてください。 次に mysite/urls.py から polls に関する URL 設定を全て削除し、以下の include() を一つだけ書くと、以下が残ります:

from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls')),
    url(r'^admin/', include(admin.site.urls)),
)

簡単に説明すると、 include`() は別の URLconf への 参照です。正規表現に $ (文字列の末尾にマッチする) が付いておらず、代り にスラッシュがついていることに注意してください。 Django は ~django.conf.urls.include を見つけると、リクエスト URL 中のマッ チした部分を切り離し、残りの部分を include されている URLconf に送って処理 させます。

従って、このシステムでユーザが “/polls/34/” にアクセスすると、次のように処 理されます:

  • Django は '^polls/' へのマッチを検出します。
  • Django はマッチ部分のテキスト ("polls/") を取り去り、残りのテキスト である "34/" を ‘polls.urls’ という URLconf に送り、処理させ ます。

これでプロジェクト側の脱カップリングはできました。今度は polls.urls 側を脱カップリングするために、 URLconf の各行から、 先頭の “polls/” を削除してください。 polls/urls.py ファイルは以下のよう になります:

from django.conf.urls import patterns, include, url

urlpatterns = patterns('polls.views',
    url(r'^$', 'index'),
    url(r'^(?P<poll_id>\d+)/$', 'detail'),
    url(r'^(?P<poll_id>\d+)/results/$', 'results'),
    url(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
)

include() と URLconf の脱カップリングの背景には、 URL のプラグ & プレイを簡単にしようという発想があります。今や polls は独自の URLconf を持っているので、 “/polls/” や “/fun_polls/”, “/content/polls/” といった、どんな パスルート下にも置けて、どこに置いてもきちんと動作します。

polls アプリケーションは絶対パスではなく相対パスだけに注意しているわけです。

ビューの作成に慣れたら、 チュートリアルその 4 に 進んで、簡単なフォーム処理と汎用ビュー (generic view) の使い方を学びましょ う。

はじめての Django アプリ作成、その 4

revision-up-to:17812 (1.4)

このチュートリアルは チュートリアルその 3 の続き です。ここでは、引続き Web 投票アプリケーションの開発を例にして、簡単なフォー ム処理とコードの縮小化を中心に解説します。

簡単なフォームを書く

それでは、前回のチュートリアルで作成した Poll の詳細ビュー用テンプレート ("polls/detail.html") を更新して、 HTML <form> エレメントを入れてみ ましょう:

<h1>{{ poll.question }}</h1>

{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="/polls/{{ poll.id }}/vote/" method="post">
{% csrf_token %}
{% for choice in poll.choice_set.all %}
    <input type="radio" name="choice" id="choice{{ forloop.counter }}"
     value="{{ choice.id }}" />
    <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
{% endfor %}
<input type="submit" value="投票する" />
</form>

簡単に説明しましょう:

  • 上のテンプレートでは、 Poll の選択肢ごとにラジオボタンを表示していま す。各ラジオボタンの value は Choice の ID に関連づけられています。 ラジオボタンの name はいずれも "choice" です。つまり、投票者 がラジオボタンのいずれかを選択してフォームを提出 (submit) すると、 choice=3 という内容のPOST データを送信します。これは HTML フォー ムの基本ですね。
  • フォームの action/polls/{{ poll.id }}/vote/ に設定し、 method="post" にしています。 (method="get" ではなく) method="post" を使っている点は極めて重要です。というのも、このフォー ムの提出はサーバ側のデータの更新につながるからです。サーバ側のデータ を更新するようなフォームを作成するときは、常に method="post" を使 いましょう。これは Django 固有の話ではなく、いわば Web 開発の王道です。
  • forloop.counter は、 for タグのループが何度実行されたかを 表す値です。
  • データが改ざんされる恐れのある POST のフォームを作成しているので、クロス サイトリクエストフォージェリ (Cross Site Request Forgeries) のことを心配 する必要があります。 ありがたいことに、 Django がこれに対応するとても使いやすい仕組みを提供し てくれているので、あまり心配する必要はありません。手短に言うと、全ての 自サイトへ向けての POST フォームに対しては {% csrf_token %} テンプレートタグを使いましょう。

{% csrf_token %} タグは、テンプレートコンテキストから はアクセスできないようなリクエストオブジェクトの情報を必要とします。このた めに、少し detail ビューに変更を加える必要があります。変更を加えた後は 以下のようになります:

from django.template import RequestContext
# ...
def detail(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    return render_to_response('polls/detail.html', {'poll': p},
                               context_instance=RequestContext(request))

これがどのように動くかについての詳細は、 RequestContext で詳しく説明し ています。

さあ、今度は提出されたデータを処理するための Django ビューを作成しましょう。 チュートリアルその 3 で、以下のような行を polls アプリケーションの URLconf に入れたことを思い出しましょう:

(r'^(?P<poll_id>\d+)/vote/$', 'vote'),

また、 vote() 関数のダミーの実装も作成しました。今度は本物を作成しま しょう。以下を polls/views.py に追加してください:

from django.shortcuts import get_object_or_404, render_to_response
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from django.template import RequestContext
from polls.models import Choice, Poll
#...
def vote(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    try:
        selected_choice = p.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        # Poll 投票フォームを再表示します。
        return render_to_response('polls/detail.html', {
            'poll': p,
            'error_message': "選択肢を選んでいません。",
        }, context_instance=RequestContext(request))
    else:
        selected_choice.votes += 1
        selected_choice.save()
        # ユーザが Back ボタンを押して同じフォームを提出するのを防ぐ
        # ため、POST データを処理できた場合には、必ず
        # HttpResponseRedirect を返すようにします。
        return HttpResponseRedirect(reverse('polls.views.results', args=(p.id,)))

このコードには、これまでのチュートリアルで扱っていなかったことがいくつか 入っています:

  • request.POST は辞書ライクなオ ブジェクトです。このオブジェクトを使うと、キー名を使って入力されたデー タにアクセスできます。この例では、 request.POST['choice'] で投票者の選んだ選択肢を文字列で返させています。 request.POST に入っている値は 常に文字列です。

    Django では、 POST と同様、 GET データにアクセスするための request.GET も提供しています。 ただし、このコードでは、POST を経由した呼び出しでないとデータを更新さ せないようにするために、 request.POST を明示的に使って います。

  • choice が POST データ上になければ、 request.POST['choice']KeyError を送出します。上のコードでは KeyError をチェッ クして、 choice がない場合にはエラーメッセージ付きの Poll フォー ムを再表示しています。

  • choice のカウントを増やした後で、 HttpResponse ではなく HttpResponseRedirect を返しています。 HttpResponseRedirect はリダイレクト先の URL 一 つだけを引数にとります (ここでは reverse() を使って URL を生成していま すが、これについては後で説明します)。

    上のコードの Python コメント文で指摘しているように、 POST データの処 理に成功したときは常に HttpResponseRedirect を 返してください。これは Django 固有の話ではなく、 Web 開発の王道です。

  • 例では、 HttpResponseRedirect のコンストラクタ の中で reverse() という関数を使ってい ます。この関数を使うと、ビュー関数中での URL のハードコードを防げます。 reverse() にはビューの名前を渡し、同 時に URL パターンからビューにマップするときに取り出される変数を指定し ます。上の例では、 reverse()チュートリアルその 3 で設定した URLconfに従っ て:

    '/polls/3/results/'
    

    のような URL を返します。 3p.id の値です。リダイレクト先 の URL は 'results' ビューを呼び出し、最終的なページを表示します。 (プレフィクスを含めた) ビューの完全な名前を指定せねばならないので注意 してください。

チュートリアルその 3 で触れたように、 requestHTTPRequest オブジェクトです。 HTTPRequest の詳細は リクエスト・レスポンスオブジェクトのドキュメント を参照してください。

投票者が Poll に投票すると、 vote() ビューは開票結果ページにリダイレク トします。開票ページを書きましょう:

def results(request, poll_id):
    p = get_object_or_404(Poll, pk=poll_id)
    return render_to_response('polls/results.html', {'poll': p})

テンプレート名が違うことだけを除き、 チュートリアルその 3detail() とほとんど同 じですね。この冗長さは後で修正することにします。

今度は results.html テンプレートを作成します:

<h1>{{ poll.question }}</h1>

<ul>
{% for choice in poll.choice_set.all %}
    <li>{{ choice.choice }} -- {{ choice.votes }}</li>
{% endfor %}
</ul>

<a href="/polls/{{ poll.id }}/">Vote again?</a>

さあ、ブラウザで /polls/1/ を表示して、投票してみましょう。票を入れるた びに、結果のページが更新されていることがわかるはずです。選択肢を選ばずにフォー ムを提出すると、エラーメッセージを表示するはずです。

汎用ビューを使う: コードが少ないのはいいことだ

チュートリアルその 3detail()results() という二つのビューはバカバカしいくらいに単純で、先程も述べた ように冗長です。(これまた チュートリアルその 3 の) Poll のリストを表示する index() ビューも同様です。

こうしたビューは、基本的な Web 開発においてよくあるケース。すなわち、URL を 介して渡されたパラメタに従ってデータベースからデータを取り出し、テンプレー トをロードして、レンダリングしたテンプレートを返す、というケースを体現して います。これはきわめてよくあるケースなので、 Django では「汎用ビュー (generic view)」というショートカットのシステムを提供しています。

汎用ビューとは、よくあるパターンを抽象化して、 Python コードすら書かずにア プリケーションを書き上げられる状態にしたものです。

これまで作成してきた polls アプリケーションを汎用ビューシステムに変換して、 コードをばっさり捨てられるようにしましょう。変換にはほんの数ステップしかか かりません。そのステップとは:

  1. URLconf を変換する。
  2. 不要になった古いビューを削除する。
  3. 新しいビュー用に URL のハンドリングを修正する。

です。詳しく見てゆきましょう。

なぜ今更コードを入れ換えるの?

一般に Django アプリケーションを書く場合は、まず自分の問題を解決するため に汎用ビューが適しているか考えた上で、最初から汎用ビューを使い、途中ま で書き上げたコードをリファクタすることはありません。ただ、このチュート リアルでは中核となるコンセプトに焦点を合わせるために、わざと「大変な」 ビューの作成に集中してもらったのです。

電卓を使う前に、算数の基本を知っておかねばならないのと同じです。

まず polls の URLconf である polls/urls.py を開きます。チュートリアルで のこれまでの作業から、中身は以下のようになっているはずです:

from django.conf.urls import patterns, include, url

urlpatterns = patterns('polls.views',
    url(r'^$', 'index'),
    url(r'^(?P<poll_id>\d+)/$', 'detail'),
    url(r'^(?P<poll_id>\d+)/results/$', 'results'),
    url(r'^(?P<poll_id>\d+)/vote/$', 'vote'),
)

これを以下のように変更しましょう:

from django.conf.urls import patterns, include, url
from django.views.generic import DetailView, ListView
from polls.models import Poll

urlpatterns = patterns('',
    url(r'^$',
        ListView.as_view(
            queryset=Poll.objects.order_by('-pub_date')[:5],
            context_object_name='latest_poll_list',
            template_name='polls/index.html')),
    url(r'^(?P<pk>\d+)/$',
        DetailView.as_view(
            model=Poll,
            template_name='polls/detail.html')),
    url(r'^(?P<pk>\d+)/results/$',
        DetailView.as_view(
            model=Poll,
            template_name='polls/results.html'),
        name='poll_results'),
    url(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
)

この例では二つの汎用ビュー、 ListViewDetailView を使っています。こ れらのビューはそれぞれ、「オブジェクトのリストを表示する」および「あるタイ プのオブジェクトの詳細ページを表示する」という二つの概念を抽象化しています。

  • 各汎用ビューは自分がどのモデルに対して動作するのか知っておく必要があ ります。これは model パラメタによって提供されます。
  • DetailView 汎用ビューには、 "pk" という名前で URL から プライマリキー をキャプチャ して渡すことになっています。そこで、汎用ビュー向けに poll_idpk に書き換えてあります。
  • 結果を表示するビューに poll_results という名前をつけてあります。 こうすると、このビューを呼び出すような URL を後で生成できます (詳しくは「 名前付きパターン <naming-url-patterns> 」の説明を参照し てください。)また、 django.conf.urls モジュールの url() 関数を使っています。上の例のように、 パターン名を指定する場合には、 url() を使う よう薦めます。

デフォルトでは、 DetailView 汎用 ビューは <app name>/<model name>_detail.html という名前のテンプレート を使います。私達のアプリケーションでは、テンプレートの名前は "polls/poll_detail.html" です。 template_name 引数は Django に自動生成されたデフォルトのテンプレート名 ではなく、指定した名前を使うように伝えるために使われます。また、 result リストビューにも template_name を指定します。これは結果 (result) ビューと詳細 (detail) ビューが、お互い実は DetailView であるにも関わらず、 レンダリングされたときに違った外観を持っているためです。

同様に、 ListView 汎用ビューも <app name>/<model name>_list.html という名前のテンプレートを使うので、 template_name を使って ListView に既存の polls/index.html テンプレートを使用するように伝えます。

このチュートリアルの前の部分では、 polllatest_poll_list といった変数の入ったコンテキスト (context) をテンプレートに渡していました。 DetailView には、 poll という変数が自動的に渡されます。なぜなら、今 私達は Django モデル (Poll) を使用していて、 Django はコンテキスト 変数にふさわしい名前を決めることができるからです。一方で、 ListView では、 自動的に生成されるコンテキスト変数は poll_list となります。これを上書 きするには、 context_object_name オプションを与えて、 latest_poll_list を代わりに使用すると指定します。この代替アプローチと して、新しいデフォルトのコンテキスト変数と一致するようにテンプレートを変 えることもできます。しかし、ただ Django に使用したい変数名を伝えるほうが 簡単でしょう。

さて、 index(), detail() および results() ビューのコードを polls/views.py から削除できるようになりました。これらのビュー関数は汎用 ビューで置き換わったので、もう必要ありません。

最後に、 URL が汎用ビューを指すように修正します。上の vote ビューでは、 reverse() 関数を使って URL のハードコードを 防いでいます。汎用ビューに切替えたので、 reverse() を変更して、URL が新しく追加した 汎用ビューを指すようにします。汎用ビューのビュー関数を使えれば簡単なのです が、汎用ビューというものは一つのサイトの中で何度も使われることがあるので、 そういうわけにはいかないのです。そこで、先程指定しておいたビューの名前を使 います:

return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))

サーバを実行して、新しく汎用ビューベースにした投票アプリケーションを使って みましょう。

汎用ビューの詳細は 汎用ビューのドキュメント を参照してく ださい。

次回予告

このチュートリアルはここでしばらく中断します。今後は以下のような内容をカバー する予定です:

  • 高度なフォーム処理
  • RSS フレームワークを使う
  • キャッシュフレームワークを使う
  • コメントフレームワークを使う
  • 管理サイトの高度な機能: パーミッション
  • 管理サイトの高度な機能:カスタム JavaScript

さしあたっては、 次のステップへ に進むとよいでしょ う。

次のステップへ

revision-up-to:17812 (1.4)

さあ、ここにきたあなたは、 入門編 をあらかた読み終えて、 Django を使い続ける決心をしたことだと思います。入門編では、 Django のほんの 表面的な部分に触れただけにすぎません (実際、入門編の分量は、全体のドキュメ ントの 10% にも満たないのです)。

さて、次は何をしましょうか?

そうですね、私達は実践を通して学ぶのがとても大好きですよね。今や、読者のみ なさんは自分のプロジェクトを作成して、いろいろと遊んでみるのに十分な段階に あります。新しい技を身に付けたければ、いつでもここに戻って来てください。

私達は、 Django ドキュメントを有意義で、読みやすく、可能な限り完璧にしよう と努力しています。このドキュメントの残りの部分では、読者の皆さんが Django のドキュメントをできるだけ活用できるように、ドキュメントがどういう仕組みに なっているのかを説明しています。

(そう、これはいわばドキュメントのドキュメントです。ただし、このドキュメント の読み方を説明するドキュメントを書いたりはしませんから心配しないでください ね。)

ドキュメントを探す

Django には、いまや 200,000 語を越す たくさん のドキュメントがあります。 その中から必要なものを捜し出すのは大変です。そういうときは、 Search PageIndex から辿るとよいでしょう。

もちろん、片っ端から読み進むのもいいですけどね。

ドキュメントの構成

Django のドキュメントは、用途に応じていくつかの部に分かれています:

  • 入門編 は、 Django や、ウェブ開発全般の初心者を 対象に作られています。あまり詳細な解説はありませんが、高い視点で Django の開発が「どのようなものか」を見られます。
  • トピック別ガイド では、 Django の個々の構成要素 について詳しく解説しています。このセクションでは、 Django の モデルシステム, テンプレートエンジン, フォームフレームワーク といったトピックを解説しています。

    おそらく、読者の皆さんはこのセクションを読み進むのに多くの時間を費す でしょう。このガイドを全て読破したら、 Django を扱う上で必要なことは ほとんど知っているはずです。

  • ウェブ開発に必要な知識は、いくつもの領域にまたがって広く、浅く分布し ているものです。 このセクションには、「〜をするにはどうしたらよいです か?」といった質問に答える、 HOWTO が書かれて います。例えば、 Django で PDF を生成する方法 や、 テンプレートタグを自作する方法 などです。

    よくある質問は、これとは別に FAQ で扱っています。

  • ガイドや HOWTO ドキュメントは、 Django の全てのクラスや関数、メソッ ドを解説しているわけではありません。 Django を学ぼうとする人に最初か ら全てを教えようとしても、溢れてしまうからです。その代わりに、個々の クラスや関数、メソッド、モジュールの解説を リファレンス に置きました。特定の関数の仕様や、どんな機能を使えるかを 調べたければ、このセクションを参照してください。

ドキュメント更新の方針

Django のコードベースが毎日のように開発と改良を重ねているように、ドキュメン トも常に改良を重ねています。ドキュメントの改良は以下のような理由に基づいて 行われます:

  • 文法やタイプミスなどの誤りを修正する場合。
  • 既存の内容に対して、新たに情報や例題を追加する場合。
  • まだ解説されていない Django の機能をドキュメント化する場合 (未ドキュ メントの機能は減りつつありますが、まだいくつか残っています)。
  • 新たな機能が追加され、ドキュメントも追加する場合。あるいは、 Django の API や挙動が変更された場合。

Django のドキュメントはコードと同じソースコード管理システム下にあり、 Subversion リポジトリの django/trunk/docs ディレクトリ以下に置かれていま す。各ドキュメントは、例えば「汎用ビュー」フレームワークや、データベースモ デルの構築方法といった具合に、個別のトピックごとに別々のテキストファイルに なっています。

ドキュメントの入手

Django のドキュメントを入手するにはいくつか方法があります。おすすめの順に以 下に示します:

Web 版

Django ドキュメントの最新版は http://docs.djangoproject.com/en/dev/ にあります。ここにある HTML ページは、ソースコード管理システム上のテキスト ファイルから自動生成されているものです。従って、これらのファイルは「最新最 良の」 Django に対応しています。つまり、最近の修正や追加事項を反映していて、 まだ開発版でしか使えないような最新の機能についても部分的に解説しているわけ です (後述の「バージョン間の相違点」を参照してください)。

ドキュメント改良のお手伝いは大歓迎です。変更すべき点、修正すべき点、改良す べき点などを チケットシステム に提出してください。Django の開発陣がチケッ トシステムを監視して、あなたのフィードバックが皆に恩恵をもたらすようにしま す。

ただし、チケットは一般的なテクニカルサポートに関わる質問ではなく、ドキュメ ント自体に関する内容にしてください。 Django のセットアップに関する個別の問 題はドキュメントのコメント欄にではなく、 django-users メーリングリストIRC の #django チャネル にお願いします。

プレーンテキスト版

オフラインで読みたい人や手早く読みたい人のために、Django ドキュメントはプレー ンテキスト形式で読めます。

Django の公式リリース版を使っているなら、ソースコードのアーカイブパッケージ (tarball) に docs/ ディレクトリが入っています。このディレクトリには各リ リースの全てのドキュメントが入っています。

Django の開発版 (いわゆる Subversion “trunk”) を使っている場合、 docs/ ディレクトリに全てのドキュメントが入っています。最新版を取得したければ、 Python コードの更新と同様、 svn update を実行してください。

最新の Django ドキュメントを Subversion から取り出すには、以下のようなシェ ルコマンドを使います:

$ svn co https://code.djangoproject.com/svn/django/trunk/docs/ django_docs

テキストドキュメントの便利でローテクな使い方の一つに Unix の grep ユー ティリティを使った全ドキュメント検索があります。例えば、以下のようにすれば、 “max_length” について触ている部分を表示できます:

$ grep -r max_length /path/to/django/docs/
ローカルで HTML で読む

以下のステップを踏めば、 HTML ドキュメントのローカルコピーを手に入れられま す:

  • Django のドキュメントは、 Sphinx というシステムを使ってプレーンテキ ストから HTML への変換を行っています。 Sphinx のウェブサイトから Sphinx をダウンロードしてインストールするか、 pip を使って インストールします:

    $ sudo pip install Sphinx
    
  • Django のドキュメントディレクトリにある Makefile を使って、ドキュ メントを HTML に変換します:

    $ cd path/to/django/docs
    $ make html
    

    GNU Make がインストールされている必要があります。

    もし Windows の場合は、ドキュメントディレクトリにあるバッチファイルを 使用して変換できます:

    cd path\to\django\docs
    make.bat html
    
  • HTML ドキュメントが docs/_build/html に生成されます。

Note

Django ドキュメントは Sphinx バージョン 0.6 以上を使って生成できます が、 Sphinx 1.0.2 以上を使用することをおすすめします。

バージョン間の相違点

前述したように、 Subversion リポジトリに入っているテキストドキュメントは 変更や追加によって「最新最良」の状態にあります。変更によって、開発版、すな わち Subverion (“trunk”) 版の Django に新たに登場した機能がテキストに記載さ れることがよくあります。このため、 Django の各バージョン間で一貫したドキュ メンテーションポリシをここで示しておきます。

我々は、以下のポリシに従っています:

  • djangoproject.com の第一のドキュメントは Subversion から生成される HTML 形式のドキュメントです。これらのドキュメントは常に最新の Django 公式リリースと、最新のリリース 以後 に追加/変更された機能に対応し ています。
  • Django の開発版に機能を追加する場合、可能ならば同じ Subversion のコミッ トトランザクションにおいてドキュメントの変更もチェックインします。
  • 追加/変更された機能を区別するため、「バージョン X.Y で新たに追加され た機能です (New in version X.Y) という文を使います。X.Y は次の (開発 中の) リリースバージョンです。
  • 特定のリリース版のドキュメントは、公式リリース時に一度フリーズされま す。従って、ドキュメントはその時のスナップショットです。以前のバージョ ンに遡ってセキュリティアップデートその他の変更を行った場合にのみ、例 外的にドキュメントを更新します。ドキュメントのフリーズ後は、各ドキュ メントの冒頭に “These docs are frozen for Django version XXX” という 一文と、ドキュメントの最新版へのリンクを追加します。

See also

Python の初心者なら、まずは Python で何ができるかを理解しましょう。 Django は 100% Python で書かれているので、ほんの最小限 Python を理解す るだけで Django をより深く理解できるはずです。

プログラミング全般の初心者なら、 非プログラマのための Python リソース一覧 から始めてみるとよいでしょ う。

Python 以外の言語を学んだことがあって、 Python を素早く学びたいのなら、 Dive Into Python をお勧めします (木を伐って作ったヤツ もあります)。 Dive Into Python があまりお好きでなくても、 Python の本 はたくさんあ りますよ。

訳注: 日本語の読者のために

日本語の Python の情報を探しているなら、 日本 Python ユーザ会のページ を訪れてみてください。

日本語で書かれた Python の書籍を探しているなら、 http://wiki.python.org/moin/JapanesePythonBooks もチェックしてみて ください。

Django を使う

revision-up-to:17812 (1.4)

このセクションでは、Django を使う上での鍵となる要素について解説しています。

Django のインストール

revision-up-to:17821 (1.4) unfinished

このドキュメントを読めば Django を動かせるようになります。

Python のインストール

Django は Python の Web フレームワークなので、当然 Python が必要です。

Djangoを動かすには2.5から2.7までのバージョンのPythonが必要です。 (後方互換性の確保のため、Python3.0ではDjangoは動作しません。 the Django FAQ を参考にすれば、Python3.0のサポートに関してもっと詳しい 情報を手に入れることが出来ます。

http://www.python.org から Python を取ってきましょう。 Linux や Mac OSX を 動かしているのなら、おそらくインストール済みのはずです。

Jython で Django を動かす

Jython (Java プラットフォームで動く Python 実装) を使っているなら、他 にもいくつかステップを踏む必要があります。詳しくは Jython 上で Django を動かす を参照してください。

Windows上のPython

Windows上では、 PATH の環境を設定しなければなりません。パスをPython の実行可能ファイルとそのスクリプトまで通す必要があります。例えば、もし、 C:\Python27\ にPythonがインストールがされているならば、追加しなけ ればいけない PATH は:

C:\Python27\;C:\Python27\Scripts;

Apache と mod_wsgi のインストール

単に Django を試してみたいだけなら、この節は読み飛ばして次の節を読んでくだ さい。Djangoにはテスト用の軽量なWebサーバが付属しているので、運用環境での動 作が必要になるまでApacheをセットアップする必要はないのです。

Django を実運用するサイトで使いたい場合、 Apache と mod_wsgi を使って下 さい。mod_wsgiにある二つのモードのうち一つを選んで実行できます。エンベデッド モードとデーモンモードがそれです。エンベデッドモードでは、 mod_wsgi は mod_perl のようなもので、 Python を Apache の中に埋め 込み、サーバの起動時に Python コードをメモリにロードします。コードは Apache プロセスが生きている間ずっとメモリ上に存在するので、他のサーバ構成よりも明 らかに高いパフォーマンスを実現します。デーモンモードでは、mod_wsgiは 独立した要求処理のいらないデーモンプロセスを呼びます。 デーモンプロセスはWebサーバーをこえた異なるユーザーとして動作します、これは セキュリティの向上へと導く可能性もあり、そしてデーモンプロセスは Apache Webサーバの 完全なリスタートすることなしでデーモンプロセスを再開でき、あるいはコードベース をよりシームレスなものへとレフレッシュさせるでしょう。 どちらのモードが適切かどうかは、mod_wsgi のドキュメントを確認して決断してください。 まずは mod_wsgi が動作する Apache がインストールされていることを確かめてください。 Django は mod_wsgi をサポートする全てのバージョンの Apache で動作します。

mod_wsgi をインストールした後の設定方法は mod_wsgiでDjangoを動かす を参照してく ださい。

何らかの理由で mod_wsgi を使えない場合でも心配はいりません Django を運用す る方法は他にもあります。お勧めの第二選択肢は、 mod_wsgi の前身、 uWSGI です。これは nginx.と一緒に動きます。もう一つは FastCGI これはApache以外のDjangoと一緒にサーバーを動かす完璧な方法です。付け加えれば、 Django は WSGI 仕様(PEP 3333)に従っているので、他にも様々なサーバプラットフォームで 動作させられます。個々のプラットフォームにおけるインストール方法の説明は サーバ構成に関する wiki ページ を参照してください。

データベースを動かす

Django のデータベース API 機能を使うのなら、データベースサーバを動かす必要 があります。 Django は PostgreSQL, MySQL, Oracle および SQLite で動作し ます (SQLite はサーバを動かさなくても使えます)。

公式にサポートされたデータベースに加えて、Djangoで他のデータベースを使うために サードパーティからバックエンドが提供されています。

DjangoとORM機能は非公式なバックエンドによってよく考慮されてサポートされてい ます。クエリは非公式なバックエンドの明確な機能として扱っています、サポートささ されたクエリにそって、おのおののサードパーティのプロジェクトによって提供される サポートチャンネルによって管理されているでしょう。

さらに、各データベースの Python バインディングをインストールしておく必要が あります。

  • PostgreSQL を使う場合、 postgresql_psycopg2 パッケージが必要です。 このデータベースについての特有の詳細が欲しいのならば、 PostgreSQL notes を参照するとよいでしょう。

    Windows 環境なら、非公式の Windows むけコンパイル済みパッケージ を使っ て下さい。

  • MySQL を使う場合は、バージョン 1.2.1p2 以降の MySQLdb が必要です。 MySQL バックエンド にまつわるデータベース固有の説 明も読んでおいたほうがよいでしょう。

  • もし、サポートされていないサードパーティのバックエンドを用いる場合、 更なる要望に応えるために提供されているドキュメントを読んでください。

Django の manage.py syncdb を使って、モデルに対応するテーブルを自動生成 するつもりなら、Django に対して、データベース上でテーブルの生成や ALTER を 行える権限を付与せねばなりません。テーブルを手動で生成するのなら、Django に 付与する権限は SELECT, INSERT, UPDATE および DELETE だけで かまいません。ただし、データベースによっては、 syncdb 時に ALTER TABLE 権限を付与しておく必要があります。 syncdb で一度テーブ ルを生成してしまえば、 syncdbALTER TABLE 文を発行しません。

テストフレームワーク を使ってデータベースクエリのテ ストを行うのなら、データベースを生成する権限も必要です。

旧バージョンの Django の除去

以前のバージョンからアップグレードする形で Django をインストールする場合、 新しいバージョンをインストールする前に、まず旧バージョンをアンインストール しておく必要があります。

setup.py install を使って Django をインストールした場合は簡単で、 Python の site-packages ディレクトリから django ディレクトリを削除 するだけです。

Python egg を使って Django をインストールした場合、Django の .egg ファ イルを削除するとともに、 easy-install.pth から Django の .egg ファ イルパスが書かれたエントリを削除します。 easy-install.pth.egg は、通常 site-packages ディレクトリ下にあります。

site-packages はどこにあるの?

site-packages の在処はオペレーティングシステムや Python のインストー ル場所によって異なります。 site-pacakges の場所を調べるには、以下の コマンドを実行してみてください:

python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

(このコマンドはPythonの対話プロンプトではなく、シェルプロンプトで実行してください。)

LinuxディストリビューションのDebianは分割する site-packages というデ ィレクトリをユーザがインストールしたパッケージのために持っていて、 Djangoをダウンロードしたtarballファイルからインストールするような時に使う。 上にあげたコマンドはシステムの site-packages を渡します、ユーザのディレクトリは /usr/local/lib/ にあり、 /usr/lib/ ではありません。

Django コードのインストール

インストール方法の説明は、 OS ごとのインストールパッケージを入れる場合、公 式リリース版を入れる場合、そして最新の開発バージョンを入れる場合で少し異な ります。

どの方法を選ぶにしても、そんなに難しくはないので安心してください。

OS ごとのインストールパッケージによるインストール

ディストリビューション固有の注意 を調べて、自分 のプラットフォーム/ディストリビューションで公式の Django パッケージやインス トーラが提供されていないか調べます。ディストリビューション固有の配布パッケー ジは、たいてい依存関係のあるパッケージを自動的にインストールしてくれたり、パ スの更新を行ってくれたりします。

公式リリースのインストールを pip

これはDjangoをインストールする上でおすすめの方法です。

  1. pip をインストールします。最も簡単な方法は、 standalone pip installer を使うことです。もし、 pip がインストー ルされているディストリビューションなら、古いものであればアップデートす る必要ががあるかもしれません。(もし古いものであれば、インストールがう まく動きません)

  2. (オプション) virtualenvvirtualenvwrapper をみてみましょう。 これらのツールは、個別の Python 環境を構築することができます、 システム全体にパッケージをインストールするよりも実用的です。 これらは、管理者権限なしでもパッケージをインストールできます。 これらのツールを学んだり使うかを決めるのはあなた次第です。

  3. もし Linux や MacOsX か、ほかの Unix 系統のOSを使用している場合、 sudo pip install Django をシェルコマンドで入力します。 Windows を使っているならば、コマンドシェルを管理者権限で起動し、 pip install Django コマンドを走らせます。 これらで、Python インストールのなかの site-packages にDjangoが インストールされます。

    もし、あなたが virtualenv を使っているなら、 sudo やadministrator (管理者)の権限を使うことなく、virtualenv の site-packages ディレクトリに Django がインストールされます。

公式リリースのインストール
  1. ダウンロードページ から、最新版の Django をダウンロードします。
  2. ダウンロードしたファイルを tar で展開します。 (例: tar xzvf Django-NNN.tar.gz)。 Windows を使っているのなら、 コマンドラインツール bsdtar を使うか、 7-zip のような GUI ベースの ツールを使います。
  3. ステップ 2 で生成された展開先のディレクトリに移ります (例: cd Django-NNN)
  4. Linux, Mac OS X, その他の Unix 系のオペレーティングシステムでは、 シェルプロンプトからコマンド sudo python setup.py install を入力 します。 Windows を使っているのなら、管理者権限でコマンドプロンプト を起動して、コマンド setup.py install を実行します。 上のコマンドを実行すると、 Django は Python インストールディレクトリの site-packages ディレクトリ下にインストールされます。
開発バージョンのインストール

Django の開発版を追いかける

最新版の Django を使うと決めたのなら、 開発の進行状況 によく注意して、 以前のバージョンと互換性のない変更 がないか気をつけておく必要がある でしょう。これらのリンク先のページに注意していれば、使ってみたい新たな 機能や、手元の Django をアップデートする際に、自分のコードのどこを修正 する必要があるか追いかけられます。 (安定版では、 Django のアップデート 時に必要な変更は全てドキュメントに記載されています。)

Django のコードを更新して最新のバグフィクスや改良を適用したいのなら、以下の 説明に従って開発バージョンをインストールしてください。

  1. Subversion, Git, Mercurial がインストールされていて、シェルからコマンドを実行できること を確認してください。 (調べるには、シェルプロンプトで svn helpgit help, hg help を入力します。) Subversionリポジトリは、公式のGitとMercurialリポジトリ自体が最新のものとな なるような標準のソースということを覚えておいてください。

  2. 以下のようにして、Django のメイン開発ブランチ (‘trunk’) をチェックアウト します:

    # Subversion
    svn co https://code.djangoproject.com/svn/django/trunk/ django-trunk
    

    Subversionリポジトリのミラーはこんな風に取得できます

    # Git (requires version 1.6.6 or later)
    git clone https://github.com/django/django.git
    # or (works with all versions)
    git clone git://github.com/django/django.git
    
    # Mercurial
    hg clone https://bitbucket.org/django/django
    

    Warning

    これらのミラーは五分ごとに最新版にアップデートされます。 けれど、サービス上にホストされてから常に五分ごとにアップデートされている という保証がついているわけではないので注意してください。

  3. Python インタプリタが Django のコードをロードできるようにします。一番便利な 方法は、 Python パスの修正 することです。 .pth ファイルに django-trunk ディレクトリへのフルpathをシステムの site-packages ディレクトリまで追加することです。例えば Unixライクなシステムでは

    echo WORKING=DIR/django-trunk > SITE-PACKAGES-DIR/django.pth
    

    (上の作業では、使っているプラットフォームの site-packages ディレク トリに合わせて SITE-PACKAGES-DIR を書き換えてください。 site-packages の場所の探し方は、 site-packages はどこにあるの? を参照してください)

  4. django_src/django/bin/django-admin.py を実行できるようにします。 Unix系のシステムでは、例えば以下のようにして、 /usr/local/bin のよう なシステムパス上にシンボリックリンクを作成します:

    ln -s WORKING-DIR/django-trunk/django/bin/django-admin.py /usr/local/bin
    

    (上の行では、WORKING-DIRを新しい django-trunk ディレクトリまでのフル pathとマッチするように変えてください)

    これで、 django-admin.py とコマンド入力するだけで、どのディレクトリ 上でも django-admin.py を起動できるようになります。

    Windows では、 django_src/django/bin/django-admin.py を、 C:\Python27\Scripts のようなシステムパス上にコピーします。

Warning

sudo python setup.py install を走らせないでください。なぜなら、 ステップ3から4までの行程はそれと同等のことを行っているからです。 もっといえば、これはDjangoを最新のバージョンにアップデートする際に 問題を引き起こすものとして知られています。

Django のソースコードを更新する際には、 django-trunk ディレクトリで svn update を実行してください。実行すると、 Subversion が更新部分を自動 的にダウンロードします。同等のコマンドをGitで行うには git pull, Mercurialでは hg pull --update を実行します

モデルとデータベース

revision-up-to:17812 (1.4)

モデルとは、サイトを構成するデータの、ただ一つかつ最終的なデータソースを指 します。モデルには、保存したいデータに不可欠なデータフィールドと、その振舞 いが収められています。一般的に、各モデルは単一のデータベーステーブルに対応 づけられています。

モデルの作成

revision-up-to:17812 (1.4)

モデルとは、サイトを構成するデータの、唯一絶対的なデータソースを指します。 モデルには、保存したいデータを表すデータフィールドと、データのビヘイビアを 定義します。通常、一つのモデルは一つのデータベーステーブルに対応しています。

モデルの基本として、以下のことを知っておいてください:

  • 各モデルは Python のクラスで、 django.db.models.Model のサブ クラスです。
  • モデルの各アトリビュートの値は、データベース上のあるフィールドを表現 します。
  • モデルの情報をもとに、 Django はデータベース API を自動生成します。 API の詳細は「 クエリを生成する 」で解説します。
簡単な例

以下の例では、 first_name および last_name というフィールドを持った Person モデルを定義しています:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

first_namelast_name はモデルの フィールド (fields) です。各 フィールドはクラスのアトリビュートとして定義します。各々のアトリビュートは データベースのカラムに対応します。

上の Person モデルは、以下のようなデータベーステーブルを生成します:

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

いくつか、技術的な注意点があります:

  • テーブルの名前 myapp_person はモデルのメタデータから自動的に決定 します。テーブル名は変更できます。「 テーブル名 」を参照して ください。
  • id は自動的に追加されます。この動作も変更できます。 「 主キーフィールドの自動設定 」を参照してください。
  • 上の例の CREATE TABLE SQL 文は PostgreSQL の書式で書かれています が、 Django は 設定ファイル に指定しておいた データベースバックエンドに合わせて適切な SQL を発行します。
モデルを使う

モデルを定義したら、そのモデルを 使う よう Django に指示しましょう。設定 ファイルを編集して、 models.py の入っているパッケージの名前を INSTALLED_APPS 設定に追加してください。

例えば、アプリケーションのモデルが mysite.myapp.models モジュール (mysite.myappmanage.py startapp スクリプトで 作成したアプリケーションのパッケージ) に入っているなら、 INSTALLED_APPS に以下のように書きます:

INSTALLED_APPS = (
    #...
    'mysite.myapp',
    #...
)

新しいアプリケーションを INSTALLED_APPS に追加したら、 manage.py syncdb を忘れずに実行してください。

フィールド

モデルのフィールドは、モデルの定義で最も重要な、かつ最小限必要な要素です。 フィールドは、以下の例のように、クラスのアトリビュートとして定義します:

class Musician(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    instrument = models.CharField(max_length=100)

class Album(models.Model):
    artist = models.ForeignKey(Musician)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()
フィールドのタイプ

モデルの各フィールドには、 Field クラスのサブク ラスから、適切なクラスのインスタンスを生成して入れます。Django は、フィール ドのクラスが何であるかという情報を、以下のような判定で使います:

  • データベースのカラム型 (INTEGER, VARCHAR など) の決定
  • Django の管理サイトで使うウィジェット (<input type="text">, <select> など) の決定
  • Django の管理サイトやマニピュレータが実施する最小限のバリデーション の決定

Django にはたくさんのフィールドクラスが組み込みで付属しています。組み込みの フィールドクラス一覧は「 モデルフィールドリファレンス 」にあります。組み込みのフィールドで実現できないことが あれば、フィールドクラスを自分で定義できます。 「 howto-custom-model-fields 」を参照してください。

フィールドのオプション

各フィールドクラスには、それぞれフィールド固有の引数がいくつかあります (詳 しくは「 モデルフィールドリファレンス 」を参照し てください)。例えば、 CharField (とそのサブクラ ス) には、データを保存するときの VARCHAR データベースフィールドの長さを 決める必須の引数、 max_length が必要で す。

また、全てのフィールドに共通の引数もあります。共通の引数はどれも省略可能で す。共通の引数は「 リファレンス 」で説 明しています。

ここでは、良く使う引数を簡単に紹介しましょう:

null
True にすると、フィールドの値が空のとき、データベースには NULL を保存します。デフォルトの設定は False です。
blank

True にすると、フィールドの値を空白 (blank) にできます。デフォ ルトの設定は False です。

null とは違うので注意してください。 null は、単に空のデータをデータベース上でどう表現す るかを決めています。一方、 blank はフィールドの値の 検証 (validation) 方法を決めています。あるフィールドに blank=True を指定すると、 Django の管理サイト 上で、そのフィールドを空の値にしたままエントリを作れます。 blank=False にすると、フィールドには必ず値を 入れねばなりません。

choices

iterable (リストまたはタプル) を指定します。 iterable の各要素は フィールドの値の選択肢を表す 2 要素のタプルです。 choices を指定すると、 Django の管理サイト上には、標 準的なテキストフィールドの代わりにセレクタボックスが表示され、ユー ザは選択肢の値だけを選べます。

選択肢のタプル列は、例えば以下のように定義します:

YEAR_IN_SCHOOL_CHOICES = (
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
)

各タプルの最初の要素が実際にデータベースに保存される値で、二つめの 要素が管理インタフェースや ModelChoiceField に表示される内容で す。あるモデルオブジェクトのインスタンスで後者の値 (表示値) を取り 出したければ、 get_FOO_display メソッドを使います。例えば、以下 のようなモデルを考えましょう:

from django.db import models

class Person(models.Model):
    GENDER_CHOICES = (
        (u'M', u'Male'),
        (u'F', u'Female'),
    )
    name = models.CharField(max_length=60)
    gender = models.CharField(max_length=2, choices=GENDER_CHOICES)

gender の表示値は get_gender_display で取り出します:

>>> p = Person(name="Fred Flinstone", gender="M")
>>> p.save()
>>> p.gender
u'M'
>>> p.get_gender_display()
u'Male'
default
フィールドのデフォルト値です。この値は、固定の値でも、関数などの呼 び出し可能オブジェクトでもかまいません。呼び出し可能オブジェクトに した場合、新たなモデルインスタンスを生成するたびにそのオブジェクト を呼び出して、フィールドのデフォルト値を動的に決定します。
help_text
管理サイトでフォームの下に表示される、詳しい「ヘルプ」テキストです。 管理サイトを使っていなくても、定義しておけばドキュメントとして役に 立ちます。
primary_key

True を指定すると、フィールドをモデルの主キーにします。

モデルのどのフィールドにも primary_key=True が指定されていない場合、Django は自動的に IntegerField を追加して主キーを保存します。従って、主キー の設定をデフォルトの状態から変更したいのでないかぎり、 primary_key=True を指定する必要はありま せん。詳しくは「 主キーフィールドの自動設定 」を参照してく ださい。

unique
True の場合、フィールドの値はテーブル全体で一意でなければなりま せん。

前置きしたように、ここではよく使うオプションを簡単に説明するにとどめます。 全オプションの詳しい情報は 「 共通のモデルフィールドオプションのリファ レンス 」を参照してください。

主キーフィールドの自動設定

デフォルトの動作では、 Django は各モデルに以下のフィールド:

id = models.AutoField(primary_key=True)

を追加します。このフィールドは主キーに使われ、フィールドの値はレコードの追 加ごとに自動的にインクリメントされてゆきます。

特定のフィールドを主キーにしたければ、フィールドのオプションに primary_key=True を指定してください。 Field.primary_key の設定されたフィールドの定義があれば、Django は id カラムを自動的に追加しません。

各モデルには必ず一つ primary_key=True のフィー ルドが必要です。

表示用のフィールド名

ForeignKeyManyToManyFieldOneToOneField を除くフィールドクラスは、 第一引数に表示用のフィールド名を指定できます。この引数は省略可能です。引数 を指定しない場合、 Django がフィールドのアトリビュート名のアンダースコアを スペースに置き換えて、表示用のフィールド名を自動的に生成します。

下の例では、表示用のフィールド名は "person's first name" です:

first_name = models.CharField("person's first name", max_length=30)

下の例では "first name" です:

first_name = models.CharField(max_length=30)

ForeignKey, ManyToManyField, および OneToOneField クラスでは、第一引数は必須 で、リレーション先のモデルのクラス名を指定せねばなりません。これらのフィー ルドクラスでは、 verbose_name キーワード引数を使って表示用の フィールド名を指定します:

poll = models.ForeignKey(Poll, verbose_name="the related poll")
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(Place, verbose_name="related place")

慣習的に、 verbose_name の先頭の文字は大文字にしません。 Django は必要なときに先頭の文字を自動的に大文字にします。

リレーション

リレーショナルデータベースの威力が、テーブルを相互に関連づけする機能である のはいうまでもありません。Django には、多対一 (many-to-one)、多対多 (many-to-many)、一対一 (one-to-one) といった、よく使うリレーションを定義す る機能があります。

多対一のリレーション

多対一のリレーションを定義するには ForeignKey を使います。このフィールドは他 のフィールド型と同じように、モデルのクラスアトリビュートとして定義できます。

ForeignKey は、リレーションを張る対象のク ラスを指定する必須の引数を一つとります。

例えば、 Car モデルに Manufacturer というフィールドを持たせたいとし ましょう。すなわち、ある Manufacturer には複数の Car が対応するが、 各 Car には一つだけ Manufacturer が対応するようにしたいとしましょう。 この場合、以下のように定義します:

class Manufacturer(models.Model):
    # ...

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer)
    # ...

再帰的リレーション (自分自身に対する多対多 のリレーション) や、 未定義のモデルに対するリレーション も定義できます。「 モデルフィールドのリファレン ス 」を参照してください。

必須ではありませんが、 ForeignKey の名前 (上の例では manufacturer) には、モデル名を小文字にしたものを使うよう勧 めます。もちろん、以下のように、好きな名前を付けてもかまいません:

class Car(models.Model):
    company_that_makes_it = models.ForeignKey(Manufacturer)
    # ...

See also

ForeignKey フィールドは モデルフィールドリファレンス で説明してい る多くの追加引数を受け取ります。これらのオプションはリレーションがどのよ うに動くべきかを定義するのに役立ちます。

逆参照されるオブジェクトへのアクセスについては リレーションの逆参照の例. に詳しく書いてあります。

多対多のリレーション

多対多の (many-to-many) リレーションを定義するには ManyToManyField を使います。このフィール ドは他のフィールド型と同じように、モデルのクラス属性に含めて使えます。

ManyToManyField には固定引数が一つあり、 リレーションを張る対象のクラスを指定します。

Pizza には複数の Topping オブジェクトを関連付ける例を考えてみましょ う。すなわち、ある Topping は複数のピザの上に置けて、逆にそれぞれのピザ には複数のトッピングを置けるというわけです。このリレーションを表現するには 以下のように定義します:

class Topping(models.Model):
    # ...

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

ForeignKey と同様、 再帰的リレーション (自分自身に対する多対多のリレーション) や、 未定義のモデルに対するリレーション も定義できま す。「 モデルフィールドのリファレンス 」を参照して ください。

必須ではありませんが、 ManyToManyField の 名前 (上の例では toppings)は、リレーション先のモデル名の複数形にするよ う勧めます。

どちらのモデルで ManyToManyField を定義し てもかまいませんが、どちらか片方のモデルだけ指定すべきです – 両方には指定 すべきではありません。

一般的に言って、 Django の管理インタフェースを使うのなら、 ManyToManyField インスタンスを入れておく のは、管理インタフェースで編集される側のオブジェクトにしておくとよいでしょ う。上の例では、 topping は (ToppingManyToManyFieldpizzas をもたせる のではなく) Pizza に入れておきます。というのも、「トッピングを乗せるピ ザ」を編集するよりも「ピザの上に乗せるトッピング」を編集する方が自然だから です。というわけで、上の例のようにすれば、管理サイトの Pizza の編集画面 上でユーザにトッピングを選ばせられます。

See also

ManyToManyField フィールドも モデルフィールドリファレンス で説明して いる多くの引数を受け取ります。これらのオプションはリレーションがどの ように動くべきかを定義するのに役立ちます。必須ではありません。

エクストラフィールドで多対多を定義する

ピザとトッピングを組み合わせたり照合したりするだけのような多対多のリレーショ ンを扱いたいのなら、標準の ManyToManyField で事 足ります。しかし、時として、二つのモデルのリレーションそのものにデータを関 連づけたい場合があります。

例えば、ミュージシャンのグループと、在籍しているミュージシャンを追跡するア プリケーションのケースを考えてみましょう。これは個人 (person) とグループの 関係なので、 ManyToManyField でリレーションを表 現できるはずです。しかし、ミュージシャンとグループの関係には、あるミュージ シャンがあるグループにいつ合流したか、のような細かい情報がたくさんあります。

こうした状況に対応するために、Django には、あらかじめリレーションを管理する ためのモデル (中間モデル) を定義しておき、その中間モデルに向けてエクストラ フィールド (extra field) を組み込んで多対多のリレーションを定義する方法があ ります。中間モデルは ManyToManyFieldthrough 引数に指定します。ミュージシャン の例は以下のように書けます:

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __unicode__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

中間モデルからは、多対多のリレーションの両側にあたるモデルに対して明示的に 外部キーを張らねばなりません。

中間モデルには、いくつか制約があります:

  • 中間モデルは、多対多リレーションのターゲットモデル (リレーションを張 られる側のモデル) に対する外部キーを 一つだけ しか定義できません (上の例では Person ですね)。同じモデルに複数の外部キーを定義する と、モデルのバリデーション時にエラーを送出します。
  • 中間モデルは、多対多リレーションのソースモデル (リレーションを張る側 のモデル) に対する外部キーを 一つだけ しか定義できません (上の例で は Group ですね)。同じモデルに複数の外部キーを定義すると、モデル のバリデーション時にエラーを送出します。
  • 自分自身に対する多対多のリレーションを定義するのに中間モデルを使う場 合にのみ、例外的に同じモデルに対するリレーションを二つ定義できます。 ただし、多対多リレーションの中では、二つの外部キーは別々、すなわちソー スとターゲットを区別して扱います。
  • 中間モデルを使って、あるモデルから自分自身に多対対のリレーションを定 義する場合、 symmetrical=False を指定せねばなりません (「 モデルフィールドのリファレンス 」を参照してください) 。

さて、これで中間モデル (例でいうところの Membership) を使った ManyToManyField を設定したので、多対多のリレーショ ンを生成できます。リレーションの生成は、中間モデルのインスタンス生成によっ て実現します:

>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
...     date_joined=date(1962, 8, 16),
...     invite_reason= "Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
[<Person: Ringo Starr>]
>>> ringo.group_set.all()
[<Group: The Beatles>]
>>> m2 = Membership.objects.create(person=paul, group=beatles,
...     date_joined=date(1960, 8, 1),
...     invite_reason= "Wanted to form a band.")
>>> beatles.members.all()
[<Person: Ringo Starr>, <Person: Paul McCartney>]

通常の ManyToManyField と違って、 addcreate, (beatles.members = [...] のような) 代入では、リレーションの定義は行えま せん:

# 使えません。
>>> beatles.members.add(john)
# これも使えません。
>>> beatles.members.create(name="George Harrison")
# これもまた使えません。
>>> beatles.members = [john, paul, ringo, george]

なぜでしょうか。中間モデルでリレーションを作成するときには、単に PersonGroup の間のリレーションだけではなく、 Membership テーブルのレコー ドを生成するための情報が全て必要だからです。単に addcreate を呼 び出したり代入を行うだけでは、リレーション以外の情報を埋められません。その 結果、中間モデルを使う場合は、 addcreate は使えないのです。 中間モデルを使っている場合、多対多のリレーションを保存するには、中間モデル のインスタンスを生成するしかない、ということを覚えておいてください。

同じ理由で remove() メソッドも使えません。 ただし、 clear() メソッド を使えば、以下のように多対多のリレーションを一括して消去できます:

# ビートルズ解散
>>> beatles.members.clear()

ひとたび中間モデルによる多対多のリレーションを作成したら、通常の多対多リレー ションと同じように、リレーション先のモデルのアトリビュートを使ってリレーショ ンをまたいだクエリを実行できます:

# 'Paul' で始まる名前の人がメンバにいるグループを探す
>>> Groups.objects.filter(members__name__startswith='Paul')
[<Group: The Beatles>]

中間テーブルを使っているので、中間テーブルのアトリビュートを使ったクエリも 実行できます:

# 1961年1月1日以降に合流した Beatles のメンバを探す
>>> Person.objects.filter(
...     group__name='The Beatles',
...     membership__date_joined__gt=date(1961,1,1))
[<Person: Ringo Starr]

メンバの情報にアクセスする必要があれば、 Membership モデルのクエリを 直接実行することができます:

>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
u'Needed a new drummer.'

別の方法として、Person オブジェクトから 多対多の逆参照 クエリを使うことによって も同じ情報にアクセスできます。

>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
u'Needed a new drummer.'
一対一のリレーション

一対一のリレーションを定義するには、 OneToOneField を使います。このフィールド も他のフィールド型と同じように、モデルクラスのアトリビュートとして定義しま す。

このリレーションがもっとも有用なのは、あるオブジェクトが別のオブジェクトを 何らかの形で「拡張」している場合の主キーとして使う場合です。

OneToOneField には固定引数が一つあり、リ レーションを張る対象のクラスを指定します。

例えば、「場所 (place)」のデータベースを作るときには、アドレス、電話番号、 といった標準的なものを作成します。その上で、レストランデータベースを作成 するときに、 Restaurant モデルの中に同じフィールドをつくるような 繰り返し作業 (repeat yourself) をする代わりに、場所データベースを基盤にして レストランのデータベースを作成したいとしましょう。このとき、 Restaurant には Place への OneToOneField をもた せられます (レストランは場所に対して “is-a” の関係だからです。実際には、こ のような状況を扱うのに モデルの継承 を使いますが、 モデル継承は OneToOneField で実現されてい ます)。

ForeignKey と同様、 再帰的リレーション未定義のモデルに対するリレーション も定義できま す。詳しくは「 モデルフィールドのリファレンス 」を参 照してください。

See also

OneToOneField フィールドは、オプションの引数を一 つとります。引数は「 モデルフィールドリファレンス 」 で解説しています。

以前は、モデル中で OneToOneField を使うと、 そのフィールドは自動的にモデルの主キーになっていました。この仕様はもうなく なりましたが、主キーにしたければ手動で primary_key に指定できます。この 変更により、一つのモデル中で複数の OneToOneField を使えるようになりました。

ファイル間にまたがるモデル

あるモジュールから別のモジュールへのリレーションは全く問題なく張れます。リ レーションを張るには、以下の例のようにモデル定義の先頭でリレーション対称の モデルを import しておき、必要なところでそのモデルクラスを参照します:

from geography.models import ZipCode

class Restaurant(models.Model):
    # ...
    zip_code = models.ForeignKey(ZipCode)
フィールド名の制約

Django がモデルのフィールド名に課している制約は二つしかありません:

  1. フィールド名は Python の予約語であってはなりません。さもないと Python のシンタクスエラーを引き起こすからです。

    悪い例:

    class Example(models.Model):
        pass = models.IntegerField() # 'pass' は予約語です!
    
  2. フィールド名には二つ以上の連続するアンダースコアを入れてはなりません。 なぜなら、Django は二重アンダースコアをクエリ照合構文で使っているか らです。

    悪い例:

    class Example(models.Model):
        foo__bar = models.IntegerField() # 二重アンダースコアがあります!
    

データベースのカラム名はフィールドの名前と一致していなくてもよいので、デー タベース側では制約を回避できます。詳しくは後述の db_column を 参照してください。

joinwhere, select のような SQL の予約語を、モデルのフィール ド名に使っても かまいません 。というのも、Django は SQL クエリを生成する ときにデータベーステーブル名やカラム名を常にエスケープするからです。エスケー プにはデータベースエンジン固有のクオート方式を使います。

カスタムのフィールド型

既存のモデルフィールドが目的とするアプリケーションに合わない場合や、あまり 一般的でないデータベースカラムタイプを活用したい場合のために、独自のフィー ルドクラスを作成できます。カスタムフィールドの詳しい作成方法は 「 howto-custom-model-fields 」で説明しています。

Meta オプション

モデルにメタデータを指定するには、以下のようにモデルの内部クラス Meta を使います:

class Ox(models.Model):
    horn_length = models.IntegerField()

    class Meta:
        ordering = ["horn_length"]
        verbose_name_plural = "oxen"

モデルのメタデータとは、モデルインスタンスの整列順 (ordering)や、データベース上のテーブル名 (db_table)、モデル名の単数形や複数形 (verbose_name, verbose_name_plural) といっ た、「フィールドの情報でない」情報です。必須のメタデータはなく、 class Meta すら省略できます。

Meta に指定できるオプションの一覧は、「 モデルオプションのリファ レンス 」で解説しています。

モデルのメソッド

カスタムの行レベル (“row-level”) の機能をオブジェクトに実装するには、カスタ ムのメソッドを定義します。 Manager メソッドの目 的が「テーブル級 (table-wide)」 の操作であるのに対し、モデルメソッドは個々 のモデルインスタンス単位の操作を実現します。

モデルメソッドは、ビジネスロジックの置き場所をモデル一箇所に限定するための 効果的なテクニックです。

例えば、以下のモデルでは、いくつかカスタムメソッドを定義しています:

from django.contrib.localflavor.us.models import USStateField

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    birth_date = models.DateField()
    address = models.CharField(max_length=100)
    city = models.CharField(max_length=50)
    state = USStateField() # Yes, this is America-centric...

    def baby_boomer_status(self):
        "Returns the person's baby-boomer status."
        import datetime
        if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31):
            return "Baby boomer"
        if self.birth_date < datetime.date(1945, 8, 1):
            return "Pre-boomer"
        return "Post-boomer"

    def is_midwestern(self):
        "Returns True if this person is from the Midwest."
        return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO')

    def _get_full_name(self):
        "Returns the person's full name."
        return '%s %s' % (self.first_name, self.last_name)
    full_name = property(_get_full_name)

この例の最後のメソッドは プロパティ (property) です。

モデルインスタンスのリファレンス 」では、 各モデルに自動的に付与されるメソッド を全て 紹介しています。ほとんどのメソッドはオーバライド可能です。詳しくは後述の 既存のモデルメソッドをオーバライドする を参照してください。といっても、 たいていはせいぜい以下の 2 つのメソッドをオーバライドするぐらいで済むでしょ う:

__unicode__()

オブジェクトの「Unicode 表現」を返す、Python の「マジックメソッド」 です。 Python や Django はこのメソッドを使ってモデルインスタンスに 型強制を適用し、通常の文字列に変換したり表示したりしています。特に、 対話コンソールや管理インタフェース上でオブジェクトを表示するときに 使われています。

このメソッドは常に定義するよう勧めます。定義しておくと、いろいろと 便利だからです。

get_absolute_url()

このメソッドを定義しておくと、 Django にオブジェクトの URL を計算さ せられます。 Django の管理インタフェースなどで、オブジェクトに関連 した URL を特定するときにこのメソッドを使います。

オブジェクトを一意に特定できるような URL を持たせたいときには、この メソッドを定義しましょう。

既存のモデルメソッドをオーバライドする

他にも、データベースの動作をカプセル化していて、カスタマイズ可能な モ デルメソッド があります。特によく変更するのは、 save()delete() の動作でしょう。

こうしたモデルメソッドは、モデルオブジェクトの挙動を変えるために好きなだけ オーバライドできます。

組み込みメソッドをオーバライドする古典的なユースケースに、オブジェクトの保 存時に何か別の処理を行うというものがあります。例を示しましょう (save() のパラメタはドキュメントを参照してください。):

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        do_something()
        super(Blog, self).save(*args, **kwargs) # 「実際の」 save() を呼び出します。
        do_something_else()

また、以下のようにすれば保存を抑止できます:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        if self.name == "Yoko Ono's blog":
            return # Yoko は自分のブログを持っていません!
        else:
            super(Blog, self).save(*args, **kwargs) # 「実際の」 save() を呼び出します。

スーパクラスのメソッド呼び出し、つまり super(Blog, self).save(*args, **kwargs) を忘れないでください。この呼び 出しを忘れると、デフォルトの処理が行われないため、データベースにデータが保 存されません。

*args, **kwargs によってモデルメソッドに渡せる引数をパススルーすること も重要です。 Django は時々ビルトインのモデルメソッドに新しい引数を追加して 拡張することがあります。メソッド定義で *args, **kwargs を使っておけば、 これらの引数が追加されても自動でサポートされることが保証されます。

削除のオーバーライド

QuerySet による一括オブジェクト削除 の時にはオブジェクトの delete() メソッドが呼ばれないこ とに注意してください。カスタマイズした削除ロジックが実行されることを 保証するには pre_deletepost_delete シグナルのいずれかまたは 両方を使えば良いでしょう。

カスタム SQL の実行

もう一つよくあるパターンは、カスタムの SQL 文をモデルメソッドやモジュールレ ベルのメソッドにに書くというものです。詳しくは、 「 素の SQL を扱う 」を参照してください。

モデルの継承

Django のモデルクラス継承は、 Python の通常のクラス継承とほぼ同じように動作 します。モデル継承を実現するには、一つだけきめておかねばならないことがあり ます。それは、親クラスを (独自のデータベーステーブルを持った) 独立のモデル にしたいか、親クラスを共通情報の単なるホルダとして使い、子クラスでその情報 を扱う形にしたいかです。

Django には 3 種類のモデル継承スタイルがあります。

  1. 複数の子モデルクラスでいちいち同じ情報を入力せずに済ませるために、親モ デルクラスに共通の情報を持たせたいことはよくあります。親モデルクラスを 単体で使うことがないのなら、 抽象ベースクラス を使うのがよ いでしょう。
  2. 一方、(他のアプリケーションなどにある) 既存のモデルをサブクラス化して拡 張したり、個々のモデルに固有のデータベースを持たせたいような場合には、 マルチテーブル継承 を使うのがよいでしょう。
  3. 親モデルクラスのフィールドには手を加えず、 Python レベルでの振る舞いだ けを変えたいのなら、 プロキシモデル を使うのがよいでしょう。
抽象ベースクラス

抽象ベースクラスは、たくさんのモデルに共通する情報を入れておきたいときに便 利な仕組みです。抽象ベースクラスを定義するには、ベースクラス定義の、 Metaabstract=True を入れておきます。モデルを 抽象ベースクラスとして定義すると、そのクラスはデータベーステーブルを生成し ません。その代り、他のモデルを定義するときに抽象ベースクラスを親にすると、 ベースクラスのフィールドが子クラスに追加されます。抽象ベースクラスで定義し たフィールドと同じ名前のフィールドを子クラスで定義しようとするとエラーを引 き起こします (Django は例外を送出します)。

例を示しましょう:

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True

class Student(CommonInfo):
    home_group = models.CharField(max_length=5)

このように定義すると、 Student モデルは name, age および home_group の三つのフィールドを持つようになります。. CommonInfo モ デルは抽象ベースクラスなので、通常の Django モデルとしては使えません。 CommonInfo はデータベーステーブルを作らず、マネジャなども持ちません。

ほとんどの用途で使えるのは、このタイプのモデル継承でしょう。抽象ベースクラ スは、子クラスで共通の情報を Python レベルに切り出しながらも、データベース レベルでは、各子クラスに一つのデータベーステーブルを生成します。

Meta の継承

抽象ベースクラスを作成するとき、 Django は抽象ベースクラスの内部クラス Meta をクラス属性として参照できるようにします。子クラ スで Meta クラスを定義しない場合、親クラスの Meta がそのまま継承されます。子クラスで Meta を拡張したければ、親クラスをサブクラス化できます。 以下に例を示しましょう:

class CommonInfo(models.Model):
    ...
    class Meta:
        abstract = True
        ordering = ['name']

class Student(CommonInfo):
    ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

Django は抽象ベースクラスの Meta クラスを生成するとき に一つだけ手を加えます。すなわち、 Meta の属性を組み 込む前に、 abstract=False を設定するのです。これにより、抽象ベースクラ スの子クラスが自動的に非抽象ベースクラスになります。もちろん、他の抽象ベー スクラスを継承した新たな抽象ベースクラスも定義できます。継承するには、明示 的に abstract=True をセットしてください。

Meta クラスの属性の中には、抽象ベースクラスで定義して も意味のないものもあります。例えば、 db_table を抽象ベースクラスの Meta で定義すると、その子クラス全て (で、独自に Meta を定義しないもの) が、同じデータベーステーブルを 使おうとしてしまいます。

マルチテーブル継承

Django では、継承の各階層にいるクラスが抽象クラスでない実際のモデルであるよ うな、もう一つのタイプのモデル継承をサポートしています。各モデルはそれぞれ が一個のデータベーステーブルを表現していて、個別にクエリを発行したり、イン スタンスを生成したりできます。継承の関係によって、親クラスと子クラスの間に は (自動生成された OneToOneField によって) リン クが張られます。以下の例で説明しましょう:

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField()
    serves_pizza = models.BooleanField()

Place の全てのフィールドは、 Restaurant からも使えます。しかし、そ れぞれのフィールドのデータは別々のテーブルに格納されます。従って、以下のよ うな操作をどちらも実行できます:

>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

例えば、 Place であり、かつ Restaurant でもあるようなオブジェクトが あれば、モデル名を小文字にした属性を使って、 Place から Restaurant を取り出せます:

>>> p = Place.objects.get(id=12)
# p が Restaurant オブジェクトなら、子クラスを返す:
>>> p.restaurant
<Restaurant: ...>

ただし、上の pRestaurant クラスで ない のなら (Place から 直接生成されたオブジェクトや、他のクラスの親クラスなら) p.restaurant はエラーを引き起こします。

Meta とマルチテーブル継承

マルチテーブル継承では、子クラスが親クラスの Meta ク ラスを継承する意味がありません。 Meta オプションは全 て親クラスだけに適用されるべきもので、他のクラスに同じ内容を適用しても、矛 盾した振る舞いを引き起こすだけです(これは、独自のテーブルを持たない抽象ベー スクラスと対照的な部分です)。

従って、マルチテーブル継承の子クラスは親クラスの Meta クラスにアクセスする方法を持ちません。ただし、限られたケースで、子クラスが 親クラスの挙動を継承する場合があります。それは、子クラスで ordering または get_latest_by 属性を指定していない場合に、 親クラスの属性を継承するというものです。

親クラスで整列カラムが指定されていて、子クラス側で整列カラムを指定したくな い場合は、明示的設定を無効にしてください:

class ChildModel(ParentModel):
    ...
    class Meta:
        # 親クラスの整列カラム設定の効果を除去する
        ordering = []
継承と逆リレーション

マルチテーブル継承は親クラスと子クラスを暗黙の OneToOneField でリンクするので、前述の例のように、 親クラスから子クラスをたどれます。しかし、子クラスをたどるときに使う名前は、 ForeignKeyManyToManyField リレーションを定義したと きのデフォルトの related_name と同じ値 を使っています。従って、子クラスで ForeignKeyManyToManyField を別のクラスに向けて張る ときには、 必ず related_name をフ ィールドに指定せねばなりません。指定し忘れると、 Django は validatesyncdb 時にエラーを送出します。

例えば、上の Place クラスに対して、 ManyToManyField を持った別のサブクラスを定義する には、以下のように書きます:

class Supplier(Place):
    # Must specify related_name on all relations.
    customers = models.ManyToManyField(Restaurant, related_name='provider')
親クラスのリンクフィールドを定義する

すでに触れたように、 Django は子クラスと抽象クラスでない親クラスにリンクし た OneToOneField を自動的に生成します。親クラス へのリンク名を操作したければ、自分で OneToOneField を作成し、パラメタに parent_link=True を渡 してください。

プロキシモデル

マルチテーブル継承 を使う時には、各々のモ デルのサブクラスに新しくデータベーステーブルが作られます。サブクラスはデー タフィールドを追加して、親クラスにはない新しいデータを保存する箇所を増やす ので、これは一般的には望まれる動作です。

しかしながら、デフォルトのマネジャーを変えたり新しいメソッドを追加すること によって、同じモデルに対して Python の動作を変えたいだけのときがあります。 これが、プロキシモデル継承がある理由です。オリジナルのモデルに対して プロキシ を作ります。そうすれば、ただオリジナルのモデルを使用しているよ うに、プロキシモデルのインスタンスを作成、更新、削除して、全てのデータをセ ーブすることが出来ます。違いは、モデルの順序づけやデフォルトのマネジャーを オリジナルを改変せずに変更できるということです。

プロキシモデルは通常のモデルと同じように宣言します。 Django に対してそのモ デルがプロキシモデルであることを教えるためには、 Meta クラス内の proxy アトリビュートを True にします。

例えば、標準の User モデルに対してテ ンプレートの中で用いるメソッドを追加したい場合、このように定義します:

from django.contrib.auth.models import User

class MyUser(User):
    class Meta:
        proxy = True

    def do_something(self):
        ...

MyUser クラスは親である User クラ スと同じデータベーステーブル上で動作します。特に、 User のどんな新しいインスタンスでも、 MyUser を通してアクセスすることができます。逆も可能です:

>>> u = User.objects.create(username="foobar")
>>> MyUser.objects.get(username="foobar")
<MyUser: foobar>

また、モデルに別のデフォルトオーダーを定義する場合にもプロキシモデルを用い ることができます。標準の User モデル ではオーダーが定義されていません (ソートはコストがかかるので、ユーザを取得 する時にいつもそうしたくないため、故意にそうしています。) プロキシを使って いて、いつも username 属性で順序づけたい場合は、こうすると簡単です:

class OrderedUser(User):
    class Meta:
        ordering = ["username"]
        proxy = True

こうすると、普通の User のクエリでは 順序が定められていませんが OrderedUser のクエリは username で順序 づけられます。

クエリセットはリクエストされたモデルを返す

User オブジェクトへのクエリで Django に MyUser オブジェクトを返させることはできません。 User オブジェク トへのクエリセットは User 型のオブジェクトを返すでしょう。プロキシオブ ジェクトの全体的なポイントは、元の User に依存しているコードは元のモデ ルを使い、追加したコードは拡張を使えるということです。(他のどんなコードも 追加のコードに依存しません。) プロキシモデルは User (または他のどんな モデルも) を自分で作成したもので置き換える手段ではないのです。

親クラスの制限

プロキシモデルは抽象クラスでないモデルクラスを 1 つだけ継承しなくてはなり ません。抽象クラスでないモデルクラスの多重継承をすることはできません。プロ キシモデルは、異なるデータベーステーブルの行へのコネクションを提供していな いからです。プロキシモデルはモデルフィールドを定義して いない 抽象モデル クラスならばいくつでも継承することができます。

プロキシモデルは親の抽象モデルクラスから Meta オプションを継承します。

プロキシモデルマネジャー

もしプロキシモデルにモデルマネジャーを指定しなかった場合、マネジャーはモデ ルの親から継承します。もしマネジャーを定義すれば、それがデフォルトになりま す。それでも、親クラスに指定されたマネジャーを使用することも出来ます。

上述した例を続けましょう。User モデルに問い合わせる時使われるデフォル トのマネジャーを、このように変更することが出来ます:

class NewManager(models.Manager):
    ...

class MyUser(User):
    objects = NewManager()

    class Meta:
        proxy = True

もしプロキシに新しいマネジャーを加えたい場合、デフォルトで存在するものと置 き換えることなく、付け加えることができます。 custom manager のドキュメントで述 べているテクニックを使うことができます。 新しいマネジャーを含んだベースクラスを作成して、主なベースクラスの後にそれ を継承しています:

# Create an abstract class for the new manager.
class ExtraManagers(models.Model):
    secondary = NewManager()

    class Meta:
        abstract = True

class MyUser(User, ExtraManagers):
    class Meta:
        proxy = True

このテクニックを必要とすることはそんなにないでしょうが、可能です。

プロキシの継承とマネージされないモデルの違い

プロキシモデルの継承は、マネージされないモデルを作るのによく似ています。 マネージされないモデルは、モデルの Meta クラスに managed 属性を使うものです。 2 つの方法は全く同じものではないので、どちらを使った方がよいのか熟慮する 価値があります。

一つ目の違いは Meta.managed=False のモデルにはモデルフィールドを指定 できることです。 (そして実際、空のモデルを欲しいのでなければ、そうしなく てはいけませんね) 注意深く Meta.db_table を注意深く設定 することで、既存のモデルの影のような、しかし Python メソッドを追加する マネージされないモデルを作れます。しかしながら、それは新しく変更を加え る時に両方のコピーを同期させ続けなければならない脆弱なものになります。

もう 1 つの違いは、どのようにモデルのマネジャーが扱われるのかという、プ ロキシモデルにとってもっと大切な点です。プロキシモデルが意図しているの は、代理しているモデル自体のようにふるまうことです。だからデフォルトの マネジャーを含む親のモデルマネージャーを継承します。多テーブルのモデル を継承する場合、子は親からマネジャーを継承しません。エクストラフィールド が関係している場合は、カスタムマネジャーが適切であるとは限らないからです。 マネジャードキュメント にもっ と詳細な内容が載っています。

これら 2 つの特徴が実装されている時、これらを 1 つのオプションに押し込 めることが試みられました。そして継承の相互作用は一般的に、特にマネジャー は、 API をとても複雑にし、理解して使うことを難しくする可能性があると分 かりました。 2 つのオプションはあるケースでは必要だと分かりました。それ で、現在は 2 つのオプションが存在しています。

一般的なルールとして:

  1. 既存のモデルやデータベーステーブルをミラーしたくて、元のデータベース テーブルカラム全てを必要としない場合、 Meta.managed=False にして ください。このオプションはデータベースのビューとテーブルを Django の コントロール下に入れずにモデリングするのに役立ちます。
  2. Python でのみモデルの振る舞いを変えたいけれど、フィールドは同じものを 使いたい場合には Meta.proxy=True を使ってください。このように設定 すると、データがセーブされた時にプロキシモデルが元のモデルの構造を保 持したままの正確なコピーとなります。
多重継承

Python のサブクラスと同様、 Django のモデルも複数の親モデルクラスを継承でき ます。クラス内の名前解決には、 Python の通常の名前解決規則が適用されるので 注意してください。子クラスで特定の名前 (例えば Meta) を参照する場合、その名前を定義している最初のベースクラスの定義を使い、最初 に名前が見つかった時点で、それ以降同じ名前のオブジェクトの解決は行われませ ん。従って、複数の親クラスで別々に Meta クラスを定義 していても、最初のベースクラスの Meta だけが使われ、 それ以外は全て無視されます。

通常は、モデルの多重継承は必要ないでしょう。多重継承が便利なのは、主に特定 のフィールドやメソッドを追加するための ‘’mix-in’’ クラスを使う場合です。 継承の階層構造はできるだけ単純に、分かりやすくしておきましょう。さもないと、 子クラスで扱っている情報が、どの親クラスから来たか調べるために四苦八苦する はめになるでしょう。

フィールド名を「覆い隠すこと」は許可されていない

通常の Python クラスの継承では、子クラスで親クラスのどんな属性でもオーバラ イドすることができます。 Django では、 Field イ ンスタンスの属性は (少なくとも今のところは) オーバライドすることができませ ん。もし親クラスが author というフィールドを持っていたとして、親クラス を継承したどんなクラスの中でも新しく author フィールドを作ることはでき ません。

親モデルのフィールドをオーバライドすることは、インスタンスの初期化 (どのフ ィールドが Model.__init__ で初期化されるかを指定すること) 、そしてシリ アライズを困難なものにします。これらは通常の Python クラスの継承が全 く同じように扱う必要のない特徴です。つまり Django のモデル継承と Python ク ラスの継承との違いは決定的なものなのです。

この制限は Field インスタンスである属性のみに適 用されます。通常の Python 属性は望み通りにオーバーライドできます。また、こ の制限は Python が見ている属性の名前のみに適用されます。自身の手でデータベ ースのカラム名を指定するのなら、多テーブルの継承向けに同じカラム名を先祖と 子のクラス両方に登場させることもできます (二つの異なるデータベーステーブル のカラムとして)

先祖のモデルの中にあるモデルフィールドをオーバーライドしようとすると、 Django は FieldError を生じさせます。

クエリを生成する

revision-up-to:17812 (1.4)

データモデル を作成したら、次はデータベースからデー タを取り出す必要があります。このドキュメントでは、モデルから利用できるデー タベース抽象化 API と、オブジェクトを生成、取得、更新する方法について説明し ます。モデルの照合オプションの詳細は データモデルリファレンス を参照してください。

このリファレンスでは、以下のような Poll アプリケーションを参考に話を進めま す:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __unicode__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    def __unicode__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateTimeField()
    mod_date = models.DateTimeField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __unicode__(self):
        return self.headline
オブジェクトの生成

Django では、データベーステーブル上のデータを Python オブジェクトで表現する ために、モデルクラスがデータベーステーブルを表現し、クラスのインスタンスが テーブル上のレコードを表現するという直感的なシステムを使っています。

オブジェクトを生成するには、キーワード引数を使ってモデルクラスのインスタン スを生成し、 save() メソッドを呼び出して データベースに保存します。

モデルクラスは Python パス上のどこからでも import でき、期待通りに動作しま す (わざわざこのような説明をするのは、以前のバージョンの Django ではモデル の import 方法がかなり風変わりだったからです)。

モデルが mysite/blog/models.py というファイルで定義されているとすると、 オブジェクトの作成は以下の例のようになります:

>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()

この操作によって、背後では INSERT SQL 文が実行されます。 Django はユー ザが明示的に save() を呼び出すまで データベースを操作しません。

save() メソッドには戻り値がありません。

See also

save() には高度な使い方のための オプションがありますが、ここでは解説しません。詳しくは save() のドキュメントを参照してください。

ワンステップでオブジェクトを生成して保存するには create() メソッドを使って ください。

オブジェクトへの変更を保存する

すでにデータベース上にあるオブジェクトへの変更を保存するには save() を使います。

Blog インスタンス b5 がすでにデータベース上にあるとすると、以下の例 は b5 の名前を変更して、データベース上のレコードを更新します:

>> b5.name = 'New name'
>> b5.save()

この例では、背後で UPDATE SQL 文が実行されています。 Django は明示的に save() を呼び出すまでデータベースを操作しません。

ForeignKeyManyToManyField の保存

ForeignKey フィールドの更新は、 通常のフィールドへの変更と同じです。すなわち、 適切な型のオブジェクトを代入して保存すると、フィールドの値を更新でき ます。この例では、Entry のインスタンス entry``の ``blog アトリビュートを更新しています。:

>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()

ManyToManyField の更新は少し違います。 リレーションにレコードを一つ追加したい場合は add() メソッドを使いま す。この例では、 entry オブジレェクトに、 Author インスタンスの joe を加えています:

>>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe)

複数のレコードを ManyToManyField に一度で加えたい 場合、 add() に、 複数の引数をくるんで呼び出せばいいのです。:

>>> john = Author.objects.create(name="John")
>>> paul = Author.objects.create(name="Paul")
>>> george = Author.objects.create(name="George")
>>> ringo = Author.objects.create(name="Ringo")
>>> entry.authors.add(john, paul, george, ringo)

間違った型のオブジェクトを外部キーに代入したり add() したりすると Django はエラーを出します。

オブジェクトの取得

オブジェクトをデータベースから取得するには、モデルクラスのマネジャ Manager を介してクエリセット QuerySet を構築します。

QuerySet はデータベース上にある オブジェクトの集まりを表現しています。 QuerySet`には、集合を指定パラメタに従って 絞り込むための条件である*フィルタ (filter)* を複数個持たせられます。 SQL 用語でいえば、クエリセットは ``SELECT` 文であり、 フィルタは WHERELIMIT のような限定節にあたります。

QuerySet はモデル の:class:~django.db.models.Manager から取得します。モデルには最低一つの Manager があり、デフォルトでは objects という 名前がついています。マネジャにはモデルクラスから直接アクセスしてください:

>>> Blog.objects
<django.db.models.manager.Manager object at ...>
>>> b = Blog(name='Foo', tagline='Bar')
>>> b.objects
Traceback:
    ...
AttributeError: "Manager isn't accessible via Blog instances."

Note

(「テーブルレベル」の操作と「レコードレベル」の操作を分離させるため、マ ネジャはモデルのインスタンスではなくモデルクラスだけからアクセスできる ようになっています。)

モデル内での QuerySets の主なソースは Manager です。 マネジャは、データベースオブジェクト上の全てのオブジェクトを表す「ルートの」 クエリセットであるかのように振舞います。例えば、初期クエリセットである Blog.objects には、データベース上の全ての Blog オブジェクトが入っています。

全てのオブジェクトの取得

テーブルからオブジェクトを取得する最も単純な方法は全てのオブジェクトを取得 するというものです。全オブジェクトを取得するには、 Managerall() メソッドを使って下さい:

>>> all_entries = Entry.objects.all()

all() メソッドはデータベース上の全ての オブジェクトを表現する QuerySet() を返します。

(Entry.objects がクエリセットを返すというのなら、なぜ単に Entry.objects と書かないのでしょうか?それは、ルートのクエリセットであ る Entry.objects が特別扱いされていて、値評価できないようになっているか らです。 all() メソッドは、値評価 できる クエリセットを返します。

フィルタを使ってオブジェクトを取り出す

Manager によって提供される、 いわゆるルート QuerySet を使えば、 データベーステーブル上の全てのオブジェクトを表せます。とはいえ、 通常は全オブジェクトの集合からサブセットだけを取り出したいことでしょう。

サブセットを作成するには、フィルタ条件を追加して、 初期 QuerySet を リファインする必要があります。 QuerySet の洗練には、主に二つの方法があります:

filter(**kwargs)
指定した照合パラメタに一致するオブジェクトの集合を表現する、新たな QuerySet を返します。
exclude(**kwargs)
指定した照合パラメタに一致 しない オブジェクトの集合を表現する、 新たな QuerySet を返します。

照合パラメタ (上の関数定義における **kwargs) は、後述の フィールドの照合 で解説するフォーマットにせねばなりません。

例えば、 2006 年のブログエントリを表す QuerySet を取得するには、以下のように filter() を使います:

Entry.objects.filter(pub_date__year=2006)

(Entry.objects.all().filter(...) のように、 all() を使わなくてもよいことに注意して下さい。 all() を使っても問題なく動作しますが、 all() が必要となるのはルートクエリセットから 全てのオブジェクトを取り出したい場合だけです。)

フィルタの連鎖

QuerySet をリファインした結果は、 それ自体 QuerySet になります。 従って、リファイン操作は連鎖させられます。例えば:

>>> Entry.objects.filter(
...     headline__startswith='What'
... ).exclude(
...     pub_date__gte=datetime.now()
... ).filter(
...     pub_date__gte=datetime(2005, 1, 1)
... )

この例では、データベースの全てのエントリを表す初期クエリセットに対し、 filter() をかけた後に exclude() を実行し、さらにもう一つ filter() をかけています。最終的に得られるのは、 “What” で始まるヘッドラ インのうち、 January 1, 2005 から今日までの間に公開されたエントリです。

フィルタしたクエリセットは一意なオブジェクトである

QuerySet のリファインを行うと、 その都度新たなクエリセットを得ます。新たな QuerySet は 以前のクエリセットになんら縛られていません。リファイン操作のたびに、 別個の独立した QuerySet が作成され、個別に保存したり、 再利用したりできます。

例えば:

>> q1 = Entry.objects.filter(headline__startswith="What")
>> q2 = q1.exclude(pub_date__gte=datetime.now())
>> q3 = q1.filter(pub_date__gte=datetime.now())

これら 3 つのクエリセットは別個のものです。最初はヘッドラインが “What” で始 まる全てのエントリの入ったベースのクエリセットです。二つ目のクエリセットは、 最初のクエリセットのサブセットであり、 pub_date の値が現在時刻よりも大 きいものを排除します。三つ目のクエリセットも最初のクエリセットのサブセット で、 pub_date の値が現在時刻よりも大きいものだけを選択するようになって います。こうしたリファイン操作は、初期クエリセット (q1) に影響を及ぼし ません。

クエリセットは遅延評価される

クエリセットの評価は遅延型 (lazy) です。すなわち、 QuerySet の作成自体は データベース操作を引き起こしません。 QuerySet評価される までデータ ベースへのクエリを実行しないので、延々フィルタを重ねられます:

>>> q = Entry.objects.filter(headline__startswith="What")
>>> q = q.filter(pub_date__lte=datetime.now())
>>> q = q.exclude(body_text__icontains="food")
>>> print q

この例では、データベースに 3 度アクセスするように見えますが、実際には一度だ け、最後の行のとき (print q) しかアクセスしません。一般に、 QuerySet の結果は、その内容を「調べる」まで、データベースから取り出され ません。 QuerySet は、クエリの内容を調べたときにはじめて 値評価 され るのです。値評価がいつ行われているかは、 クエリセットはいつ評価されるのか で詳しく説明しています。

ゲットを使って一つのオブジェクトを取り出す

filter() は常に、 QuerySet を渡し、もし一つだけ オブジェクトがマッチするクエリ - のようなケースならば、 これは単一の要素を含んだ QuerySet です。

もし、クエリにマッチするのが一つだけだと分かるなら、 Managerget() メソッドが使えます。 これはオブジェクトを直接的に返します。:

>>> one_entry = Entry.objects.get(pk=1)

filter() と同じように、 クエリは get() と一緒に使えます、 もう一度 フィールドの照合 を見てください。

get() を使うのと、 filter()[0] でスライス するのとでは違いがあります。もし、クエリにマッチするものがなかった時、 get()DoesNotExist 例外を 送出します。この例外はモデルクラスの属性で、クエリは上にあるコードのように 動きます、もし Entry オブジェクトに 1 というプライマリーキーがないなら、 Django は Entry.DoesNotExist 例外を送出します。

同様に、 Django は get() クエリで 一つ以上のアイテムとマッチした場合にも例外を送出します。このようなケースでは、 MultipleObjectsReturned がモデルクラス自身の属性に反しています。

その他のクエリセットメソッド

ほとんどの場合、データベース上のオブジェクトを照合するには、 all() か、 get() filter() exclude() メソッドで事足ります。とはいえ、クエリセットがサポートしているメソッドは もっとたくさんあります。クエリセットメソッドの詳細な説明は、 クエリセット API リファレンス を参照してください。

クエリセットに制約を課す

クエリセットの返す結果を特定の個数に制限したい場合には、 Python の配列スラ イス表記を使います。これは SQL の LIMIT 節や OFFSET 節と等価です。

以下の例は、最初の 5 オブジェクトだけを返します (LIMIT 5 に相当します):

>>> Entry.objects.all()[:5]

以下の例は、 6 番目から 10 番目までのオブジェクトを返します (OFFSET 5 LIMIT 5 に相当します):

>>> Entry.objects.all()[5:10]

負の数でのインデクシングはサポートしていません。 (すなわち、 Entry.objects.all()[-1] このようなものです)

一般に、 QuerySet をスライスしても QuerySet を新たに生成して返すだけで、 クエリの評価は行いません。例外はスライス表記に「ステップ (step)」パラメタを 使ったときです。以下の例では、クエリを実際に実行し、最初の 10 オブジェクト 中から 1 つおきにオブジェクトを取り出したリストを返します:

>>> Entry.objects.all()[:10:2]

リストではなく 単一の オブジェクトを取得したい場合 (SELECT foo FROM bar LIMIT 1 のような場合) には、スライスではなく単純な インデクス指定を行います。以下の例はデータベースのエントリをヘッドラインに ついてアルファベット順に整列した後、最初の Entry を取得して返します:

>>> Entry.objects.order_by('headline')[0]

これはだいたい以下と同じになります:

>>> Entry.objects.order_by('headline')[0:1].get()

ただし、指定条件にマッチするオブジェクトがない場合、前者は IndexError, 後者は DoesNotExist を送出します。詳しくは get() のドキュメントを参照してください。

フィールドの照合

フィールドの照合操作によって、 SQL の WHERE 節の中身が決まります。フィー ルドの照合を行うには、 filter(), exclude() および get() といった QuerySet のメソッドのキーワード引数を指定します。

基本的に、照合のキーワード引数名は field__lookuptype=value のような形 式をとります (アンダースコアは二重です)。例えば:

>>> Entry.objects.filter(pub_date__lte='2006-01-01')

は、(大雑把にいって) 以下のような SQL 文に変換されます:

SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

これがどうして可能なのか

Python には、任意の名前と値をもった引数を受け取れる関数を定義する機能が あり、引数名とその値は実行時に評価されます。くわしい情報は公式の Python チュートリアルの キーワード引数 を参照してください。

照合の中でのフィールドの指定は、モデルフィールドの名前でなければいけませ ん。 ForeignKey の場合、例外ががありますが、 フィールドネームを _id というサフィックス(suffix)で指定できます。 このようなケースでは、バリューパラメータはフォーリンモデルの プライマリーキーの生の値を含みます。例えば::
>>> Entry.objects.filter(blog_id__exact=4)

照合時に無効なキーワード引数が渡されると、 TypeError が送出されます。

データベース API は 2 ダース近くの照合タイプをサポートしています。詳しいリ ファレンスは フィールド照合リファレンス を参照してく ださい。ここでは、よく使う照合タイプをいくつか示します:

exact

「厳密一致」です。例えば:

>>> Entry.objects.get(headline__exact="Man bites dog")

は、以下のような SQL を生成します:

SELECT ... WHERE headline = 'Man bits dog';

照合タイプを指定しなかった場合、つまり二重アンダースコアの入ったキー ワード引数を使わないかぎり、照合条件は exact とみなされます。

例えば、以下の二つの文は同じ意味です:

>>> Blog.objects.get(id__exact=14)  # Explicit form
>>> Blog.objects.get(id=14)         # __exact is implied

exact はよく使われるため、便宜的にこのような仕様にしています。

iexact

大小文字を区別しない一致です。以下のクエリ:

>>> Blog.objects.get(name__iexact="beatles blog")

は、 “Beatles Blog”, “beatles blog”, “BeAtlES blOG” といったタイト ルの Blog オブジェクトにマッチします。

contains

大小文字を区別する部分一致テストです。以下のクエリ:

Entry.objects.get(headline__contains='Lennon')

は、おおざっぱにいって以下の SQL に変換されます:

SELECT ... WHERE headline LIKE '%Lennon%';

'Today Lennon honored' には一致しますが、 'today lennon honored' には一致しないので注意してください。

大小文字を区別しない icontains もあります。

startswith, endswith
それぞれ、前方一致と後方一致です。大小文字を区別しない istartswithiendswith もあります。

ここに挙げたのはほんの一部です。全ての照合タイプの解説は フィールド照合タイプのリファレンス を参照してくださ い。

リレーションをまたいだ照合

Django では、背後で自動的に SQL JOIN を処理し、照合の際にリレーションを 「追跡」する、強力でありながら直感的な手段を提供しています。リレーションを またぐには、二重アンダースコアを使ってリレーションの張られたフィールドのフィー ルド名を指定します。リレーション間のスパンは、目的のフィールドに到達するま でいくらでも連鎖させられます。

以下の例では、 name'Beatles Blog' であるような BlogEntry エントリオブジェクト全てを取得します:

>>> Entry.objects.filter(blog__name__exact='Beatles Blog')

スパンは好きなだけ深く張れます。

リレーションのスパンは逆方向にも張れます。「逆方向の」リレーションを参照す るには、モデル名を小文字にした名前を使います。

以下の例では、 headline'Lennon' を含むような Entry を少なく とも一つ持つような全ての Blog オブジェクトを取得します:

>>> Blog.objects.filter(entry__headline__contains='Lennon')

複数のリレーションをまたいでフィルタを行っていて、中間のモデルにフィルタ条 件に合致する値が存在しないと、 Django はその値が空である (NULL が入って いる) だけの有意なオブジェクトとして扱います。つまり、エラーを送出しません。 例えば、以下のフィルタを考えましょう:

Blog.objects.filter(entry__author__name='Lennon')

(Author モデルは存在するものとします) entryauthor を空にし ていると、 Django は author が存在しないために name を辿れませんが、 エラーは送出せず、あたかも name も空であるかのように扱います。たいてい は、この仕様で期待通りに動きますが、 isnull を使うと、少し混乱をきたし ます。すなわち:

Blog.objects.filter(entry__author__name__isnull=True)

は、 authorname が空の Blog だけでなく、 entryauthor が空の Blog も返してしまうのです。後者のオブジェクトを返して 欲しくないのなら、以下のように書いてください:

Blog.objects.filter(entry__author__isnull=False,
        entry__author__name__isnull=True)
多値のリレーションをスパンする

ManyToManyFieldForeignKey の逆リレーションを使ってフィルタを行 う場合、 2 種類の異なるフィルタ方法があります。 Blog / Entry のリレー ション (Blog から Entry が 1 対多であるようなリレーション) を考えて みましょう。このようなモデルでは、例えばヘッドラインに ‘Lennon’ を含み、 かつ 2008 年に公開されたエントリを持つようなブログを検索したい場合があ るでしょう。あるいは、ヘッドラインに ‘Lennon’ を含むか、 あるいは 2008 年に公開されたエントリを含むようなブログの検索もあり得ます。複数のエン トリが一つの Blog に関連付けられているので、いずれのクエリも実行可能で すし、意味をなす場合があるでしょう。

ManyToManyField を使っている場合にも、 同じような状況が起こります。例えば、 Entrytags という名前の ManyToManyField があり、 “music”“band” というタグに関連付けられたエントリを検索したい場合や、 “music” タグのついた “public” 状態のエントリを取り出したい場合があるで しょう。

こうした状況をうまく扱うために、 Django には filter() および exclude() といった呼び出しがあります。 filter() に指定した条件は同時に適用され、 条件全てに一致する要素をフィルタします。 filter() を連続 して呼び出すと、通常はオブジェクトの集合により狭い制約をかけますが、多値リ レーションの場合、新たな制約は、前の filter() で絞り込んだリレーション 先をさらに絞り込むのではなく、前の filter() で絞り込んだリレーション先 にリンクしているリレーション元からリレーションを張られている全てのオブジェ クトに対して適用されてしまいます。

この話はちょっとややこしいので、例を挙げて解説しましょう。 ‘Lennon’ をヘッ ドラインに含み、 2008 年に公開されたエントリを含むブログを選択するには、以 下のように書きます:

Blog.objects.filter(entry__headline__contains='Lennon',
        entry__pub_date__year=2008)

一方、 ‘Lennon’ をヘッドラインに含むか、 あるいは 2008 年に公開された エンリを含むブログを検索するには、以下のように書きます:

Blog.objects.filter(entry__headline__contains='Lennon').filter(
        entry__pub_date__year=2008)

後者の例では、最初の filter() でクエリセットに制約をかけ、特定のエント リにリンクを持つブログだけを取り出しています。次の filter() では、取り 出した Blog オブジェクトから、 さらに 二つ目の条件に合うものに制約を かけています。従って、二つ目の filter() で制約をかけている対象の entry は、最初のフィルタで絞り込んだエントリと同じときもあれば、違うと きもあります。一つめの filter() でフィルタしているのはあくまでも Blog であって、 Entry ではないからです。

この挙動は、 exclude() にもあてはまります。 一つの exclude() に指定した条件は、 (多値リレーションの場合は) 各インスタンスに同時に適用されます。 filter()exclude() を連続して呼び出すと、 毎回違うリンク先集合を使ってフィルタを行ってしまう可能性があるのです。

フィルタはモデルのフィールドを参照できる

これまで与えられた例の中で、私たちはフィルタを同じモデルフィールドの バリューと比較してきました。しかし、モデルの値を同一のモデルの別のフィールドと 比較したい場合はどうしたらよいのでしょう?

Django は F() expressions をこの比較のために 提供しています。 F() のインスタンスはクエリの内側のモデルフィールドへの 参照として働きます。これらのは同じモデルインス タンスの異なる二つのフィールドを比較するクエリフィルターです。

例えば、これは pingbacks よりコメントが多い全てのブログエントリーのリスト を見つけるものです。 F() オブジェクトを使って、 pingback のカウント数 が参照できるようにすます。:

>>> from django.db.models import F
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))

Django は追加や削除、かけ算、分割と剰余などの計算も F() オブジェクトで 使えるようにサポートしています。ブログエントリーの中で、 pingbacks よりコメン トが 二倍 以上あるものを抽出するには、クエリをこのようにします:

>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)

ブログエントリーの中で、 pingback 自体ののカウント数とコメント数よりも ブログエントリーの、エントリーのレーティングが小さい・少ないものにするには このようにクエリを書きます。:

>>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))

また、 F() オブジェクト内で離れた関係を表記するために、ダブルアンダー スコア表記を用いることができます。ダブルアンダースコア付きの F() オブジェクトは、ひもづいているオブジェクトへのアクセスが必要な 時のために存在しています。例えば、作者の名前がブログの名前と同じ 全てのエントリーを取り出そうとしたとき、このようなクエリが発行できます。

>>> Entry.objects.filter(authors__name=F('blog__name'))
リリースノートを参照してください

date と date/time フィールドは、 timedelta オブジェクト で足したり引いたりできます。これは発行されてから三日以上経た全ての エントリーを抽出するクエリです:

>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))
pk 照合ショートカット

利便性のために、 Django には pk という照合形式があります。 pkprimary_key を表します。

Blog モデルの例では、主キーは id フィールドなので、以下の二つの文は 等価です:

>>> Blog.objects.get(id__exact=14) # 明示的な形式
>>> Blog.objects.get(id=14) # 暗黙で __exact を表す
>>> Blog.objects.get(pk=14) # pk は暗黙で id__exact を表す

pk__exact のクエリにしか使えないわけではありません。どのクエリ 用キーワードも pk と組み合わせてかまいません。 pk を使うと、モデル の主キーに対するクエリを表します:

# id が 1, 4 および 7 のブログエントリを取得する
>>> Blog.objects.filter(pk__in=[1,4,7])

# id > 14 の全てのブログエントリを取得する
>>> Blog.objects.filter(pk__gt=14)

pk による検索は join 越しでも行えます。 例えば、以下の二つの文は等価で す:

>>> Entry.objects.filter(blog__id__exact=3) # 明示的な形式
>>> Entry.objects.filter(blog__id=3)        # 暗黙で __exact を表す
>>> Entry.objects.filter(blog__pk=3)        # __pk は暗黙で __id__exact を表す
LIKE 文におけるパーセント記号とアンダースコアのエスケープ

LIKE を使う SQL 文になるようなフィールド照合メソッド (iexact, contains, icontains, startswith, istartswith, endswith, iendswith) では、 LIKE 文で使われる二つの特殊な文字、すなわちパーセ ント記号とアンダースコアを自動的にエスケープします。 (LIKE 文では、パー セント記号は任意の複数文字に対するワイルドカードを表し、アンダースコアは任 意の一文字に対するワイルドカードを表します。)

この機能によって、照合操作を直感的に行え、データベースの抽象化を守れます。 例えば、パーセント記号を含むようなエントリ全てを取得したければ、以下のよう にパーセント記号をそのまま使います:

>>> Entry.objects.filter(headline__contains='%')

Django はクオートの処理に気を配ってくれます。 SQL は以下のような感じになり ます:

SELECT ... WHERE headline LIKE '%\%%';

アンダースコアについても同じようなエスケープを行います。パーセント記号とア ンダースコアはいずれも透過的に処理されます。

キャッシュとクエリセット

データベースへのアクセスを最小限にとどめるため、 QuerySet 各々にはキャッシュがあります。 効率的なコードを書く上で、キャッシュのからくりを理解しておくのは重要なことです。

QuerySet が新たに生成された時点では、 キャッシュは空です。 QuerySet を 最初に評価したとき (すなわち、データベースへのクエリが最初に生じたとき)、 Django はクエリ結果をクエリセットオブジェクト内のキャッシュに保存し、明示的 にリクエストした結果だけ (例えば、 QuerySet‘s に対してイテレーション操作を する場合には、結果セットの最初の要素) を返します。それ以後は、 QuerySet‘ を再利用するとキャッシュ済みの結果を返します。

このキャッシュの挙動をよく覚えておいて下さい。というのも、 QuerySet を正しく扱わないと、 おもわぬところで手を噛まれるはめになるからです。例えば、以下の例では 二つの QuerySet を作成し、値を評価して、 すぐにクエリセットを捨ててしまっています:

>>> print [e.headline for e in Entry.objects.all()]
>>> print [e.pub_date for e in Entry.objects.all()]

そのため、全く同じデータベースクエリを二度実行し、データベースの負荷を倍加 させています。また、 Entry は二つのリクエストを処理する間にも追加された り削除されたりする可能性があるため、二つのリストには必ずしも同じデータベー スレコードが入っているとは限りません。

こうした問題を避けるには、 QuerySet を保存して再利用してください:

>>> queryset = Entry.objects.all()
>>> print [p.headline for p in queryset] # クエリセットを評価します。
>>> print [p.pub_date for p in queryset] # キャッシュの値を再利用します。
Q オブジェクトを使った複雑な照合

filter() などで複数の キーワード引数を指定してクエリを行うと、各々のキーワード引数の表す照合条件は 違いに “AND” で結ばれます。より複雑なクエリ (例えば OR を使ったクエリ) を 実行する必要がある場合には Q オブジェクトを使えます。

Q オブジェクト (django.db.models.Q) は、 複数のキーワード引数をカプセル化するために使われます。 キーワード引数は前述の 「フィールドの照合」で説明したものと同じです。

例えば、以下の Q オブジェクトは単一の LIKE クエリをカプセル化してい ます:

from django.db.models import Q
Q(question__startswith='What')

Q オブジェクトは &| といった演算子で組み合わせられます。二 つの Q オブジェクトを演算子で結ぶと、新たな Q オブジェクトを生成し ます。

例えば、以下の文は二つの question__startswith クエリを “OR” したものを 表す単一の Q オブジェクトを生成します:

Q(question__startswith='Who') | Q(question__startswith='What')

この Q オブジェクトは以下の WHERE 節と等価です:

WHERE question LIKE 'Who%' OR question LIKE 'What%'

Q オブジェクトを &| で組み合わせれば、好きなだけ複雑なクエ リ文を作成できます。丸括弧を使ったグルーピングも可能です。また、 ~ 演算 子を使えば Q オブジェクトの「否 (nagate)」を取れるので、例えば以下のよ うに、通常のクエリと否のクエリの積をとれます:

Q(question__startswith='Who') | ~Q(pub_date__year=2005)

キーワード引数をとる照合関数 ( filter() exclude() get() など) には、複数の Q を固定引数として (名前なしの引数として) 渡せます。複数の Q オブジェクトを照合関数に渡した場合、それらは互いに “AND” で結ばれます。 例えば:

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

は、だいたい以下のような SQL になります:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

照合関数は Q オブジェクトとキーワード引数を混ぜて使えます。照合関数に渡 した全ての引数は (キーワード引数も Q オブジェクトも) 互いに “AND” で結 ばれます。ただし、 Q を指定する場合はどのキーワード引数よりも前に指定せ ねばなりません。たとえば:

Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who')

は有効なクエリで、前の例と同じになりますが、以下の文:

# INVALID QUERY
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

は無効です。

See also

OR lookups examples の例には、 Q を使った Django のユニット テストがあります。

オブジェクトの比較

二つのモデルオブジェクトを比較するには、標準の Python 比較演算子、すなわち 二重等号符: == を使います。背後では二つのモデルオブジェクト間の主キー値 が比較されます。

上の Entry の例では、以下の二つの文は等価です:

>>> some_entry == other_entry
>>> some_entry.id == other_entry.id

モデルの主キーが id という名前でなくても問題はありません。どのような名 前であれ、比較は常に主キーを使って行われます。例えば、モデルの主キーのフィー ルド名が name であれば、以下の二つの文は等価です:

>>> some_obj == other_obj
>>> some_obj.name == other_obj.name
オブジェクトの削除

削除用のメソッドには、 便宜的に delete() という名前が付いてます。 このメソッドはオブジェクトをただちに削除し、戻り値を返しません:

e.delete()

複数のオブジェクトの一斉削除も可能です。 QuerySet には QuerySet() の全てのメンバを削除します。

例えば、 pub_date が 2005 年の Entry オブジェクトを全て削除するには 以下のようにします:

Entry.objects.filter(pub_date__year=2005).delete()

忘れてならないのは、この処理はできる限り SQL レベルで行われるため、 delete() メソッドが全てのインスタンスの delete() メソッドを呼ぶとは 限らないということです。モデルクラス上で delete() をカスタマイズしてい て、オブジェクトを削除するときに呼び出したいのなら、 QuerySetdelete() メソッドで一括削除するのではなく、直接 ( QuerySet の各要素を 取り出して逐次 delete() を呼ぶなどして) 「手動で」インスタンスを削除せ ねばなりません。

Django は、オブジェクトを削除する際に、通常 SQLでいう ON DELETE CASCADE 制約をエミュレートします。すなわち、 削除対象のオブジェクトを指すような外部キーを持つ全てのオブジェクトも 同時に削除されるのです。:

b = Blog.objects.get(pk=1)
# 次の命令は、 Blog と Blog を指す Entry 全てを削除してしまいます。
b.delete()
このカスケードの挙動は ForeignKeyon_delete 引数を通して変えることが出 来ます。

delete()QuerySet のメソッドにすぎず、 Manager 自体には公開 されていないので注意してください。これは誤って Entry.objects.delete() を実行して 全ての エントリを削除してしまわないようにするための安全機構で す。本当に全てのオブジェクトを削除 したい のなら、以下のように明示的に全 てのオブジェクトを表すクエリセットをリクエストしてください:

Entry.objects.all().delete()
モデルインスタンスをコピーする

モデルインスタンスをコピーする組み込みのメソッドは提供されていません、 ですが全てのフィールドとバリューを同一にした新しいインスタンスを簡単に作成する ことができます。最もシンプルなケースでは、 pkNone にすることができ ます。ブログの例を使うと:

blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # post.pk == 1

blog.pk = None
blog.save() # post.pk == 2

継承を使うと、もう少し複雑になってしまいます。 Blog のサブクラスについて 考えてみましょう。:

class ThemeBlog(Blog):
    theme = models.CharField(max_length=200)

django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme = 'python')
django_blog.save() # django_blog.pk == 3

継承の働きによって、 pkid を None にしなくてはいけません:

django_blog.pk = None
django_blog.id = None
django_blog.save() # django_blog.pk == 4

このプロセスはひもづいているオブジェクトをコピーしません。もし、関係性のあるも のもコピーしたいのならば、もう少し多めにコードを書かなければいけません。 EntryAuthor に many to many フィールドを持っている場合:

entry = Entry.objects.all()[0] # some previous entry
old_authors = entry.authors.all()
entry.pk = None
entry.save()
entry.authors = old_authors # saves new many2many relations
複数のオブジェクトを一度に更新する

QuerySet が表現する全てのオブジェクトのある フィールドに特定の値を指定したいような場合があります。 update() メソッドを使えば、 この処理を実現できます。例えば:

# pub_date が 2007 の全エントリのヘッドラインを更新する
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

この操作を行えるのは、リレーションフィールドでないフィールドか、 ForeignKey のフィールドのみです。また、フィールドに指定する値はハードコー ドされた Python の値でなければなりません (つまり、その時の何らかのフィール ド値は直接セットできません)。 ForeignKey のフィールドを更新するには、以下のように、 新たなモデルインスタンスを作成して渡します:

>>> b = Blog.objects.get(pk=1)

# 全てのエントリをこの blog に属させる
>>> Entry.objects.all().update(blog=b)

update() メソッドは (delete() と同様)、即座に適用され、値を返しませ ん。また、更新対象のクエリセットには、モデルの主のテーブル一つに対してし かアクセスできないという制限があります。フィルターは関係するテーブルに 使えますが、アップデートできるのはモデルのメインテーブルのカラムだけです。:

>>> b = Blog.objects.get(pk=1)

# この blog に属している全ての headline をアップデートします。
>>> Entry.objects.select_related().filter(blog=b).update(headline='Everything is the same')

update() メソッドは SQL 文に直接変換されるので注意してください。このメ ソッドは、フィールド値の直接更新を大量一括実行するためのものです。 モデルの save() メソッドを呼出さないので、 ( QuerySet の呼び出しに連動している) pre_savepost_save といった シグナルは発生しません。QuerySet 内の全ての要素に対して save() メソッドを適用したければ、 単に全要素に渡って save() を呼び出してください:

for item in my_queryset:
    item.save()

モデルの中の別フィールドの値によって別フィールドをアップデートするには F() objects も使えます。これは、特に 最新の値によってカウンタを増加させたい場合に使えます。例えば、 pingback のカウント数をブログのエントリごとに増加させるには:

>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)

しかしながら、 F() はフィルタ内と EXCLUDE 句とは 違うところもあり、 アップデートに F() オブジェクトを使った時には JOIN が使えません。 つまり、アップデートされるモデル内で参照できるフィールドのみを使えるという ことです。もし、 JOIN を F() オブジェクトで使おうとした場合、 FieldError が生じます。:

# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))
生 SQL へのフォールバック

Django のデータベースマッパで扱うには複雑すぎる SQL 文を書かねばならないよ うな場合には、生の SQL 文実行モードを使えます。Django は生 SQL 文をクエリ とうる方法を二つ持っています。 素の SQL クエリを直接実行する を見てください。

生 raw-SQL 文実行モードの使い方としてお勧めなのは、そのようなクエリ文を実行 するモデルのカスタムメソッドやカスタムマネジャのメソッドを実装するというも のです。 Django はモデルレイヤでデータベースクエリを記述するように 何ら要求してはいません が、このアプローチをとることで、データアクセスのた めのロジックを一箇所にまとめられるので、コード組織化の観点からスマートにな ります。詳しい説明は topics-db-sql を参照してください。

最後に、 Django のデータベースレイヤは単にデータベースへの一つのインタフェー スに過ぎないということに注意しておきましょう。データベースには他のツールや プログラム言語、データベースフレームワークを介してアクセスできます。データ ベースについて Django 固有の何かがあるわけではないのです。

集約(Aggregation)

revision-up-to:17812 (1.4)

このトピックは Djangoのデータベース抽象API において個別のオブジェクトの作成、取得、削除を行うDjangoのクエリの使い方で 説明されています。しかし、オブジェクトのコレクションの合計を取ったり、 集約 したりすることで引き出された値を取得しなければならないことがあります。 このトピックガイドはDjangoクエリを使って集約値がどうやって生成されたり 返されたりするのかを解説します。

このガイドでは以下のモデルを使います。これらモデルはオンライン書店の一連 の在庫を管理するために使われます。

class Author(models.Model):
   name = models.CharField(max_length=100)
   age = models.IntegerField()
   friends = models.ManyToManyField('self', blank=True)

class Publisher(models.Model):
   name = models.CharField(max_length=300)
   num_awards = models.IntegerField()

class Book(models.Model):
   isbn = models.CharField(max_length=9)
   name = models.CharField(max_length=300)
   pages = models.IntegerField()
   price = models.DecimalField(max_digits=10, decimal_places=2)
   rating = models.FloatField()
   authors = models.ManyToManyField(Author)
   publisher = models.ForeignKey(Publisher)
   pubdate = models.DateField()

class Store(models.Model):
   name = models.CharField(max_length=300)
   books = models.ManyToManyField(Book)
チートシート

お急ぎですか? 上のモデルを使った場合の一般的な集約クエリは以下のようになり ます

# 書籍の合計数
>>> Book.objects.count()
2452

# publisher=BaloneyPress の場合の書籍の合計数
>>> Book.objects.filter(publisher__name='BaloneyPress').count()
73

# 全書籍の平均価格
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}

# 最も高額な書籍
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max('price'))
{'price__max': Decimal('81.20')}

# 出版社ごとの書籍数を "num_books"属性で
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
[<Publisher BaloneyPress>, <Publisher SalamiPress>, ...]
>>> pubs[0].num_books
73

# トップ5の出版社を書籍数の多い順に
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
>>> pubs[0].num_books
1323
QuerySetに対して集約を生成する

Djangoでは集約を生成するのに2つの方法が用意されています。最初の方法は、 全 QuerySet に対して合計値を生成する物です。例えば、売り出されている 全ての書籍の平均値を計算したい場合などです。Djangoのクエリ文法では、全書籍 セットを表現するには以下の方法が用意されています

>>> Book.objects.all()

必要なのはこの QuerySet に含まれるオブジェクトに関しての合計値を計算 する方法です。これは aggreagte() 句を QuerySet に加えることで 行われます。

>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg('price'))
{'price__avg': 34.35}

all() はこの例では冗長なので、 次のように簡素化できます

>>> Book.objects.aggregate(Avg('price'))
{'price__avg': 34.35}

aggregate() 句への引数は計算したい集約値を表します – この例では、 Book モデルの price フィールドの平均になります。 利用可能な集約関数の一覧は QuerySet リファレンス にあります。

aggregate()QuerySet の最後の句になります。それが呼び出されると、 name-valueペアの辞書が返されます。nameは集約値に対する識別子です;valueは 計算された集約値です。 name はフィールド名と集約関数より自動的に生成されます。 集約値の名前を手動で指定したいのであれば、集約句を指定する際にその名前を 指定します

>>> Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}

1つ以上の集約を生成したいのであれば、 aggregate() 句に別の引数を 追加するだけです。よって、全書籍の最高の定価と最低の定価を知りたいのであれば 、次のクエリを発行します

>>> from django.db.models import Avg, Max, Min, Count
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
QuerySetの各アイテムを集約する(注釈付け)

サマリ値を生成する2つ目の方法は QuerySet の各オブジェクトに対して 個別のサマリを生成することです。例えば、書籍の一覧を取得しているとすれば、 それぞれの書籍に寄稿している著者が何名いるのかを知りたいこともあるでしょう。 各書籍は Author に対して many-to-many の関係を持っています;この QuerySet での関連をサマリ化できます。

オブジェクトごとのサマリは annotate() 句を使うことで生成することができ ます。 annotate() が指定されると、 QuerySet の各オブジェクトは 指定された値で注釈付け( annotate )されます。

これらの注釈付け ( annotation ) 構文は aggregate() 句で使われる物と 全く同じです。 annotate() への各引数は計算される注釈付けを意味します。 例えば、Bookを著者数で注釈付けするには

# 注釈付けされるクエリセットを組み立てる
>>> q = Book.objects.annotate(Count('authors'))
# クエリセットの最初のオブジェクトを取得
>>> q[0]
<Book: The Definitive Guide to Django>
>>> q[0].authors__count
2
# クエリセットの2番目のオブジェクト取得
>>> q[1]
<Book: Practical Django Projects>
>>> q[1].authors__count
1

aggregate() と同様に, 注釈(annotation)の名前は集約関数の名前と集約される フィールド名で自動的に作成されます。 注釈付けを指定する時にエイリアス名を 指定すると、このデフォルトの名前をオーバーライドすることができます

>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1

aggregate() とは違って, annotate() は最終句では ありませんannotate() 句の出力は QuerySet です; この QuerySet は他の QuerySet オペレーションによって修正可能です。 filter()order_by などが使え、また別の annotate() 呼び出しさえも可能です。

Joinと集約

ここまではクエリを受けるモデルに帰属するフィールドに対して集約することに 関して扱ってきました。しかし、集約したい値が、クエリを受けるモデルの関連 するモデルに属することもあります。

集約関数の中で集約したいフィールドを指定するときには、 Djangoではフィルタ において、関連フィールド参照するときにつかわれるのと同じ 二重アンダースコア表記 を使うことことができ ます。 そうすれば Django は関連した値を取得して集約するために必要な任意 のテーブルをjoinしてくれます。

例えば、それぞれのお店で提供されている書籍の価格帯を見つけるにはこのような 注釈付けを行うと良いでしょう

>>> Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price'))

こうすると Django は Store モデルを取得し( many-to-many 関連を通じて ) Bookモデルと join し、書籍のpriceフィールドに関して注釈付けして最小値と 最大値を生成してくれます。

同じルールは aggregate() 句にも適用されます。あるお店で売られている 任意の書籍の最安値と最高値を知りたいのであれば、次のような集約を使います:

>>> Store.objects.aggregate(min_price=Min('books__price'), max_price=Max('books__price'))

Joinのチェーンは必要なだけ深くできます。例えば、売り出し中の任意の書籍の 中で最も若い著者の年齢を取得するには、次のようなクエリを発行します

>>> Store.objects.aggregate(youngest_age=Min('books__authors__age'))
集約と他のQuerySet句
filter()exclude()

集約はフィルタに参加させることができます。 任意の filter() (あるいは exclude() ) を通常のフィールドに適用すれば、集約したいオブジェクトの 制約をさせる効果が得られます。

annotate() 句を使うと、 フィルタは注釈付け計算したいオブジェクト を制限できるようになります。例えば、次のクエリを使うと表題が “Django”で 始まる全ての書籍に関しての注釈付けリストを生成することが出来ます

>>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors'))

aggregate() 句を使うと集約計算したいオブジェクトを制限できるように なります。例えば、次のクエリを使うと表題が”Django”で始まる全ての書籍の 平均価格を生成することができます

>>> Book.objects.filter(name__startswith="Django").aggregate(Avg('price'))
注釈付けに対するフィルタリング

注釈付けされた値もフィルターできます。 他のモデルフィールドと同じ方法で、 filter()exclude() 句で注釈付けのエイリアスを使うことで来ます。

例えば、作家が一人以上いる書籍の一覧を生成するには、次のクエリを発行します:

>>> Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1)

このクエリは注釈付けした結果セットを生成して、その注釈付けを元にした フィルタを生成します。

annotate() 句と filter() 句の順番

annotate() 句と fitler() 句 の両方を含んだ複雑なクエリを開発している のであれば、これらの句がその QuerySet に適用される順番に付いて特に注意 を払うべきです。

クエリに annotate() 句が適当される時は、 注釈付けはそれが要求された時点 までのクエリの状態に関して注釈付けが行われます。 これが実際に意味することは、 filter()annotate() は代替可能な 操作ではないということです – すなわち、クエリ間で結果の差があるということ です。

>>> Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0)

と次のクエリです

>>> Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book'))

2つのクエリは少なくとも1つの良い書籍(すなわち評価が 3.0を超えた書籍) があるPublisher のリストを返します。しかし、最初のクエリの注釈付けでは 出版社が出版する全ての書籍の総数を返します;2番目のクエリは注釈付けされた 件数での良い本の一覧を返します。最初のクエリでは、フィルタの前に注釈付け されるので、フィルタは注釈付けに何の影響も与えません。2番目のクエリでは フィルタが注釈付けの前に行われるので、注釈付け計算が行われるべきオブジェクト をフィルタが制限します。

order_by()

注釈付けはソート順( ordering ) に基づいて行うことが可能です。 order_by() 句を定義すると、提供する注釈付けがクエリの中で annoteate() 句の部分と して定義したエイリアスを参照することができます。

例えば、書籍に寄稿した著者の数で書籍の QuerySet を並べ替えるには 次のクエリを使います。:

>>> Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')
values()

本来、注釈付けはオブジェクト毎に行われるのが基本です。– 注釈付けされる QuerySet は元の QuerySet での各オブジェクトに対して1つの結果を 返します。しかし、結果セットで返されるカラムを制限するために values() が使われると、注釈付けの評価方法少しかわります。元の QuerySet の 各結果に対して注釈付けの結果を返すのではなく、 元の結果が values() 句 で指定されたフィールドのユニークな組み合わせに対してグループ化されます。 そして注釈付けが各ユニークグループに対して行われます;注釈付けはグループの 全てのメンバに対して計算されるのです。

例えば、それぞれの著者によって書かれた書籍の平均評価を見つけるために著者の クエリを次のように考えてください

>>> Author.objects.annotate(average_rating=Avg('book__rating'))

これはデータベースにある各著者に対して、彼らの平均書籍評価で注釈付けして 1つの結果を返します。

しかし、 values() 句を使えばこの結果は少し異なります

>>> Author.objects.values('name').annotate(average_rating=Avg('book__rating'))

この例では、 著者が name でグループ化されるので、各 ユニークな 著者の name に対して注釈付けされた値のみが取得されます。つまり、同じ名前の二人の著者が 居ると、1つのクエリの結果に結合されます;平均は二人の著者で書かれた本の平均 として計算されるのです。

annotate() 句と values() 句の順番

filter() 句を使うと、 クエリに適用される annotate() 句と values() 句の順番が重要です。 values() 句が annotate() 句の前にあれば、注釈 付けは values() 句で表現されたグループ化を使って計算されます。

しかし、 annotate() 句が values() の前にあると、注釈付けは全 クエリセットに対して生成されます。この場合、 values() 句は出力に生成 されるフィールドのみを制限します。

例えば、 values() 句と annotate() 句の順番を前の例で反対にすると:

>>> Author.objects.annotate(average_rating=Avg('book__rating')).values('name', 'average_rating')

これは各著者に対する1つのユニークな結果を生成します;しかし、著者の name と average_ration の注釈付けのみが出力データに返されます。

average_ragint が返されるべき値リストに明示的に含まれていることも注目 すべきです。これは values() 句と annotate() 句の順番の為に必要なの です。

もしも values() 句が annotate() 句の前にあるならば、注釈付けは 自動的に結果セットに加えられます。しかし、 values() 句が annotate() 句の後に加えられるのであれば、明示的に注釈付けカラムを含める必要があります。

デフォルトのソート順あるいは order_by() との相互作用

クエリセットの order_by() で示されたフィールド(もしくはモデルに対する デフォルトのソート順で使われるフィールド)はたとえ values() の呼び出しで 指定されていなかったとしても出力データを選択する時には使われます。 このような追加フィールドは”like” な結果を一緒にグループかするのに使われたり、 同じ結果行を分離するのに使われたりします。 特に、件数を数えるときに使われます。

例えば、 このようなモデルがあるとします

class Item(models.Model):
    name = models.CharField(max_length=10)
    data = models.IntegerField()

    class Meta:
        ordering = ["name"]

ここでの重要な部分は、 name フィールドのデフォルトのソート順です。 もしも、ユニークな data の値が何回現れるのかを数えたいのであれば、この ようにしてもいいでしょう

# 警告: 完全に正しい訳ではない!
Item.objects.values("data").annotate(Count("id"))

...こうすると共通の data の値で Item オブジェクトがグループ化され て、各グループの id の値の件数が数えられます。ただし、完全には動作しま せん。 name のデフォルトのソート順はグルーピングでも有効ですので、この クエリはユニークは (data,name) ペアでグループされてしまい、求める結果 とは異なってしまいます。代わりに次のクエリセットを作るべきです

Item.objects.values("data").annotate(Count("id")).order_by()

...このクエリでは任意のソート順を明らかにしています。 つまり data を使って 有害な影響なく並べ替えることができました。クエリの中でその役目を既に果たして いるからです。

この振る舞いは distinct() に対する クエリセットのドキュメントに書かれていることと同じで、一般ルールも同じです。 :普通は結果の中で追加フィールドが役目を果たすことはないので、ソート順を明確 にしないならば、少なくとも values() 呼び出しで選択するこれらのフィールドに 対して制限するようにしないといけません。

Note

Django が無関係のカラムを取り除いてくれないのはなぜなのか?と思うのも もっともです。主な理由は distinct() や他の場所との一貫性です : Django は指定されたそーと順制約を 決して 取り除くことはしません ( 他のメソッドの振る舞いも変更することができません。 API の安定性 にあるポリシーに違反するからです )

注釈付けを集約する

注釈付けの結果を集約することもできます。 aggregate() 句を定義する時は その集約は、クエリの annotate() の部分で定義された任意のエイリアスを 参照することができます。

例えば、書籍とに著者数の平均を計算したいのであれば、まず書籍の集合に対して 著者数で注釈付けし、それから注釈フィールドを参照して著者数を集約します。

>>> Book.objects.annotate(num_authors=Count('authors')).aggregate(Avg('num_authors'))
{'num_authors__avg': 1.66}

マネジャ

revision-up-to:17812 (1.4) unfinished
class Manager

マネジャ (Manager) とは、データベースクエリ操作を Django モデルに提供し ているインタフェースです。 Django アプリケーション内のモデルは全て少なくと も一つマネジャを備えています。

マネジャクラス Manager の動作はデータベース API ドキュメントの クエリを生成する で説明していますが、この節ではマネジャの挙動をカス タマイズするためのモデルオプションについて具体的に触れます。

マネジャの名前

デフォルトでは、 Django は全ての Django モデルクラスに object という名 前で Manager オブジェクトを追加します。ただし、 objects をフィール ド名として使いたい場合や、マネジャに objects 以外の名前をつけたい場合に は、モデルごとに名前を変えてやる必要があります。クラス中でマネジャの名前を 変更するには、 models.Manager() 型のクラス属性を定義します。例えば:

from django.db import models

class Person(models.Model):
    #...
    people = models.Manager()

このようにすると、 Person.people.all()Person オブジェクトのリス トを提供し、 Person.objects の参照は AttributeError 例外を送出します。

カスタムマネジャ

ベースクラスの Manager クラスを拡張して、モデル中でカスタムのマネジャを インスタンス化すれば、モデルでカスタムのマネジャを使えます。

マネジャをカスタマイズする理由は大きく分けて二つあります。一つはマネジャに 追加のメソッドを持たせたい場合、もう一つはマネジャの返す初期 QuerySet を変更したい場合です。

追加のマネジャメソッド定義

モデルに「テーブルレベル」の機能を持たせたい場合、マネジャへのメソッドは良 い方法です。 (「行レベル」の機能を持たせたい、例えばモデルオブジェクトの個々 のインスタンスに影響する関数を実装したい場合には、カスタムのマネジャメソッ ドではなく モデルのメソッド を使って下さい。)

カスタムのマネジャメソッドは何を返してもかまいません。 QuerySet を返さ なくてもよいのです。

例えば、以下のカスタムマネジャでは、 with_counts() というメソッドを提供 しています。このメソッドは全ての OpinionPoll オブジェクトからなるリスト を返しますが、その際に集約クエリの結果である num_responses という追加の 属性を追加します:

class PollManager(models.Manager):
    def with_counts(self):
        from django.db import connection
        cursor = connection.cursor()
        cursor.execute("""
            SELECT p.id, p.question, p.poll_date, COUNT(*)
            FROM polls_opinionpoll p, polls_response r
            WHERE p.id = r.poll_id
            GROUP BY 1, 2, 3
            ORDER BY 3 DESC""")
        result_list = []
        for row in cursor.fetchall():
            p = self.model(id=row[0], question=row[1], poll_date=row[2])
            p.num_responses = row[3]
            result_list.append(p)
        return result_list

class OpinionPoll(models.Model):
    question = models.CharField(max_length=200)
    poll_date = models.DateField()
    objects = PollManager()

class Response(models.Model):
    poll = models.ForeignKey(Poll)
    person_name = models.CharField(max_length=50)
    response = models.TextField()

この例では、 OpinionPoll.objects.with_counts() を使うと、 num_responses 属性を備えた OpinionPoll オブジェクトのリストを返しま す。

この例でもう一つ注意して欲しいのは、マネジャメソッドが自分の属しているモデ ルクラスを取り出すために self.model にアクセスできるという点です。

初期 QuerySet の変更

マネジャのベースの QuerySet は、システム上の全てのオブジェクトを返しま す。例えば、以下のモデル:

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

では、 Book.objects.all() とすると、データベース上の全ての books を返し ます。

Manager.get_query_set() メソッドをオーバライドすれば、 Manager のベー スの QuerySet をオーバライドできます。 get_query_set() は必要なプロ パティを備えた QuerySet を返さねばなりません。

例えば、以下のモデルには 二つの マネジャがあります。片方は全てのオブジェ クトを返し、もう一方は Roald Dahl の書いた本だけを返します:

# まず Manager のサブクラスを定義します。
class DahlBookManager(models.Manager):
    def get_query_set(self):
        return super(DahlBookManager, self).get_query_set().filter(author='Roald Dahl')

# 次に Book モデルに明示的にフックします。
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

    objects = models.Manager() # デフォルトマネジャ。
    dahl_objects = DahlBookManager() # Dahl 縛りのマネジャ。

このモデル例では、 Book.objects.all() はデータベース上の Book を全て返 しますが、 Book.dahl_objects.all() は Roald Dahl の書いた本だけを返しま す。

get_query_set()QuerySet オブジェクトを返すので、もちろん filter()exclude() をはじめ全ての QuerySet メソッドを使えま す。従って、以下のような文を実行できます:

Book.dahl_objects.all()
Book.dahl_objects.filter(title='Matilda')
Book.dahl_objects.count()

この例はもう一つ興味深いテクニックの存在を示しています。それは同じモデルで 複数のマネジャを使えるということです。モデルには、好きなだけマネジャのイン スタンスをアタッチできます。この手法を使うと、よく利用するフィルタをモデル に簡単に実装できます。

例えば:

class MaleManager(models.Manager):
    def get_query_set(self):
        return super(MaleManager, self).get_query_set().filter(sex='M')

class FemaleManager(models.Manager):
    def get_query_set(self):
        return super(FemaleManager, self).get_query_set().filter(sex='F')

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female')))
    people = models.Manager()
    men = MaleManager()
    women = FemaleManager()

この例では、 Person.men.all(), Person.women.all(), Person.people.all() といったクエリを発行できるようになっており、期待通 りの結果を得られます。

カスタムのマネジャオブジェクトを使う場合、 Django がモデル内に最初に見つけ たマネジャ (モデルに定義した順番で最初のマネジャ) は特別扱いされるというこ とに注意してください。 Django はクラス内で最初に見つけたマネジャを「デフォ ルトの」マネジャにし、このデフォルトマネジャを ( dumpdata を含 む) あちこちでモデルのマネジャとして使います。ですから、 get_query_set() のオーバライドによって、扱いたいオブジェクトを取り出せ なくなるような羽目に陥らないように、デフォルトマネジャの選択には細心の注意 を払ってください。

カスタムマネジャとモデルの継承

クラスの継承とモデルのマネジャの関係は、お互い完全にしっくりきているわけで はありません。マネジャはたいていあるクラス固有のものなので、サブクラスでマ ネジャを継承するのは必ずしもよいアイデアとはいえないからです。また、最初に 宣言されたマネジャが*デフォルトマネジャ* になることから、デフォルトマネジャ の制御が重要になってきます。そこで、ここでは、 Django がカスタムマネジャと モデル継承 をどのように扱うか説明します:

  1. 抽象ベースクラスでないクラスで定義されたマネジャは、他のクラスに継承 されません 。非抽象ベースクラスのマネジャを再利用したければ、 子クラスで明示的に宣言してください。この種のマネジャは、たいていマネ ジャを定義しているクラス固有のもので、(デフォルトマネジャとして) 継 承すると思わぬ結果を招くことがあるからです。そのため、子クラスに自動 的に継承されないのです。
  2. 抽象ベースクラスのマネジャは、通常の Python の名前解決規則 (name resolution order, 子クラスの名前が他の名前をオーバライドする、 親クラスリストの最初の親クラスの名前から順に参照する、など) に基づい て、常に子クラスに継承されます。抽象ベースクラスは、子クラスに共通し て持たせたい情報やふるまいを保持するためのクラスだからです。共通のマ ネジャの定義は、共通の情報として親クラスに置くのが適切です。
  3. デフォルトマネジャは、そのクラスで最初に宣言されたマネジャクラスか、 最初に見付かった抽象ベースクラスのデフォルトマネジャです。明示的なデ フォルトマネジャの設定がなければ、 Django の通常のデフォルトマネジャ を使います。

これらのルールはモデルのグループに対してカスタムマネジャのコレクションを インストールしたいときに十分なフレキシビリティを提供しています。 例えば、このようなベースクラスがあるとします

class AbstractBase(models.Model):
    ...
    objects = CustomManager()

    class Meta:
        abstract = True

サブクラスでこれを直接使うのであれば、 ベースクラスでマネジャを定義して いないので objects がデフォルトのマネジャ になります。

class ChildA(AbstractBase):
    ...
    # このクラスは CustomManager をデフォルトマネジャとして持っています

AbstractBase から継承するけれども別のマネジャをデフォルトで用意する のであれば、子クラスにデフォルトマネジャを提供することが出来ます:

class ChildB(AbstractBase):
    ...
    # 明示的なデフォルトマネジャ
    default_manager = OtherManager()

ここで、 default_manager がデフォルトです。 objects マネジャは 引き続き利用できます。というのは継承されているからです。デフォルトとして 使われないというだけです。

この例の最後として、子クラスにマネジャを追加したいけれども、 AbstractBase のデフォルトを引き続き利用したいとします。子クラスに 新しいマネジャを直接追加することができません。 というのはそうするとデフォルトを上書いてしまい、抽象基底クラスの全ての マネジャを明示的に含めなければならなくなるからです。 解決法は他の基底クラスにマネジャを追加して、デフォルトの後に継承階層に 含めることです

class ExtraManager(models.Model):
    extra_manager = OtherManager()

    class Meta:
        abstract = True

class ChildC(AbstractBase, ExtraManager):
    ...
    # デフォツオマネージャは CustomManagerですが、
    # OtherManagerも"extra_manager"属性として利用可能です。
実装する際に考慮すること

カスタム Manager にどんな機能を追加したにせよ、 Manager インスタンスのシャロウコピー (shallow copy)を可能にしなければなりませ; すなわち、以下のコードは正しく動く必要があります

>>> import copy
>>> manager = MyManager()
>>> my_copy = copy.copy(manager)

Django はある種のクエリの最中にマネジャをシャロウコピーさせます; もしも Manager がコピーされないのであればそのようなクエリは失敗します。

これはほとんどのカスタムマネジャにとっては問題とはならないでしょう。 自分の Manager に簡単なメソッドを追加するだけであれば、 うっかり Manager インスタンスをコピーさせないようにしてしまう、という ことはあり得ないでしょう。しかし、 オブジェクトの状態を管理するために Manager オブジェクトの __getattr__ やその他のプライベートメソッド をオーバーライドするのであれば、 Manager がコピーされる能力に影響を 与えないようにするべきです。

自動マネジャタイプの制御

このドキュメントはDjangoがマネジャクラスを作る際にすでに何度も触れられて きました: 関連オブジェクトにアクセスする ための デフォルトマネジャ と “プレーン” マネジャ、です。 Djangoの実装においては、一時的なプレーン マネジャが必要な箇所がいくつかあります。これらの自動的に作成されるマネジャ は通常は django.db.models.Manager のインスタンスです。

この章では “自動マネジャ( automatic manager )” という用語を、 Django が モデルマネジャを自動的に作成してくれる、という意味で使います。 – マネジャ無しのモデルのデフォルトマネジャの場合もありますし、関連オブジェクト にアクセスする際に一時的に使われたりもします。

このデフォルトクラスが正しい選択では無い場合もあります。 Django自体では 提供されていない django.contrib.gis アプリケーションに1つの例があります。 データベースと円滑に相互作用するためには、特殊なクエリセット (GeoQuerySet)を使わなくてはならないので、 全ての gis モデルは特殊な マネジャクラス(GeoManager)を使わなくてはいけません。 このような特殊なマネジャを必要とするモデルは自動マネジャが作成されるときには 必ず同じマネジャクラスを使う必要があります。

Django にはカスタムマネジャ開発者に対して、モデルのデフォルトマネジャが作成 される際には必ず自分の作成したマネジャクラスが自動マネジャとして使われるよう に指定できるような方法が用意されています。これは、マネジャクラスに use_for_related_fields 属性を設定することで実現されます

class MyManager(models.Manager):
    use_for_related_fields = True

    ...

この属性がモデルの デフォルト マネジャに設定される(デフォルトマネジャだけ がこのような状況になり得ます)と、Django はクラスに対して自動的にマネジャを 作成する必要になると必ずこのクラスを使うようになります。 それ以外の場合は、 django.db.models.Manager が使われます。

歴史的ノート

使われる目的を考えると、この属性名(use_for_related_fields)は 少し変です。元々は、この属性は関連フィールドのアクセスだけに使われる ようなマネジャを制御していましたのでこういう名前になったのです。 コンセプトが明確になるにつれてますます広い用途で使われるようになり ましたが、名前は変更されていません。これは第一に既存のコードが 将来の Django のバージョンに置いても 継続し動作する ようにするためです。

自動マネジャインスタンスに使えるように正しくマネジャを書く

上記の django.contrib.gis の例ですでに触れたように、 use_for_related_fields は主にカスタム QuerySet サブクラス を返さなければならないマネージャのための機能です。 あなたのマネジャでこの機能を提供する場合、いくつか覚えておかなければ ならないことがありますので、このセクションで示します。

この種のマネジャのサブクラスでは結果をフィルタしてはいけない

自動マネジャが使われる一つの理由は、他のモデルから関連したオブジェクトに アクセスする場合です。この場合、Djangoはフェッチしようとしているモデル の全てのオブジェクトを見る必要があるので、 参照される 全て が取得 される必要があるのです。

もしも get_query_set() メソッドをオーバーライドして、列をフィルター すれば Django は正しくない結果を返します。これをやってはいけません。 get_query_set() の結果をフィルタするマネジャは自動マネジャとしては ふさわしくありません。

素の SQL クエリを直接実行する

revision-up-to:17812 (1.4) unfinished

モデルクエリAPI では十分には役に立たない場合、 逆戻りして素のSQLを書くことができます。Djangoでは素のSQLクエリを実行する のに2つの方法があります:Manager.raw() を使って、 素のクエリを実行する ことでモデルインスタンスを返すか、あるいは モデル層全体を避けて カスタムSQLを直接実行する ことができます。

素のクエリを実行する
リリースノートを参照してください

マネージャーメソッド raw() を使って素のSQLクエリを実行し、モデルインスタンス を返すことができます。:

Manager.raw(raw_query, params=None, translations=None)

このメソッドは素のSQLクエリを受け取りそれを実行し、 RawQuerySet インスタンスを返します。 この RawQuerySet インスタンスを通常の QuerySet の様に列挙してオブジェクトインスタンスを返すことができます。

例を使うと最も簡単に説明できます。次のようなモデルがあるとします:

class Person(models.Model):
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    birth_date = models.DateField(...)

このようなカスタムSQLを実行したとします

>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):
...     print p
John Smith
Jane Jones

もちろんこの例はあまりエキサイティングではありません – Person.objects.all() を実行しているのと全く同じです。しかし、 raw() は他のオプションを提供 していてそれを使うと非常にパワフルです。

モデルテーブル名

Person テーブルの名前はこの例では何処から来たのか?

デフォルトでは Djanog はデータベーステーブル名をモデルの “アプリケーションラベル(app label)” – manage.py startapp で 使われた名前です – とモデルのクラス名を間にアンダースコアを入れて 連結させて作ります。仮定した例では、 Person モデルは myapp アプリケーションに存在するので、 myapp_person となります。

詳細は db_table オプションに関するドキュメントで 確認してください。そこにはデータベーステーブル名を手動で設定する 方法も書かれています。

Warning

.raw() に渡されたSQL文はチェックされません。DjangoはそのSQL文が データベースから行セットを返すことを期待しますが、そうするために 何かをしてくれる訳ではありません。クエリが行を返さないのであれば、 (おそらく意味不明な)エラーとなります。

クエリフィールドをモデルフィールドに対応付けする

raw() はクエリの中のフィールドをモデルのフィールドに自動的に対応付け します。

クエリにおけるフィールドの並び順は関係ありません。言い換えると、以下の 2つのクエリは同じように動きます:

>>> Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person')
...
>>> Person.objects.raw('SELECT last_name, birth_date, first_name, id FROM myapp_person')
...

対応付けは名前で行われます。つまり、クエリの中でSQLの AS 句を使って フィールドをモデルフィールドに対応付けすることができます。よってもしも他の テーブルに Person のデータを持っているのであれば、 Person インスタンス に簡単に対応付けさせることができます

>>> Person.objects.raw('''SELECT first AS first_name,
...                              last AS last_name,
...                              bd AS birth_date,
...                              pk as id,
...                       FROM some_other_table''')

名前が一致するのであれば、モデルインスタンスは正常に作成されます。

また translations 引数を raw() に渡すことでクエリの フィールドをモデルフィールドに対応付けすることも出来ます。 これは、クエリのフィールド名をモデルのフィール名に辞書で対応付けさせる 方法です。例えば、上のクエリはこのように書き換えることが出来ます:

>>> name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
>>> Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
インデックス参照

raw() ではインデックスを使うことができるので、最初の結果だけが欲しいの であればこのように書くことができます:

>>> first_person = Person.objects.raw('SELECT * from myapp_person')[0]

けれども、インデックス化とスライス化はデータベースレベルでは行われません。 データベースに巨大な Person オブジェクトがあるのならば、SQLレベルで クエリに制限をかける方がより効率的です

>>> first_person = Person.objects.raw('SELECT * from myapp_person LIMIT 1')[0]
モデルフィールドを遅延評価する

フィールドは省略することができます

>>> people = Person.objects.raw('SELECT id, first_name FROM myapp_person')

このクエリで返される Person オブジェクトは遅延評価されるモデル インスタンスとなります ( defer() を参照 )。つまり、クエリで省略されたフィールドが必要であればロードすること が出来るということです。例えば:

>>> for p in Person.objects.raw('SELECT id, first_name FROM myapp_person'):
...     print p.first_name, # オリジナルのクエリで取得される
...     print p.last_name # 必要なときに取得される
...
John Smith
Jane Jones

外見上は下の名前も名字も同じクエリで取得されたように見えます。しかし、この例 では実際は3つのクエリが発行されます。raw()クエリでは下の名前のみが取得され ます – 名字は print される時に必要に応じて取得されます。

省略出来ないフィールドが1つだけあります – プライマリキー フィールドです。 Djangoはプライマリキーを使ってモデルインスタンスを識別 するので、素のクエリには常に含まれている必要があります。プライマリキーを 入れるのを忘れると InvalidQuery 例外が投げられます。

アノテーションの追加

モデルに定義されないフィールドを含んだクエリを実行することも出来ます。 例えば、 PostgreSQL’s age() function を使ってデータベースで計算した 年齢の人々を一覧することができます

>>> people = Person.objects.raw('SELECT *, age(birth_date) AS age FROM myapp_person')
>>> for p in people:
...     print "%s is %s." % (p.first_name, p.age)
John is 37.
Jane is 42.
...
raw() にパラメータを与える

クエリをパラメータ化したいのであれば、 raw()params 引数を渡す ことが出来ます

>>> lname = 'Doe'
>>> Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])

params はパラメータリストです。 クエリ文字列の中で %s プレースホルダーを使います(これはデータベース エンジンに関わらず同じです); それらは params リストからのパラメータで 置き換えられます。

Warning

rawクエリでは文字列書式化を使うな!

上のクエリをこの様に書き換えたくなるかも知れません:

>>> query = 'SELECT * FROM myapp_person WHERE last_name = %s' % lname
>>> Person.objects.raw(query)

してはいけません

params リストの使用は SQL injection attacks から完璧に 守られます。この攻撃は攻撃者がデータベースに任意のSQLと投入するための よく知られている手法です。もしも文字列の補完挿入を使うと、早晩SQL インジェクションの餌食になるでしょう。 params リストを使う限りは 攻撃から守られます。

カスタムSQLを直接実行する

時々 Manager.raw() でさえも十分でないことがあります: モデルに明確に マップさせることの出来ないクエリや、 UPDATE . INSERT , DELETE を 直接実行する必要なこともあるでしょう。

このようなケースでは、モデル層全体を通過してデータベースを直接操作すること が常に可能です。

django.db.connection というオブジェクトがデフォルトのデータベー ス接続を 表現して、 django.db.transaction がデフォルトのトランザクションを表現して います。このデフォルトのデータベース接続を使うには、 まず connection.cursor() を呼び出してカーソルオブジェクトを取得します。 次いで cursor.execute(sql, [params]) を呼び出して SQL を実行した後、 cursor.fetchone()cursor.fetchall() を読んで結果行を返します。 データを変更する操作を行った後には、必ず transaction.commit_unless_managed() を呼び出して、変更をデータベースに commit してください。クエリが単にデータを取得するだけの操作なら、 commit は 必要ありません。 例を示しましょう:

def my_custom_sql():
    from django.db import connection, transaction
    cursor = connection.cursor()

    # データを変更する操作なので、 commit が必要
    cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
    transaction.commit_unless_managed()

    # データを取得するだけの操作なので commit は不要
    cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
    row = cursor.fetchone()

    return row

複数のデータベースを使っているのであれば django.db.connections を使って 目的のデータベース接続(とカーソル)を取得することができます。 django.db.connections は辞書ライクなオブジェクトでエイリアスを使って 特定のデータベース接続を取得することができます:

from django.db import connections
cursor = connections['my_db_alias'].cursor()
# ここにコードを書く...
transaction.commit_unless_managed(using='my_db_alias')

デフォルトでは Python DB API がフィールド名無しの結果を返しますが、 これは値の list であって dict でないということです。 少しだけパフォーマンスを犠牲にすれば次のようにして結果を dict で 返すことができます

def dictfetchall(cursor):
    " カーソルの全ての行を辞書として返す "
    desc = cursor.description
    return [
        dict(zip([col[0] for col in desc], row))
        for row in cursor.fetchall()
    ]

2つの違いを例として示します:

>>> cursor.execute("SELECT id, parent_id from test LIMIT 2");
>>> cursor.fetchall()
((54360982L, None), (54360880L, None))

>>> cursor.execute("SELECT id, parent_id from test LIMIT 2");
>>> dictfetchall(cursor)
[{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}]
トランザクションと素のSQL

素のSQL呼び出しをするときは、 Djangoは現在のトランザクションを自動的に ダーティとしてマークします。これらの呼び出しを含むトランザクションが 正確に閉じたことを確認する必要があります。 詳細に関しては、 Djangoのトンランザクション処理に求められるもの を参照してください。

リリースノートを参照してください

Django 1.3より前では、 素のSQL呼び出しを使う際、 transaction.set_dirty() を使って手動で トランザクションを ダーティーとマークする必要がありました。

接続とカーソル

connectioncursorPEP 249 で説明されている Python DB-API 標準をほとんど実装しています (ただし トランザクション処理 を除く)。 Python DB-APIに精通していないのであれば cursor.execute() のSQL文は SQL文にパラメータを直接追加するのではなく、プレースホルダーとして "%s" を使うということを知っておいてください。 このテクニックを使うのであれば、使用されているデータベースライブラリは必要に 応じて 自動的にパラメータをクオートしたりエスケープしたりします。 (また、Djangoは "%s" を求めているのであって SQLite Python バインディング で使われる "?" では ありません 。これは一貫性とわかりやすさのためです) 。

データベーストランザクションの管理

revision-up-to:17812 (1.4)

Django はトランザクションをサポートしているデータベース向けに、トランザクショ ン管理を制御する方法をいくつか提供しています。

デフォルトのトランザクション処理

Django のデフォルトの挙動では、組み込みのデータ変更に関わるモデル関数を呼び 出したときにはいつでも自動的に commit を行います。例えば、 model.save()model.delete() を呼び出すと、変更は即座にコミットされます。

これはほとんどのデータベースにおける自動コミット設定とほとんど同じ挙動です。 すなわち、ユーザがデータベースへの書き込みを必要とするような操作を行うと、 Django はすぐに INSERT/UPDATE/DELETE 文を実行し、次いで COMMIT を実行します。暗黙のロールバックは行いません。

HTTP リクエストとトランザクションを結び付ける

TransactionMiddleware を介してリクエストとレスポンスのフェイズにトラン ザクションを結び付けるというものです。

このトランザクション処理は次のように行われます: まず、リクエスト処理の開始 時にトランザクションを開始します。レスポンスを問題なく生成できたら、全ての トランザクションをコミットします。ビュー関数が例外を送出したら、ロールバッ クを起こします。

この機能を有効にするには、 TransactionMiddleware ミドルウェアを MIDDLEWARE_CLASSES 設定に追加します:

MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.transaction.TransactionMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
)

ミドルウェアの配置順はとても重要です。トランザクションミドルウェアは呼び出 されるビュー関数だけでなく、後続のミドルウェアモジュール全てに影響します。 従って、セッションミドルウェアをトランザクションミドルウェアの後ろに配置す ると、セッションの生成はトランザクションの一部に入ってしまいます。

いくつかのキャッシュミドルウェアの例外は: CacheMiddleware, UpdateCacheMiddleware, FetchFromCacheMiddleware は影響を受けませ ん。データベースキャッシュを使用しているときでも、 Django のキャッシュミドル ウェアは独自のデータベースカーソルを使います。(内部的に独自のデータベース コネクションとマッピングされています。)

ビュー内でトランザクションを管理する
トランザクションを管理するコンテキストマネージャーは Django 1.3 で 新しくなりました。

ほとんどのユーザにとって、非明示的なリクエストベースのトランザクションは素 晴らしい働きをすることでしょう。しかしながら、トランザクションの管理方法を より詳細に制御したい場合、 django.db.transaction の中の関数群を使って 関数ごと、またはコードブロックベースごとにトランザクションを管理してください。

これらの関数は、下記で詳細に説明しています。二つの方法で使えます。:

  • 特定の関数の デコレーター としての一例は:

    from django.db import transaction
    
    @transaction.commit_on_success
    def viewfunc(request):
        # ...
        # this code executes inside a transaction
        # ...
    
  • コンテキストマネージャー として特定のブロックに使うには

    from django.db import transaction
    
    def viewfunc(request):
        # ...
        # this code executes using default transaction management
        # ...
    
        with transaction.commit_on_success():
            # ...
            # this code executes inside a transaction
            # ...
    

両方のテクニックは、 Python の全てのサポートバージョンで使えます。 しかしながら、 Python 2.5 では、 with 文を使う際には from __future__ import with_statement をモジュールの先頭で 加えなければ行けません。

Note

下記ではビュー関数を例に取ってはいますが、以下に述べるデコレータと コンテキストマネージャーはトランザクションを扱う必要がある全ての コードで使用することが出来ます。

autocommit()

ビュー関数のトランザクションの挙動を、グローバルな設定に関係なく Django の デフォルトの挙動にスイッチするには、 autocommit デコレータを使います。

例えば:

from django.db import transaction

@transaction.autocommit
def viewfunc(request):
    ....

@transaction.autocommit(using="my_other_database")
def viewfunc2(request):
    ....

viewfunc() の中では、 model.save()model.delete() 、その他デー タベースに書き込みを行う全ての関数でトランザクションを commit します。 viewfunc2() は同じ挙動になるでしょう、ですが "別のデータベース" コネクションにです。

commit_on_success()

commit_on_success デコレータを使うのは、関数内の全ての処理にわたるトラン ザクションを使えます:

from django.db import transaction

@transaction.commit_on_success
def viewfunc(request):
    ....

@transaction.commit_on_success(using="my_other_database")
def viewfunc2(request):
    ....

関数の実行に成功すると、 Django はそれまでの全ての作業を commit します。関 数が例外を送出すると、 Django はトランザクションを rollback します。

commit_manually()

トランザクションを完全に管理したい場合には、 commit_manually デコレータ を使います。このデコレータは Django にユーザが自分でトランザクションを管理 しようとしていることを知らせます。

commit()rollback() を行わずにデータを変更した場合は TransactionManagementError 例外を送出します。

手動のトランザクション管理は以下のようになります:

from django.db import transaction

@transaction.commit_manually
def viewfunc(request):
    ...
    # commit/rollback を好きなタイミングで行えます
    transaction.commit()
    ...

    # ただし、自分でちゃんとやっておくのを忘れないように!
    try:
        ...
    except:
        transaction.rollback()
    else:
        transaction.commit()

@transaction.commit_manually(using="my_other_database")
def viewfunc2(request):
    ...
トランザクションを操作する必要性
リリースノートを参照してください

Django はリクエストの完了より前にオープンなトランザクションを閉じなくてはいけ ません。もし、 autocommit() (通常のコミットモード)を使用しているか、 commit_on_success() ならば、自動的にその処理が行われます。 しかし、手動でトランザクションを管理していると( commit_manually() デコレータを使用していれば)、トランザクションがコミットされるか、 ロールバックするかをリクエストが終了する前に確かめておかなければいけません。

これは全てのデータベースオペレーションに適用されます、書き込み処理だけでは ありません。データベースから読み取るだけだったとしても、トランザクションは リクエストが完了する前にコミットかロールバックされてなければいけません。

トランザクション管理をグローバルに無効化する方法

制御マニアの人は、 Django 設定ファイルで DISABLE_TRANSACTION_MANAGEMENTTrue に設定すれば、全ての自動トランザクション管理を無効にし、自分で トランザクションを管理できます。

この場合、 Django はいかなるトランザクション管理も行わなくなります。ミドル ウェアが非明示的にトランザクションを commit することはなくなり、自分でロー ル管理を行わねばなりません。さらに、何らかのミドルウェアで変更の commit を 自分で行わねばならなくなります。

従って、トランザクションの無効化は、自作のトランザクション制御ミドルウェア を実行したい場合や、本当に変わったことをやりたい場合向けです。ほとんどの状況では、 デフォルトの挙動かトランザクションミドルウェアで十分で、必要に応じ て特定の関数だけを変更すればよいでしょう。

セーブポイント

セーブポイントはトランザクションの中で、全てのトランザクションではなく、 トランザクションの一部をロールバックできるようにします。セーブポイントは PostgreSQL 8 や Oracle 、MySQL (バージョン 5.0.3 とそれより新しいもので InnnoDB をストレージエンジンに使っているもの)バックエンドで使えます。 他のバックエンドはセーブポイントを関数で提供します、しかしこれは空の オペレーションです – これは実際何もしません。

MySQL バックエンドでのセーブポイントは Django 1.4 からサポートされ始め ました。

セーブポイントは、通常の autocommit を Django で使っている限りこれは 役に立ちません。もし、 commit_on_successcommit_manually を 使っていると、それぞれの開かれたトランザクションは一連のデータベース処理として 構築され、コミットやロールバックを待ちます。もし生じた問題をロールバックしたい のならば、完全にトランザクションをロールバックします。セーブポイントは、 transaction.rollback() で動作する完全なロールバックを細かく 動作させられるようにします、

それぞれの関数は using 引数を取ります。これはこの処理が適用される データベースの名前にしてください。もし using 引数がなかったら、 "default" データベースが使われます。

セーブポイントは、トランザクションオブジェクトの三つのメソッドによって コントロールされています。:

transaction.savepoint(using=None)

新しいセーブポイントを作ります。これは、 “よい”状態にある トランザクションをマークするポイントです。

セーブポイント ID (sid)を返します。

transaction.savepoint_commit(sid, using=None)

最後のコミットか、セーブポイントが作られたときからの動作を含むように セーブポイントをアップデートします。

transaction.savepoint_rollback(sid)

トランザクションをセーブポイントかコミットされたところまで戻します。

セーブポイントを使った例は:

from django.db import transaction

@transaction.commit_manually
def viewfunc(request):

  a.save()
  # open transaction now contains a.save()
  sid = transaction.savepoint()

  b.save()
  # open transaction now contains a.save() and b.save()

  if want_to_keep_b:
      transaction.savepoint_commit(sid)
      # open transaction still contains a.save() and b.save()
  else:
      transaction.savepoint_rollback(sid)
      # open transaction now contains only a.save()

  transaction.commit()
MySQL でのトランザクション

MySQL を使っている場合、MySQL のバージョンと使っているテーブルの形式に応じ て、テーブルがトランザクションをサポートする場合としない場合があります。 (「テーブルの形式」とは、”InnoDB” や “MyISAM” などを指します。) このドキュ メントでは MySQL のトランザクションにまつわる説明はしませんが、 MySQL のサ イトには トランザクションに関する情報 が掲載されています。

MySQL 構成がトランザクションをサポート していない 場合、 Django は自動コ ミットモードで動作します。すなわち、 SQL 文は呼び出されたその場で実行され、 コミットされます。 MySQL 構成がトランザクションをサポートしている場合、 Django はこのドキュメントの説明通りにトランザクションを処理します。

PostgreSQL のトランザクションで例外処理を扱う

PostgreSQL のカーソルが例外を呼び出した時(典型的には IntegrityError )、 同じトランザクションの中の以後全ての SQL がエラーにより失敗します “トランザ クションブロックの終わりまでクエリは無視され、最新のトランザクションは 破棄されます”。一方で save() は PostgreSQL の例外処理とは似ていません、 そこではもっと進歩して慣用的なパターンがあり、ユニークフィールドでオブジェクト をセーブするようなものであったり、 force_insert/force_update フラグを使って セーブしたり、またはカスタム SQL の

この種のエラーからの回復方法はいくつかあります。

トランザクションロールバック

トランザクションを全て巻き戻すための最初のオプション例です:

a.save() # Succeeds, but may be undone by transaction rollback
try:
    b.save() # Could throw exception
except IntegrityError:
    transaction.rollback()
c.save() # Succeeds, but a.save() may have been undone

transaction.rollback() を呼ぶと、トランザクションをまるまる元に戻します。 コミットされてないデータベースへの手続きは全て失われます。この例では、 a.save() による変更は失われます、ですがこの手続きはエラーを出しません。

セーブポイント ロールバック

もし、 PostgreSQL 8 か、それより新しいものを使っていれば、 セーブポイント を使って データベースが動作する前、失敗するまえに戻せます、セーブポイントを アップグレードしたり設定することが出来ます。この方法は、オペレーションが 失敗した時に、一つ前の手続きにもどることができ、完全にトランザクションを 巻き戻さなくて済みます。:

a.save() # Succeeds, and never undone by savepoint rollback
try:
    sid = transaction.savepoint()
    b.save() # Could throw exception
    transaction.savepoint_commit(sid)
except IntegrityError:
    transaction.savepoint_rollback(sid)
c.save() # Succeeds, and a.save() is never undone

この例では、 a.save() は実行されておらず、 b.save() が 例外を発生させています。

データベースレベル オートコミット

PostgreSQL 8.2 かそれより新しいと、進歩したオプションが PostgreSQLを実行 するためにあります。 データベースレベル オートコミット です。 もしこのオプションを使うと、恒常的にトランザクションが開かなくなり、 例外を捕まえた後でも処理を継続できるようになります。:

a.save() # succeeds
try:
    b.save() # Could throw exception
except IntegrityError:
    pass
c.save() # succeeds

Note

これは、 オートコミットデコレータ と同じではなく、データベースレベルでのオートコミットを使う時に、それは データベースのトランザクションは全くありません。 オートコミット でコレーッタはトランザクションを使い、データベースが変化する処理が生じた 時に、自動的にそれぞれのトランザクションをコミットします。

マルチデータベース (Multiple databases)

revision-up-to:17812 (1.4)
リリースノートを参照してください

このトピックガイドでは、 Django がマルチデータベースをサポートしたことについて 述べられています。他の多くの Django ドキュメントでは単一のデータベースを扱う ことを想定しています。マルチデータベースを扱いたいなら、いくつか追加の手順を行う 必要があります。

データベースを定義する

Django で複数のデータベースを扱うための最初のステップは、使用したいデータベース サーバについて Django に伝えることです。これには DATABASES 設定を使い ます。データベースへのエイリアスを設定し、 Django 全体にわたって特定のデータ ベースを参照できるようにします。特定のデータベースとの接続を設定する辞書です。 内部の辞書の設定については、すべて DATABASES ドキュメントで述べられて います。

データベースにはどんなエイリアスでも設定できます。しかし、 default は特別な 意味を持っています。Django は他のデータベースが一切選ばれていない場合に、 default によってデータベースを使います。 default データベースが無い 場合は、常に使うデータベースの指定に気をつけてください。

以下の例は settings.py の一部で、 2 つのデータベースを定義しています。デフォ ルトが PostgreSQL データベースで、 users は MySQL データベースを呼び出し ます:

DATABASES = {
    'default': {
        'NAME': 'app_data',
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'USER': 'postgres_user',
        'PASSWORD': 's3krit'
    },
    'users': {
        'NAME': 'user_data',
        'ENGINE': 'django.db.backends.mysql',
        'USER': 'mysql_user',
        'PASSWORD': 'priv4te'
    }
}

DATABASES 設定に定義していないデータベースにアクセスすると、 django.db.utils.ConnectionDoesNotExist 例外が送出されます。

データベースの同期

syncdb 管理コマンドは 1 度に 1 つのデータベースを操作します。デフォ ルトでは default データベースが操作されます。 --database 引数 を与えることで、 syncdb に他のデータベースを同期するよう指示できます。例における 全データベースの全モデルを同期するには、以下を実行する必要があります:

$ ./manage.py syncdb
$ ./manage.py syncdb --database=users

どのアプリケーションも特定のデータベースに同期させたくないときは、 database router を定義できます。これによって 特定のモデルに利用制限を設けられます。

他にも、粒度の小さい同期の制御をしたいなら、特定アプリケーションの sqlall の出力のすべてか一部を、直接データベースプロンプトにパイプし ます。こんなかんじです:

$ ./manage.py sqlall sales | ./manage.py dbshell
他の管理コマンドを使う

データベースを扱う他の django-admin.py コマンドは、 syncdb と 同じように動作します。今までと同じく、データベースを制御するための --database を使用します。は一度に 1 つのデータベース上でのみ動作し ます。

自動データベースルーティング

マルチデータベースを扱う最も簡単な方法は、データベースルーティングスキーム (a database routing scheme) を設定することです。デフォルトのルーティングスキーム は、オブジェクトが元のデータベースに ‘ベットリ (sticky)’ なままであることを保証 します (例えば foo データベースから取ってきたオブジェクトが、同じ foo データベースに保存されるということ) 。デフォルトのルーティングスキームは、データ ベースが特定されていないと、全クエリを default データベースに返します。

デフォルトのルーティングスキームを有効にする必要はありません。 ‘設定する必要なく (out of the box)’ 全 Django プロジェクトで提供されています。より面白いデータ ベースの割り当てをしたいなら、個別のデータベースルータを定義、導入しましょう。

データベースルータ

データベースルータは、 4 つのメソッドを提供するクラスです。

db_for_read(model, **hints)

model タイプのオブジェクトの読み込み操作に使われるデータベースを提示 します。

データベース操作においてデータベースを選ぶ助けになる追加の情報を提示できる なら、 hints 辞書に提供します。妥当なヒントの詳細は こちら に書かれています。

提示するものが無い場合は None を返します。

db_for_write(model, **hints)

Model タイプのオブジェクトの書き込みに使われるデータベースを提示します。

データベース操作においてデータベースを選ぶ助けになる追加の情報を提示できる なら、 hints 辞書に提供します。妥当なヒントの詳細は こちら に書かれています。

提示するものが無い場合は None を返します。

allow_relation(obj1, obj2, **hints)

obj1 、 obj2 間のリレーションが許可されている場合 True 、リレーションが 許可されていない場合 False 、 ルータに設定がない場合 None を返します。単なる 検証の操作です。外部キー、多対多の操作において、リレーションが 2 オブジェク ト間で許可されているかどうか判別するために使用されます。

allow_syncdb(db, model)

modeldb で与えられたデータベースと同期されるべきかどうかを判別し ます。モデルが同期されるべきとき True 、 そうでないとき False 、 ルータに 設定がない場合 None を返します。このメソッドは与えられたデータベース上に モデルが存在するかどうかを判別するのに使えます。

ルータはこれら すべて のメソッドを提供する必要はありません。 1 つかそれ以上は 省略されるでしょう。あるメソッドが省略されれば、 Django は該当のチェックを行う とき、そのルータをスキップします。

ヒント

データベースルータから受け取ったヒントによって、与えられたリクエストをどのデータ ベースで受け取るべきかを決めます。

今のところ、提供される唯一のヒントは instance です。実行中の読み込み、もしく は書き込み操作に関連づけられたオブジェクトのインスタンスです。これは保存された インスタンスか、多対多のリレーションに追加されたインスタンスになります。場合に よっては、インスタンスヒントは全く提供されません。ルータはインスタンスヒントの 存在をチェックします。ルーティングの振る舞いを変えるためにヒントが使われるべきか どうか判断します。

ルータを使う

データベースルータは DATABASE_ROUTERS 設定によって導入されます。 この設定ではクラス名のリストを定義します。マスタールータ (django.db.router) に使われるべきルータを指定します。

マスタールータは Django のデータベース操作に使われます。これはデータベースに処理 を割り当てるために使われます。クエリがどのデータベースを使うべきか知る必要がある ときは常にマスタールータが呼び出されます。その際モデルと (有効な場合は) ヒントが ルータに提供されます。データベースが提示されるまで、 Django は順番に各ルータを 試します。提示されない場合、現在のヒントインスタンスの _state.db を試し ます。ヒントインスタンスが提供されないか、インスタンスがデータベースステートを 保持していない場合、マスタールータは default データベースを割り当てます。

例の狙い!

この例はデモンストレーションを意図しています。ルータインフラストラクチャ (the router infrastructure) が、データベースの使い方を変えるために、どの ように使えるかのデモンストレーションです。デモンストレーションに際して、 いくつかの複雑な問題はあえて無視します。

myapp 中のモデルのうちのどれかが other データベース外のモデルとの関係 を含んでいれば、この例は動きません。 Cross-database relationships では、 Django が今のところ扱えない参照整合性の問題を紹介しています。

記載されているマスター/スレーブ構成にも欠陥があります。応答の遅延を扱う上で、 なんの解法も提供しません (つまり、クエリ不一致によって、スレーブに伝播させる ための書き込みに時間が取られるからです) 。

実際どんな意味があるのでしょう? myappother データベースに存在し、 その他のモデルは masterslave1slave2 間の、マスター/スレーブ 構成に存在して欲しいとしましょう。これを実現するには、 2 つのルータが必要です:

class MyAppRouter(object):
   """myapp アプリケーションのモデルの全データベース操作を制御するルータ"""

   def db_for_read(self, model, **hints):
       "myapp モデルの全操作を 'other' に向ける"
       if model._meta.app_label == 'myapp':
           return 'other'
       return None

    def db_for_write(self, model, **hints):
       "myapp モデルの全操作を 'other' に向ける"
       if model._meta.app_label == 'myapp':
           return 'other'
       return None

    def allow_relation(self, obj1, obj2, **hints):
       "myqpp 中のモデルが含まれている場合、全リレーションを許可"
       if obj1._meta.app_label == 'myapp' or obj2._meta.app_label == 'myapp':
           return True
       return None

    def allow_syncdb(self, db, model):
       "myapp アプリケーションが 'other' DB にのみあることを確かなものとする"
       if db == 'other':
           return model._meta.app_label == 'myapp'
       elif model._meta.app_label == 'myapp':
           return False
       return None

class MasterSlaveRouter(object):
   """単純なマスター/スレーブ構成を設けるルータ"""

   def db_for_read(self, model, **hints):
       "全読み込み操作をランダムなスレーブに向ける"
       return random.choice(['slave1','slave2'])

    def db_for_write(self, model, **hints):
       "全書き込み操作をマスターに向ける"
       return 'master'

    def allow_relation(self, obj1, obj2, **hints):
       "DB プール内で 2 オブジェクト間のリレーションを許可"
       db_list = ('master','slave1','slave2')
       if obj1._state.db in db_list and obj2._state.db in db_list:
           return True
       return None

    def allow_syncdb(self, db, model):
       "全データベース上に全モデルを明示的に配置する"
       return True

ここで設定ファイルに、以下を追加します (path.to. は、ルータを定義した モジュールへの実際の Python パスで置き換えます):

DATABASE_ROUTERS = ['path.to.MyAppRouter', 'path.to.MasterSlaveRouter']

ルータが処理される順序は重要です。ルータは DATABASE_ROUTERS 設定に 記述されている順序で問い合わせされます。この例では MyAppRouterMasterSlaveRouter よりも前に処理されます。結果として、 myapp 中のモデル に関する決定は、他の決定が行われるより前に処理されます。もし DATABASE_ROUTERS 設定が、違う順序で 2 つのルータを並べている場合、 MasterSlaveRouter.allow_syncdb() が最初に処理されるでしょう。 MasterSlaveRouter の多目的な性質が示すのは、全モデルが全データベース上で利用可能 であろうということです。

このセットアップが導入できたら、 Django コードをいくつか走らせてみましょう:

>>> # この検索は 'credentials' データベース上で行われるでしょう
>>> fred = User.objects.get(username='fred')
>>> fred.first_name = 'Frederick'

>>> # この保存も 'credentials' に直接行われます
>>> fred.save()

>>> # これらの検索はスレーブデータベースにランダムに割り当てられます
>>> dna = Person.objects.get(name='Douglas Adams')

>>> # 新しいオブジェクトが作られた際はデータベースに対する割り当てがありません
>>> mh = Book(title='Mostly Harmless')

>>> # この割り当てはルータに助言を求め、 mh を author オブジェクトと同様に、
    # 同じデータベースに割り当てます
>>> mh.author = dna

>>> # この保存は、マスターデータベース上に 'mh' インスタンス強制します
>>> mh.save()

>>> # しかし再度オブジェクトを取り出すと、再びスレーブに戻ってきます
>>> mh = Book.objects.get(title='Mostly Harmless')
データベースの手動選択

さらに Django は、コードの中でデータベース処理を完全にコントロールできる API を 提供しています。手動でのデータベース割り当ては、ルータによるデータベース割り当て よりも優先されます。

QuerySet のためのデータベース手動選択

QuerySet “チェーン (chain)” のどの点に置いても、 QuerySet のためにデータ ベースを選択できます。ただ、 QuerySet から using() を呼び出すだけで、 特定のデータベースを使う他の QuerySet を取得できます。

using() は引数を 1 つだけ受け取ります。クエリを走らせたいデータベースへ名を 受け取ります。例えば:

>>> # これは 'default' データベースで実行されます
>>> Author.objects.all()

>>> # So will this.
>>> Author.objects.using('default').all()

>>> # これは 'other' データベースで実行されます
>>> Author.objects.using('other').all()
save() のためのデータベース選択

Model.save()using キーワードを使って、どのデータベースにデータを 保存するかを特定できます。

例えば、 legacy_users データベースへオブジェクトを保存としたいとすると、 このようにします:

>>> my_object.save(using='legacy_users')

using によって特定しない場合は、 save() はルータに割り当てられたデフォル トのデータベースに保存します。

あるデータベースから他のデータベースにオブジェクを移動する

あるデータベースにインスタンスをセーブした場合は、新しいデータベースにインスタ ンスを移行する手段として、 save(using=...) を使うためことは魅了的かもしれ ません。

以下の例を考えてください:

>>> p = Person(name='Fred')
>>> p.save(using='first')  # (命令 1)
>>> p.save(using='second') # (命令 2)

命令 1 において、新しい Person オブジェクトは first データベースに保存 されています。この場合、 p はプライマリキーを持たないので、 Django は SQL の INSERT 命令を発行します。これはプライマリキーを生成し、 Django は p に プライマリキーを付与します。

命令 2 によって保存が行われるとき、 p はすでにプライマリキーの値を保持して おり、 Djagno はそのプライマリキーを新しいデータベースで使用しようとしています。 そのプライマリキーが second データベースで使われていない場合は、何の問題は ありません。新しいデータベースにそのオブジェクトがコピーされます。

しかし、 p のプライマリキーがすでに second データベースで使われている 場合は、 second データベースの現行のオブジェクトは p が保存された際に 上書きされます。

これ避けるには 2 つの方法があります。 1 つめは、インスタンスのプライマリキーを 消してしまうことです。オブジェクトにプライマリキーが無い場合は、 Django はそれを 新しいオブジェクトとして扱います。これによって second データベースからは 何も消えません:

>>> p = Person(name='Fred')
>>> p.save(using='first')
>>> p.pk = None # Clear the primary key.
>>> p.save(using='second') # Write a completely new object.

2 つめの選択肢は、 save()force_insert オプションを使うことです。 これは Django に SQL INSERT を実行させます。

>>> p = Person(name='Fred')
>>> p.save(using='first')
>>> p.save(using='second', force_insert=True)

これは Fred という名の人物 (person) が、同じプライマリキーを両方のデータ ベース上で保有していることを保証します。その second データベースに書き込もう としたときにプライマリキーがすでに使われている場合、エラーが送出されます。

削除用のデータベースを選択する

デフォルトでは、既存のオブジェクトを削除するという要求は、オブジェクトの取得に 使用されたデータベース上で実行されます:

>>> u = User.objects.using('legacy_users').get(username='fred')
>>> u.delete() # will delete from the `legacy_users` database

モデルを削除するデータベースを特定するために、 using キーワード引数を Model.delete() メソッドに渡します。この引数は save()using キーワード引数と似たように機能します。

例えば、 legacy_users データベースから new_users データベースへ移行して いるとすると、以下のコマンドが使えます:

>>> user_obj.save(using='new_users')
>>> user_obj.delete(using='legacy_users')
マルチデータベースでマネジャを使う

マネジャの db_manager() メソッドを使って、マネジャアクセスを非デフォルト データベースに渡してください。

例えば User.objects.create_user() という、データベースに関するカスタムマネ ジャメソッドを持ってるとします。 create_user() はマネジャメソッドであって QuerySet メソッドではないので、 User.objects.using('new_users').create_user() とはできません (create_user() メソッドは User.objects で上のみ有効です。マネジャで あって、マネジャから得られた QuerySet オブジェクト上ではありません) 。この 解法は以下のようになります:

User.objects.db_manager('new_users').create_user(...)

db_manager() は指定したデータベースに紐づけたマネジャのコピーを返します。

マルチデータベースで get_query_set() を使う

マネジャの get_query_set() をオーバーライドする際には、 (super() を 使って) 親を呼び出すか、マネージャの _db のつく属性 (使うデータベース名 を含む文字列) を適切に扱ってください。

例えば get_query_set メソッドからカスタムされた QuerySet クラスを返し たいなら、こうしてください:

class MyManager(models.Manager):
    def get_query_set(self):
        qs = CustomQuerySet(self.model)
        if self._db is not None:
            qs = qs.using(self._db)
        return qs
Django admin インタフェースにマルチデータベースを表示する

Django の admin は、マルチデータベースの明示的なサポートはしていません。ルータ チェインによって指定された他のデータベス上のモデルのため、 admin インタフェース を提供したいなら、カスタム ModelAdmin クラスを 書く必要があります。特定のデータベースを admin インタフェースのコンテンツに 使用するように命令します。

ModelAdmin オブジェクトは 5 つのメソッドを持っています。マルチデータベースを サポートするためカスタマイズできます:

class MultiDBModelAdmin(admin.ModelAdmin):
    # A handy constant for the name of the alternate database.
    using = 'other'

    def save_model(self, request, obj, form, change):
        # Tell Django to save objects to the 'other' database.
        obj.save(using=self.using)

    def delete_model(self, request, obj):
        # Tell Django to delete objects from the 'other' database
        obj.delete(using=self.using)

    def queryset(self, request):
        # Tell Django to look for objects on the 'other' database.
        return super(MultiDBModelAdmin, self).queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        # Tell Django to populate ForeignKey widgets using a query
        # on the 'other' database.
        return super(MultiDBModelAdmin, self).formfield_for_foreignkey(db_field, request=request, using=self.using, **kwargs)

    def formfield_for_manytomany(self, db_field, request=None, **kwargs):
        # Tell Django to populate ManyToMany widgets using a query
        # on the 'other' database.
        return super(MultiDBModelAdmin, self).formfield_for_manytomany(db_field, request=request, using=self.using, **kwargs)

この実装はここでは、マルチデータベースストラテジー機能を提供します。与えられた タイプのすべてのオブジェクトが、特定のデータベースに格納されます (例えば、 全 User オブジェクトを other データベースに)。 マルチデータベースの 使い方がより複雑なら、 ModelAdmin にそのストラテジーの反映が必要になります。

インラインは同様の方法で処理できます。メソッドを 3 つカスタマイズします:

class MultiDBTabularInline(admin.TabularInline):
    using = 'other'

    def queryset(self, request):
        # Tell Django to look for inline objects on the 'other' database.
        return super(MultiDBTabularInline, self).queryset(request).using(self.using)

    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
        # Tell Django to populate ForeignKey widgets using a query
        # on the 'other' database.
        return super(MultiDBTabularInline, self).formfield_for_foreignkey(db_field, request=request, using=self.using, **kwargs)

    def formfield_for_manytomany(self, db_field, request=None, **kwargs):
        # Tell Django to populate ManyToMany widgets using a query
        # on the 'other' database.
        return super(MultiDBTabularInline, self).formfield_for_manytomany(db_field, request=request, using=self.using, **kwargs)

モデル admin 定義を書いた後は、それらは任意の Admin インスタンスに登録でき ます:

from django.contrib import admin

# Specialize the multi-db admin objects for use with specific models.
class BookInline(MultiDBTabularInline):
    model = Book

class PublisherAdmin(MultiDBModelAdmin):
    inlines = [BookInline]

admin.site.register(Author, MultiDBModelAdmin)
admin.site.register(Publisher, PublisherAdmin)

othersite = admin.Site('othersite')
othersite.register(Publisher, MultiDBModelAdmin)

この例は 2 つの admin サイトをセットアップします。 1 つめのサイトでは、 AuthorPublisher オブジェクトが見られます。 Publisher オブジェクト は、その出版社が発行した書籍を表示するインライン表を持っています。

マルチデータベースで生のカーソルを使う

2 つ以上のデータベースを使っているなら、 django.db.connections を、特定の データベースへの接続(およびカーソル)を取得するために使えます。 django.db.connections は辞書ライクオブジェクトです。これによってエイリアスを 使用して特定の接続を取得できます:

from django.db import connections
cursor = connections['my_db_alias'].cursor()
マルチデータベースの制限
クロスデータベースリレーション

Django は今のところ、複数のデータベースに及ぶ外部キーか多対多リレーションを サポートを提供していません。別のデータベースにモデルを分配するルータを使って いたなら、それらのモデルに定義される、すべての外部キーと多対多リレーションは 1 つのデータベースに入れられます。

これは参照整合のためです。2 オブジェクト間のリレーションを維持するために、 Django は正当に参照されたオブジェクトのプライマリキー知る必要があります。簡単に プライマリキーの妥当性を評価することはできません。

InnoDB で Postgres 、 Oracle 、 MySQL を使っているなら、データベースの整合性 レベルで強制されます。データベースレベルのキーの制約は、検証できないリレーション の生成を防ぎます

MyISAM テーブルで SQLite か MySQL を使っているなら、強制される参照整合性はあり ません。結果として、 ‘偽の (fake)’ クロスデータベースの外部キーができるかも しれません。しかしこの設定は Django で公式にサポートされているものではありま せん。

テーブルスペース

revision-up-to:17812 (1.4)

データベースシステムのパフォーマンスを最適化する一般的な方法は、 テーブルスペース を使ってディスクレイアウトを整理することです。

Warning

Django はテーブルスペースの作成は行いません。テーブルスペース作成、管理の 詳細については使っているデータベースエンジンのドキュメントを参照してくださ い。

テーブルのテーブルスペースを宣言する

db_tablespace オプションをモデルの class Meta に渡すことによって、モデルが生成した特定のテーブルに対してテーブルス ペースを指定することができます。 このオプションはモデルの ManyToManyField で自動的に 作られたテーブルにも影響します。

DEFAULT_TABLESPACE 設定で db_tablespace のデフォルト値を指定できます。 ビルトインの Django アプリケーションやコードを自分で制御できない他のアプリケー ションにテーブルスペースを設定するのに便利です。

インデックスのテーブルスペースを宣言する

db_tablespace オプションを Field のコンストラクタに渡すことで、その Field のカラムインデックスの 代替テーブルスペースを指定できます。そのカラムにインデックスが作られない場合は このオプションは無視されます。

DEFAULT_INDEX_TABLESPACE 設定を使って db_tablespace のデフォルト値を指定することもで きます。

もし db_tablespace が指定されず、 DEFAULT_INDEX_TABLESPACE もセットしていない場合は、インデックスは テーブルと同じテーブルスペースに作られます。

class TablespaceExample(models.Model):
    name = models.CharField(max_length=30, db_index=True, db_tablespace="indexes")
    data = models.CharField(max_length=255, db_index=True)
    edges = models.ManyToManyField(to="self", db_tablespace="indexes")

    class Meta:
        db_tablespace = "tables"

この例では、 TablespaceExample モデルによって生成されるテーブル (モデル テーブルと多対多のテーブル) は tables テーブルスペースに保存されます。 name フィールドのインデックスと多対多テーブルのインデックスは indexes テー ブルスペースに保存されます。 data フィールドもインデックスを生成しますが、 テーブルスペースが指定されていないので、デフォルトのモデルテーブルスペースであ る tables に保存されることになります。

データベースサポート

PostgreSQL と Oracle はテーブルスペースをサポートしています。 SQLite と MySQL はサポートしていません。

テーブルスペースをサポートしていないバックエンドを使う場合は、 Djang はテーブ ルスペース関連の全てのオプションを無視します。

Django 1.4 から PostgreSQL バックエンドがテーブルスペースをサポートするよ うになりました。

データベースアクセスの最適化

Django のデータベース層は、開発者がデータベースから多くを得ることを助ける色々 な方法を提供しています。このドキュメントは関連するドキュメントのリンクを集めて 色々なヒントを加え、データベース利用の最適化を試みる時に踏むべきステップを概略 する多くの見出しのもとに整理しています。

まずは計測

一般的なプログラミングの実践として、これは言うまでもないことです。 実行されるクエリと実行にかかるコスト を見てく ださい。また、 django-debug-toolbar のような外部のプロジェクトや、データベー スを直接モニタするツールを使っても良いでしょう。

必要に従って、速度を最適化するのか、メモリを最適化するのか、または両方なのかを 思い出してください。時には一方の最適化が他方にとって有害なものになりますが、ま た時には互いに助けになります。また、データベースプロセスでの処理は、 Python プ ロセスで行われる同じ量の処理と同じコストにならないかもしれません。優先度がどう か、バランスを取るべきか、全ての計測が必要か、を決定するのはあなたです。これら はアプリケーションとサーバに依存するでしょうから。

以下の全てにおいて、変更が利益を生んでいることを確かめるため、そして大きすぎる 利益がコードの可読性を下げていないかを確かめるため、変更を行うごとに計測するの を忘れないようにしてください。以下の示唆 ** 全て ** について言えることですが、 あなたの環境では一般的な原則が当てはまらないかもしれない、もしかすると逆かもし れないということに注意してください。

標準的な DB 最適化テクニックを使う

以下が含まれます:

  • インデックス。計測の結果インデックスを追加するべきだと決心した 後には これ を最も優先すべきです。インデックスを追加するには django.db.models.Field.db_index を使います。
  • 適切なフィールドの型を使います。

上記の明らかなことは既に行ってあると仮定します。このドキュメントの残りでは、必 要のないことをしないためにどのように Django を使うかに焦点を当てます。このド キュメントはまた、 汎用的なキャッシング のような高くつ く操作全般に適用するような最適化技術は扱いません。

クエリセットを理解する

クエリセット を理解することはシンプルなコードで 良いパフォーマンスを得るために欠かせません。とりわけ:

クエリセットの評価を理解する

パフォーマンスの問題を避けるには、次のことを理解することが大切です:

キャッシュされる属性を理解する

QuerySet 全体をキャッシュするのと同様、 ORM オブジェクトの属性の結果も キャッシュされます。一般的に呼び出し可能でない属性はキャッシュされます。例えば ブログでのモデル例 を前提にすると:

>>> entry = Entry.objects.get(id=1)
>>> entry.blog   # Blog オブジェクトはこの時点で検索されます
>>> entry.blog   # キャッシュバージョンが使われ、 DB アクセスしません

しかし一般的に、呼び出し可能な属性は毎回 DB 参照を行います:

>>> entry = Entry.objects.get(id=1)
>>> entry.authors.all()   # クエリが実行された
>>> entry.authors.all()   # クエリがまた実行された

テンプレートコードを読む時には注意してください。テンプレートシステムはカッコを 使うことを許容しませんが、上記の区別なく呼び出し可能オブジェクトを自動的に呼び ます。

自分のカスタムプロパティに注意してください。キャッシュを実装するかは開発者に任 されています。

with テンプレートタグを使う

QuerySet のキャッシング動作を利用するには、 with テンプレートタグ を使う必要があるかもしれません。

iterator() を使う

多くのオブジェクトを持っている時、 QuerySet のキャッシング動作は大量のメモ リ使用につながる可能性があります。この場合、 iterator() が助けになるかもしれませ ん。

Python よりもデータベースで行うべき動作

具体例として:

  • 最も基本的なレベルでは、 filter と exclude を使って データベースのフィルタリングをすることができます。

必要なSQLを生成するのにこれらで不十分なら:

QuerySet.extra() を使う

移植性は比較的低いですが、より強力なメソッドが extra() です。これはクエリに対する明 示的な SQL の追加を可能にします。これでもまだ十分強力じゃないなら:

生の SQL を使う

データを検索したりモデルを作成するためのカスタム SQL を自分で書いてください。 django.db.connection.queries を使うと、 Django が 書き出したクエリを見ることができますので、そこから始めましょう。

必要になると分かっているデータを一度に検索する

一般的に、一つのデータ「集合」の別々の部分のために、データベースを複数回叩くの は、一つのクエリで一度に検索するよりも効率が低いです。 もしクエリがループの中で実行されていて、それ故に多くのデータベースクエリを一つ だけにまとめることが必要なら、特に重要です。

必要ないものを検索しない
QuerySet.values()values_list() を使う

値の dictlist が必要なだけで、 ORM モデルオブジェクトが必要ないな ら、 values() を適切に使ってください。 これらはテンプレートコードのモデルオブジェクトを置き換えるのに便利です。辞書が テンプレートで使われているものと同じ属性を持っているなら、うまく行きます。

QuerySet.defer()only() を使う

必要のない (またはほとんどの場合に必要ない) データベースカラムがあると分かって いるなら、それらをロードしないように defer()only() を使ってください。 もしそのようなカラムを 使う 場合は、 ORM が個別のクエリで取りに行かなければ ならないことに注意してください。不適切にそれを使うなら、悲観的に考えましょう。

また、遅延フィールドを使ってモデルを構築する時に Django の中でいくらかの (小さ な追加の) オーバーヘッドが発生することに注意してください。計測なしでの遅延 フィールドの使用に積極的になりすぎないでください。わずかなカラムしか使っていな い時でも、データベースは結果の 1 つの行のためにほとんどの非 text 型、非 VARCHAR 型のデータをディスクから読み出さなければなりません。 defer()only() メソッドは多くのテキストデータや Python データに戻すために多くの処 理が必要となるフィールドのロードを避けるのにはとても便利です。例によって、まず は計測、それから最適化をしましょう。

QuerySet.count() を使う

数を数えたいだけなら、 len(queryset) を使うよりもこちらの方が良いです。

QuerySet.exists() を使う

少なくとも 1 つの結果が存在するかを調べたいだけなら、 if queryset よりもこ ちらの方が良いです。

しかし:

count()exists() を使いすぎない

QuerySet からの他のデータが必要なら、それを評価しましょう。

例えば、 body 属性とユーザへの多対多のリレーションを持っている電子メールモ デルを考えましょう。以下のテンプレートコードは最適です:

{% if display_inbox %}
  {% with emails=user.emails.all %}
    {% if emails %}
      <p>You have {{ emails|length }} email(s)</p>
      {% for email in emails %}
        <p>{{ email.body }}</p>
      {% endfor %}
    {% else %}
      <p>No messages today.</p>
    {% endif %}
  {% endwith %}
{% endif %}

これが最適な理由は:

  1. QuerySets が遅延評価されるので display_inbox が False の場合にデータベース アクセスが発生しません。
  1. with を使うと、あとで使われるために user.email_all を変数に保存 します。再利用できるキャッシュが使われます。
  1. {% if emails %} 行は QuerySet.__nonzero__() の呼び出しを引き起こし ます。これは user.emails.all() がデータベースで実行されることにつながり ます。少なくとも一行目が ORM オブジェクトに変換されます。結果がなければ False を返し、あれば True を返します。
  1. {{ emails|length }}QuerySet.__len__() を呼びます。他のクエリを 実行せずにキャッシュの残りを満たします。
  1. for ループは既に満たされているキャッシュの上に繰り返されます。

全体として、このコードは 1 個か 0 個のデータベースクエリを実行します。 唯一の計画的な最適化の実施が with タグ の使用です。どの箇所で QuerySet.exists()QuerySet.count() を使っても追加のクエリの原因にな ります。

QuerySet.update()delete() を使う

オブジェクトを検索してロードし、何かの値をセットして個別に保存するよりも、 QuerySet.update() 経由でバルクの SQL UPDATE 文を使うほうが良いです。同 様に、可能な限り バルクでの削除 を使いましょ う。

しかしながら、これらのバルクアップデートメソッドは個別のインスタンスの save()delete() メソッドを呼べないことに注意してください。つまり、 通常のデータベースオブジェクト シグナル によって起動され るものも含め、開発者がこれらのメソッドに追加したいかなるカスタムの動作も実行さ れないことになります。

外部キーの値を直接使う

外部キーの値が必要なだけなら、関連するオブジェクトの全体を取得してそのプライマ リキーを得るのではなく、既に取得しているオブジェクトの外部キーの値を使いましょ う。例えばこのようにする代わりに:

entry.blog.id

こうします:

entry.blog_id
バルクでのインサート

複数のオブジェクトを作る時、可能であれば、 bulk_create() メソッドを使って SQL ク エリの数を減らしましょう。例えば:

Entry.objects.bulk_create([
    Entry(headline="Python 3.0 Released"),
    Entry(headline="Python 3.1 Planned")
])

が以下よりも望ましいです:

Entry.objects.create(headline="Python 3.0 Released")
Entry.objects.create(headline="Python 3.1 Planned")

このメソッドに関する注意 がたくさんありますので、ユースケースに合致しているか確認してください。

このことは ManyToManyFields にも当 てはまります。このようにすることは:

my_band.members.add(me, my_friend)

以下よりも良いです:

my_band.members.add(me)
my_band.members.add(my_friend)

ここで BandsArtists は多対多の関係を持っているとします。

HTTP リクエストの処理

revision-up-to:11321 (1.1)

このセクションでは、 Django における HTTP リクエスト処理に関する情報を扱っ ています:

URL ディスパッチャ

revision-up-to:17812 (1.4)

すっきりした、簡潔で明解な URL スキームの設計は、高品質の Web アプリケーショ ンでは重要な要素です。 Django では、フレームワークの制限なしに、望み通りの URL を設計できます。

.php.cgi といった拡張子は必要なく、 0,2097,1-1-1928,00 のよ うな意味不明の URL にする必要もありません。

URL はすっきりした扱いやすいものにすべきであるという主張については、ワール ドワイドウェブの産みの親である Tim Berners-Lee の優れた解説、 Cool URIs don’t change を参照してください。

概要

あるアプリケーション向けの URL を設計するには、 URLconf (URL 設定: URL configuration) と呼びならわされている Python モジュールを作成します。このモ ジュールは pure Python のコードで、中にはただ URL パターン (単純な正規表現) から Python のコールバック関数 (自作のビュー) へのマッピングが入っているだ けです。

Django はまた、 URL が稼働している言語から翻訳することを許可しています。 このプロセスは、 internationalization docs で、説明 しています。

このマッピングは短くもできますし、必要なだけ長くもできます。他のマッピング も参照できます。また、 pure Python コードなので、動的に生成できます。

Django のリクエスト処理

ユーザが Django で作られたサイト上のページをリクエストした時に、どの Python コードが実行されるかは以下のアルゴリズムで決定されます:

  1. まず、Django は、どのモジュールをルート URLconf として使うか決定しま す。もともとは、この値は ROOT_URLCONF に設定されています。ただし、 HttpRequest オブジェクトに urlconf という属性が設定されてい た場合( request processing で設定されます) 、その値を ROOT_URLCONF の代わりに使います。
  2. Django は上記の Python モジュールをロードして、 urlpatterns とい う名前の変数を探します。この変数の値は Python のリストで、 django.conf.urls.patterns() が返すのと同じ形式です。
  3. Django は URL パターンを順に調べて、リクエスト URL に最初にマッチし たところで止まります。
  4. 何らかの正規表現にマッチしたら、 Django はマッピングされているビュー を import して呼び出します。ビューは単純な Python 関数です。ビュー関 数の第一引数には HttpRequest が、それ以降の引 数には正規表現でキャプチャした値が渡されます。
  5. もし、正規表現が何にもマッチしなかったり、パターンマッチングプロセスの 途中のどこかで例外が発生した場合、 Django は、適切なエラーハンドリング ビューを呼び出します。 エラーハンドリング を見てください。
凡例

URLconf の一例を示します:

from django.conf.urls import patterns, url, include

urlpatterns = patterns('',
    (r'^articles/2003/$', 'news.views.special_case_2003'),
    (r'^articles/(\d{4})/$', 'news.views.year_archive'),
    (r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
    (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)

注意:

  • URL 中の値を取り出すには、単に丸括弧で囲むだけです。
  • 先頭のスラッシュは必要ありません。全ての URL に共通だからです。例えば、 ^/articles ではなく ^articles にします。
  • 正規表現文字列のリテラルの前に 'r' があります。これは必須ではあり ませんが、付けた方がよいでしょう。 r は、”raw” 文字列、すなわち文 字列中のいかなる文字もエスケープしないことを表します。 Dive Into Python’s explanation も参考にしてください。

例のリクエストを挙げて説明しましょう:

  • /articles/2005/03/ へのリクエストは 3 つめのエントリにマッチしま す。 Django は news.views.month_archive(request, '2005', '03') を 呼び出します。
  • /articles/2005/3/ はどの UrL パターンにもマッチしません。リストの 3 つめのエントリでは月番号が 2 桁になるよう要求しているからです。
  • /articles/2003/ はリストの 2 番目ではなく、最初のパターンにマッチ します。パターンは順番に調べられ、最初にテストにパスしたものが使われ るからです。この法則を、特別扱いしたい URL の処理に使ってもかまいませ ん。
  • /articles/2003 は URL がスラッシュで終わっていないので、どのパター ンにもマッチしません。
  • /articles/2003/03/3/ は最後のパターンにマッチします。 Django は news.views.article_detail(request, '2003', '03', '3') を呼び出し ます。
名前つきグループ

上の例では、 名前なしの 簡単な正規表現グループを (丸括弧表記で) 使って URL から情報を取り出し、ビュー関数に 固定引数 として渡していました。より 高度な方法に、 名前つきの 正規表現グループで URL から情報を取り出し、ビュー の キーワード引数 に渡すものがあります。

Python の正規表現では、名前つき正規表現グループは、 name をグループの名 前、 pattern をマッチさせるパターンとして、 (?P<name>pattern) で表 されます。

上の URLconf の例を書き換えて、名前つきグループにしたものを示します:

urlpatterns = patterns('',
    (r'^articles/2003/$', 'news.views.special_case_2003'),
    (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
    (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'),
    (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', 'news.views.article_detail'),
)

この URLconf は前の例と全く同じ機能を実現しますが、一つだけはっきり違うのは、 取り出した値を固定引数ではなくキーワード引数としてビュー関数に渡すという点 です。例えば:

  • /articles/2005/03/ へのリクエストは、 news.views.month_archive(request, year='2005', month='03') ではなく news.views.month_archive(request, '2005', '03') を呼び出します。
  • /articles/2003/03/3/ へのリクエストは news.views.article_detail(request, year='2003', month='03', day='3') を呼び出します。

実際には、このような名前つきグループを使うと URLconf が少しだけ明示的な書き 方になり、引数の順番に起因するバグを起こしにくくなります – それに、自作ビュー の関数定義で引数順を変更できます。いうまでもなく、こうした恩恵は簡潔さの犠 牲の上に成り立っています: 開発者の中には、名前つきグループの構文が醜くて冗長 だと感じる人もいます。

マッチ/グルーピングのメカニズム

URLconf パーザが正規表現中の名前つきグループと名前なしグループを扱う際のア ルゴリズムを以下に示します:

名前つきの引数があればそれを使います。名前なし引数は無視します。名前つきの 引数がなければ、すべての名前なし引数を固定引数として使います。

どちらの場合でも、追加のキーワード引数を指定できます。後述の「ビュー関数に 追加のオプションを渡す」を参照してください。

URLconf の検索対象

URLconf はリクエストされた URL を通常の Python 文字列として検索します。この 文字列には GET や POST のパラメタも、ドメイン名も入りません。

例えば、 http://www.example.com/myapp/ URLconf が検索対象にするのは myapp/ です。

http://www.example.com/myapp/?page=3 へのリクエストの場合でも myapp/ です。

URLconf はリクエストメソッドを調べません。換言すれば、同じ URL に対する POST, GET, HEAD といった全てのリクエストメソッドは同じビュー関 数に送られます。

urlpatterns の書き方

urlpatternsdjango.conf.urls.patterns`() の返す形式の Python リストになります。 urlpatterns 変数の値を作るときには、常に patterns() を使うようにして下さい。

django.conf.urls 汎用的な関数

Deprecated since version 1.4: Django 1.4 の関数 patterns, url, include に加えて handler*django.conf.urls モジュールの中にあり、以下で説明さ れているシンボル群です。

Django 1.3 までは、これらは django.conf.urls.defaults の中に位置していました。まだ、以前のモジュールからインポート することが出来ますが、 Django 1.6 でそれが出来なくなります。

patterns
patterns(prefix, pattern_description, ...)

プレフィクス (prefix) 引数、および任意の個数の URL パターンをとり、Django で必要な形式の URL パターンのリストを返す関数です。

patterns() の最初の引数は プレフィクス (prefix) 文字列です。後述の 「 ビュープレフィクス 」 を参照してください。

残りの引数は以下の形式のタプルにします:

(正規表現, Pythonコールバック関数 [, パラメタ辞書 [, エントリ名]])

パラメタ辞書 および エントリ名 はオプションで、省略できます (詳しくは「 ビュー関数に追加のオプションを渡す 」を参照してください)。

Note

patterns() は関数呼びだしの形式を取っているので、取れる引数 (URL パ ターン) は最大 255 個に制限されています。これは全ての Python 関数呼びだ しに共通する制約です。通常は、 URL パターンを include() でモジュラ に構造化するものなので、事実上この制約はほとんど問題になりません。とは いえ、運悪く 255 個の制約に引っかかってしまうようなら、 pattern() が Python のリストを返すということを思い出して、以下のように引数を分割 し、リストを構築するとよいでしょう:

urlpatterns = patterns('',
    ...
    )
urlpatterns += patterns('',
    ...
    )

Python のリスト型にはサイズ制限がありませんから、いくつでも URL パター ンを定義できます。ただし、一度に 254 個づつ (先頭のプレフィクス引数のた めに、 255 個のうちの一つを使います) しか定義できないという制約に注意し てください。

url
url(regex, view, kwargs=None, name=None, prefix='')

url() 関数は、タプルの代わりとして patterns() の引数に指定できます。 この関数は、パラメタ辞書がないときに URLconf のエントリ名を指定したい場合に 便利です。例えば、以下のように用います:

urlpatterns = patterns('',
    url(r'/index/$', index_view, name="main-view"),
    ...
)

この関数は 5 つの引数をとり、そのほとんどが省略可能です:

url(regex, view, kwargs=None, name=None, prefix='')

name パラメタが便利な理由は「 URL パターンに名前を付ける 」の節を参 照してください。

prefix パラメタは patterns() の最初の引数と同じ意味を持ち、 view を文字列形式で指定する場合にしか使われません。

include
include(<module or pattern_list>)

関数は現在の URLconf で “included” しておくべき Python のフル import パス を他の URLconf モジュールへと 取りこみます。

include() も引数としてイテレート可能です。これは、 URL パターンを返します。

他の URLconf を取り込む を見てください。

エラーハンドリング

Django が、リクエストされた URL にマッチする正規表現を 見つけられなかったとき、または例外が発生したとき、 Django は error-handling view を発生させます。ビューはルートの URlconf に設定された三つの変数で、指定されたケースで使用 されます。これらの変数の設定は、他のどの URLconf にも影響を 与えません。

エラービューのカスタマイズ を参照してください、もっと詳しいことが載っています。

handler403
handler403

呼ぶことができます、またはユーザがリソースにアクセスするのに 必要なパーミッション(permission 権限)を持っていない場合に、 ビュー関数への完全な Python の import パスが入った文字列です。

通常、これは 'django.views.defaults.permission_denied' これのデフォルト値は満足させるでしょう。

403 (閲覧が禁止されています ビュー) にもっと沢山の情報が載っています。

handler403 は Django 1.4の新しいものです
handler404
handler404

呼び出せるか、マッチする URL パターンがない場合に呼び出されるビュー関数への、 完全な Python の import パスが入った文字列です。

デフォルト値は、 'django.views.defaults.page_not_found' です。 普通はこのデフォルト値で十分のはずです。

前のバージョンの Django では、 import パスが入った文字列のみを、受け取れ ます。
handler500
handler500

呼び出しか、サーバエラーが生じた場合に呼び出されるビュー関数への、 完全な Python の import パスが入った文字列です。 サーバエラーはビュー関数のコード中で実行時エラーが生じたときに起きます。

デフォルト値は、 'django.views.defaults.page_not_found' です。 普通はこのデフォルト値で十分のはずです。

前のバージョンの Django では、 import パスが入った文字列のみを、受け取れ ます。
URL 中のテキストを取り出す際の注意

引数として取り出したテキストは、正規表現が何にマッチするかに関係なく通常の Python 文字列型になります。例えば、下のような URLconf の行:

(r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),

では、 news.views.year_archive() に渡される year 引数は、整数ではな くあくまでも文字列になります。 \d{4} が整数を表す文字列にしかマッチしな いことは関係ありません。

よく使うトリックとして、ビュー関数の引数にデフォルトパラメタを指定しておく という方法があります。 URLconf とビューの一例をあげて説明しましょう:

# URLconf
urlpatterns = patterns('',
    (r'^blog/$', 'blog.views.page'),
    (r'^blog/page(?P<num>\d+)/$', 'blog.views.page'),
)

# View (in blog/views.py)
def page(request, num="1"):
    # Output the appropriate page of blog entries, according to num.

上の例では、 URL パターンはどちらも同じビュー、 blog.views.page を指し ています。しかし、最初のパターンでは、 URL から何の情報も取り出しません。最 初のパターンがマッチすると、 page() 関数は num の値として、デフォル トの "1" を使います。二つめのパターンがマッチすると、 page() は正規 表現で取り出した num の値を使います。

パフォーマンス

urlpatterns 内の各正規表現は、最初にアクセスした際にコンパイルされます。 これによって、システムは劇的に高速になります。

ビュープレフィクス

コードを繰り返し書かなくてもよいように、 patterns() 呼び出しの中で共通 のプレフィクスを指定できます。

Django の概要 からとってきた URLconf の例を示します:

from django.conf.urls import patterns, url, include

urlpatterns = patterns('',
    (r'^articles/(\d{4})/$', 'news.views.year_archive'),
    (r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
    (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)

この例では、各ビューには共通のプレフィクス、 'news.views' があり ます。 urlpatterns の各エントリに繰り返し入力する代わりに、 patterns() 関数の最初の引数にプレフィクスを指定して、各ビュー関数に適用 できます。

このことを念頭に置いて、上記の例をもっと簡潔に書くと以下のようになります:

from django.conf.urls import patterns, url, include

urlpatterns = patterns('news.views',
    (r'^articles/(\d{4})/$', 'year_archive'),
    (r'^articles/(\d{4})/(\d{2})/$', 'month_archive'),
    (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'),
)

プレフィクスには末尾のドット (".") を入れていないことに注意してください。 Django はドットを自動的に入れます。

複数のビュープレフィクス

現実的には、色々なビューを取り混ぜて使うことになり、 urlpatterns に共通 のプレフィクスを持たせられなくなることでしょう。しかし、パターンの重複を防 ぐビュープレフィクスのショートカット機能には、もう一つの利用法があります。 それは、以下のように複数の patterns() オブジェクトを足し合わせるという ものです:

古い書き方:

from django.conf.urls import patterns, url, include

urlpatterns = patterns('',
    (r'^$', 'django.views.generic.date_based.archive_index'),
    (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'django.views.generic.date_based.archive_month'),
    (r'^tag/(?P<tag>\w+)/$', 'weblog.views.tag'),
)

は、以下のような書き方に改められます:

from django.conf.urls import patterns, url, include

urlpatterns = patterns('django.views.generic.date_based',
    (r'^$', 'archive_index'),
    (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','archive_month'),
)

urlpatterns += patterns('weblog.views',
    (r'^tag/(?P<tag>\w+)/$', 'tag'),
)
他の URLconf を取り込む

urlpatterns 好きな場所で、他の URLconf モジュール上の定義を取り込めます。 この操作は、本質的には一連の URL を他の URLconf の下に「すげかえる(root)」 操作になります。

例として、 Django ウェブサイト 自体の URLconf の例外を示します。この URLconf は他の URLconf をいくつも取り込んでいます:

from django.conf.urls import patterns, url, include

urlpatterns = patterns('',
    # ... snip ...
    (r'^comments/', include('django.contrib.comments.urls')),
    (r'^community/', include('django_website.aggregator.urls')),
    (r'^contact/', include('django_website.contact.urls')),
    (r'^r/', include('django.conf.urls.shortcut')),
    # ... snip ...
)

この例の正規表現が、 $ (行末にマッチする文字) を使っておらず、末尾にスラッ シュを付けていることに注意しましょう。 Django が include() をみつけると、 URL からマッチした部分を取り去り、残りの文字列を include された URLconf に 送って続きの処理を行わせます。

URLconf を Python モジュールで include 引数で指定する方法ではなく、 追加した URL patterns を含める別の可能性として、 patterns によって 返されたパターンリストを直接的に使う方法があります。:

from django.conf.urls import patterns, url, include

extra_patterns = patterns('',
    url(r'^reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'),
    url(r'^charge/$', 'credit.views.charge', name='credit-charge'),
)

urlpatterns = patterns('',
    url(r'^$',    'apps.main.views.homepage', name='site-homepage'),
    (r'^help/',   include('apps.help.urls')),
    (r'^credit/', include(extra_patterns)),
)

この手法は、 Django のアドミンアプリケーションのインスタンスを配置する時に 見られます。 Django のアドミンは、 AdminSite のインスタンスとして 配置されます。それぞれの ~django.contrib.admin.AdminSite インスタンスは urls アトリビュートを持っていて、 それらは url パターンとしてインスタンスに使用可能です。 それは、アドミンのインターフェイスを配置する時に、 include() を プロジェクトの urlpatterns に入れることができます。

キャプチャされたパラメタ

include された側の URLconf は、親となる URLconf で取り出された全てのパラメ タを受け継ぎます。従って、以下のような例はうまく動作します:

# In settings/urls/main.py
urlpatterns = patterns('',
    (r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
)

# In foo/urls/blog.py
urlpatterns = patterns('foo.views',
    (r'^$', 'blog.index'),
    (r'^archive/$', 'blog.archive'),
)

上の例では、 include された側にも "username" 変数が期待どおりに渡されま す。

URL の名前空間を定義する

もし、複数のインスタンスを一つのアプリケーションで必要としたならば、 インスタンスの間で区別を付けられることが役立つでしょう。 これは、一つのアプリケーションが分割する URL の名前付けの 複数のインスタンスにおいて URL の名前付け を使う時に 特に大切になります。一つのアプリケーションの中の複数の インスタンスは、名前づけられた URL を分割します、名前空間は インスタンスそれぞれに名前づけられた URL の分割を教える方法です。

URL の名前空間は二つのパートになります、両方とも文字列です:

  • 一つは application namespace です。これはデプロイ(deploy)されている アプリケーションの名前を示します。単一のアプリケーションの全てのインスタンス は、同じアプリケーションの名前空間 を持ちます。例えば、 Django のアドミンアプリケーションは幾分予測可能な アプリケーションの名前空間を持っています admin です。
  • そして、 instance namespace です。この識別子はアプリケーションの特有の インスタンスです。インスタンスの名前空間は、プロジェクト全体に渡り、 一意のものです。これはアプリケーションの通常のインスタンスを指定するために 使われます。例えば、通常 Django のアドミンインスタンスは admin の インスタンスの名前空間を持っています。

URL の名前空間は二つの方法によって指定されています。

始めに、URL パターンを構成する時、アプリケーションとインスタンスの名前空間を、 include() の引数として、渡すことができます。:

(r'^help/', include('apps.help.urls', namespace='foo', app_name='bar'))

これは apps.help.urls のなかで定義された URL を含み、インスタンスの 名前空間 bar と、アプリケーションの名前空間 foo へといきます。

二つ目は、埋め込まれた名前空間のデータを内包するオブジェクトを含むことができま す。もし、 patterns オブジェクトを include() したなら、オブジェクトは グローバルな名前空間へと加えられます。しかしながら、三つのタプルを 含んだオブジェクトを include() することもできます:

(<patterns object>, <application namespace>, <instance namespace>)

これは、与えられたアプリケーションとインスタンスの名前空間へと指定された URL パターンを含みます。例えば、 Django の AdminSite オブジェクトの urls アトリビュートは 3つのタプルを返し、それはアドミンサイトの 全てのパターンを含んでいます。そして、アドミンインスタンスの名前を足すと アプリケーション名前空間の admin です。

一度定義した、名前空間化された URL は、名前空間から逆引きしてたどること が出来ます。もっと詳しく、名前空間づけた URL を逆引きする方法について知るには、 URL 名前空間 を見てください。

ビュー関数に追加のオプションを渡す

URLconf には、ビュー関数に追加の引数を Python の辞書型で渡せるようにするた めのフックがあります。

URLconf タプルにはオプションとして 3 つめの要素を指定できます。この要素は ビューに渡したい追加の引数からなる辞書にします。

例えば:

urlpatterns = patterns('blog.views',
    (r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}),
)

この例では、 /blog/2005/ というリクエストに対し、 Django は blog.views.year_archive() ビューを呼び出し、以下のキーワード引数を渡し ます:

year='2005', foo='bar'

このテクニックは 汎用ビュー配信フィードフレームワーク で、メタデータ やビューへのオプションを渡すために使われています。

衝突を避ける

URLconf を書くとき、名前付きのキーワード引数をキャプチャさせ、同時に追 加引数の辞書に同名の項目を追加するような書き方ができてしまいます。この 場合、辞書に設定した内容が優先されます。

include() に追加のオプションを渡す

include() にも追加のオプションを渡せます。 include() に追加のオプショ ンを渡すと、そのオプションは include された側の URLconf の 全ての URL 設定 に適用されます。

例えば、以下の二つの URLconf は機能的に全く同じです:

その 1:

# main.py: include する側
urlpatterns = patterns('',
    (r'^blog/', include('inner'), {'blogid': 3}),
)

# inner.py: include される側
urlpatterns = patterns('',
    (r'^archive/$', 'mysite.views.archive'),
    (r'^about/$', 'mysite.views.about'),
)

その 2:

# main.py: include する側
urlpatterns = patterns('',
    (r'^blog/', include('inner')),
)

# inner.py: include される側
urlpatterns = patterns('',
    (r'^archive/$', 'mysite.views.archive', {'blogid': 3}),
    (r'^about/$', 'mysite.views.about', {'blogid': 3}),
)

追加オプションは、ビューがオプションを実際に有効なオプションとして受け取る かどうかに関わらず、 常に include される側の URLconf の 全ての 行に渡さ れるので注意してください。このため、 include に追加オプションを渡すテクニッ クが有効なのは、include される側の URLconf に入っている全てのビューが、追加 のオプションを受け取れるとはっきりしている場合だけです。

文字列の代わりに呼び出し可能オブジェクトを渡す

開発者の中には、ビューのパスが入った文字列の代わりに、ビューそのものを表す Python 関数オブジェクトを渡す方が自然だと考えている者もいます。この代替案も サポートされており、任意の呼び出し可能オブジェクトをビューに渡せます。

例えば、 以下のような「文字列の」URLconf があったとします:

urlpatterns = patterns('',
    (r'^archive/$', 'mysite.views.archive'),
    (r'^about/$', 'mysite.views.about'),
    (r'^contact/$', 'mysite.views.contact'),
)

文字列の代わりにオブジェクトを渡して、同じ機能の URLconf を実現できます。オ ブジェクトを忘れず import してください:

from mysite.views import archive, about, contact

urlpatterns = patterns('',
    (r'^archive/$', archive),
    (r'^about/$', about),
    (r'^contact/$', contact),
)

以下の例も機能的に全く同じです。個々のビューを個別に import する代わりにビュー の入ったモジュールを import すると、すこしだけすっきり書けます:

from mysite import views

urlpatterns = patterns('',
    (r'^archive/$', views.archive),
    (r'^about/$', views.about),
    (r'^contact/$', views.contact),
)

どのスタイルを使うかは自由です。

このテクニックを使った場合 (文字列の代わりにオブジェクトを渡した場合) 上で説明した “”ビュープレフィクス”” は効果を及ぼさないので注意してください。

URL パターンに名前を付ける

URLconf 中の複数の URL パターンから同じビュー関数を呼ぶケースはよくあります。 たとえば、以下の二つの URL パターンは、どちらも archive というビューを 指しています:

urlpatterns = patterns('',
    (r'/archive/(\d{4})/$', archive),
    (r'/archive-summary/(\d{4})/$', archive, {'summary': True}),
)

この URLconf には何ら問題はないのですが、 (permalink() デコレータや {% url %} を使って) 逆引き URL マッチング (reverse URL matching) を 行うと問題を引き起こします。というのも、二つの URLパターンが同じビューを指 しているために、Django の逆引き URL マッチング機構は、 archive ビューに 対する正しい URL がわからなくなってしまうからです。

この問題を解決するために、Django は 名前付き URL パターン をサポートし ています。すなわち、各 URL パターンに名前をつけて、同じビューやパラメタを使っ ているパターンどうしを区別できます。その上で、付けた名前を使って逆引き URL マッチングを行えます。

例えば、 URLconf が以下のようになっていたとしましょう:

urlpatterns = patterns('',
    url(r'/archive/(\d{4})/$', archive, name="full-archive"),
    url(r'/archive-summary/(\d{4})/$', archive, {'summary': True}, "arch-summary"),
)

上記に記した名前(full-archive and arch-summary)を使って、個別にそれ ぞれのパターンの URL にアクセスすることができます。

{% url arch-summary 1945 %}
{% url full-archive 2007 %}

つまり、二つの URL パターンがどちらも同じく archive ビューを参照してい ても、 url()name パラメタを指定すれば、テンプレート中で二つを区 別できるというわけです。

URLconf エントリに付ける名前は、どんな文字を入れても構いません。 Python の 変数名規則には縛られません。

Note

URLconf エントリに名前を付ける場合、他のアプリケーションの名前と衝突し なさそうな名前を使ってください。例えば、ある URL パターンを “comment” と命名していて、他のアプリケーションでも同じ名前を使っていたとしましょ う。この名前をテンプレートで使うと、もはやどちらの URL がテンプレートに 挿入されるのか判断する術はありません。

URLconf エントリの名前に、例えばアプリケーション名などからとったプレフィ クスを追加しておけば、名前が衝突しにくくなってよいでしょう。というわけ で、単に “comment” ではなく、 “myapp-comment” にするよう勧めます。

URL 名前空間

名前空間化された URL は : 演算子を使うことによって指定されます。 例えば、アドミンアプリケーションの、メインのインデックスページは admin:index を使うことによって参照されます。

名前空間は、ネスト(nest 入れ子)することができます。 foo:bar:whiz と名前づけられた URL は、トップレベルの名前空間である foo の中から bar という名前で定義されたものを探し、さらにその中から whiz という名前のパターンを探します。

名前空間化された URL (すなわち、myapp:index のようなもの) が与えられる て解決すると、 Django は完全にパス化されたものをパーツごとに分解しようとしま す。そしてその時に、 URL の探索を行おうとします。

  1. 最初に、 Django はアプリケーションの名前空間とマッチするものを探そうとし ます。(この例では myapp です。)これは、アプリケーションのインスタンスの リストを作ります。

  2. もし、 現在の アプリケーションが定義されていれば、 Django は インスタンスの為に URL リゾルバを見つけて返します。 現在の アプリケーション は、テンプレートコンテキストの上のアトリビュートとして指定されます。 アプリケーションは複数の配置を持つことを想定していて、テンプレートのレンダ リングをするために使われる ContextRequestContextcurrent_app アトリビュートに指定されます。

    現在のアプリケーションは reverse() 関数の引数から、手動で 指定することも出来ます。

  3. もし、現在のアプリケーションがないとしたらどうでしょう。 Django は デフォルトのアプリケーションインスタンスを探します。デフォルトの アプリケーションインスタンスは、アプリケーションの名前空間とマッチする インスタンスの名前空間を持つインスタンスです。(この例では、 myapp のインスタンスは myapp と呼ばれます)

  4. もし、デフォルトのアプリケーションインスタンスがなかったとしたら、 Django は一番初めに配置されたアプリケーションのインスタンスを選択します。 それは、インスタンスの名前がどんなものであってもそうでしょう。

  5. もし、提供された名前空間がステップの1のアプリケーションの名前空間と マッチしない場合、 Djangoはインスタンスの名前空間として、直接参照しようと します。

もし入れ子になった名前空間なら、ビューの名前が逆引きできるまで、名前空間の それぞれのパートに対してこれらのステップを繰り返します。

この行動の解決戦略をお見せしましょう、 myapp: の foo と呼ばれる インスタンスと、 bar と呼ばれるものについて考えてみましょう。 myapp はメインのインデックスページを持っていて、 URL の名前は index で す。セットアップを使って、参照可能にしてみましょう。:

  • もし、インスタンスのうち一つが現在のものであれば、言い換えると、もし bar インスタンスの中でユーティリティページをレンダリングしならば、 myapp:index は、 bar インスタンスのインデックスページとして 逆引きします。
  • もし、現在のインスタンスがなければ、言い換えると、もしサイトのどこかで ページのレンダリングを行うならば、 myapp:index は最後に登録された myapp のインスタンスを逆引きします。これらは通常のインスタンスではなく、 myapp の最後のインスタンスが使われます。これは foobar で、プロジェクトの URL パターンに導入された順番に依存します。
  • foo:index は常に foo インスタンスのインデックスページを解決しようと します。

もし、通常のインスタンスも存在すれば、すなわち、 myapp と名前づけられた インスタンスが存在すると、このようなことがおきます。:

  • もし、インスタンスのうち一つが現在のものであれば、言い換えると、もし bar インスタンスの中でユーティリティページをレンダリングしならば、 myapp:index は、 bar インスタンスのインデックスページとして 逆引きします。
  • もし、現在インスタンスがなければ、言い換えるとサイトのどこかのページを レンダリングするなら myapp:index は、通常のインスタンスの インデックスページとして逆引きします。
  • foo:index は、再び foo インスタンスのインデックスページへと 逆引きします。
django.core.urlresolvers ユーティリティ関数
reverse()

コード中で url のようなことをしたい場合のために、Django では django.core.urlresolvers.reverse モジュールを提供しています:

reverse(viewname[, urlconf=None, args=None, kwargs=None, current_app=None])

viewname は関数名 (関数への参照か、関数名の文字列表記で、 urlpatterns 上で使っている形式) または URL パターン名 です。通常、 urlconf パラメタについて考える必要はなく、以下のように、固定引数とキー ワード引数だけを指定して url マッチングを行います:

from django.core.urlresolvers import reverse

def myview(request):
    return HttpResponseRedirect(reverse('arch-summary', args=[1945]))

reverse() 関数は大抵の正規表現パターンを URL に逆変換できますが、全てと は限りません。今のところ、パターン中に垂直バー ("|") を含められません。 垂直バーを含むパターンは、 URL からビューへのマッチングには問題なく使えます が、パターンの逆変換はできないので注意してください。

current_app 引数は、リゾルバが現在実行しているるビューが属している アプリケーションを指し示すためのヒントを提供します。この current_app 引数は、アプリケーションの名前空間をひも解き、指定したアプリケーション インスタンスへと導くヒントとして扱われ、 URL 名前空間 に従っています。

args の代わりに、 kwargs を用いることもできます。例えば:

>>> reverse('admin:app_list', kwargs={'app_label': 'auth'})
'/admin/auth/'

argskwargs は、 reverse() を同時に通過することはできません。

ビューが全て正しいことを確認してください

URL 名の種々のパターンへのひも付けの生成の一部として、 reverse() 関数は、 URLconf ファイルのすべてと調べる各ビューの名前 をインポートする必要があります。これは各ビュー関数のインポートと関連 しています。もし 何か エラーが、ビュー関数のインポートする中で起きれば 、それは reverse() がエラーを返す原因になります。もし、ビュー関数が 逆引きしようとしたものでなかったときでさえもです。

URLconf ファイルの中でビューの参照が実在するのと、 正しくインポートされていることを確かにしてください。 参照するビューがまだ書かれていないのに、それを行に含まないでください。 なぜならそのビューはまだインポートできないからです。

Note

reverse() によって返される文字列は、 ref:URL クオート <uri-and-iri-handling> です。例えば:

>>> reverse('cities', args=[u'Orléans'])
'.../Orl%C3%A9ans/'

もっとエンコーディングを適用するには(urlquote()urllib.quote のように) reverse() のアウトプットは望ましくない 結果を引き起こします。

reverse_lazy()
リリースノートを参照してください

reverse() の簡単に使えるバージョン

reverse_lazy(viewname[, urlconf=None, args=None, kwargs=None, current_app=None])

これは、プロジェクトの URLConf がロードされる前に、 URL 逆引きを使う必要がある 場合に便利です。いくつかの一般的なケースではこの関数がまさに必要になります:

  • ジェネリッククラスベースビューをの url アトリビュートとして、 URL を逆引きして提供する場合
  • デコレータとして、逆引き URL を提供する場合( django.contrib.auth.decorators.permission_required() の デコレータのための login_url 引数のような)
  • 関数のシグネチャの中で、パラメータとしてデフォルトの値として 逆引きした URL を提供する場合。
resolve()

django.core.urlresolvers.resolve() 関数は、URL のパスとそれに付随してい るビュー関数を呼び出すのに使われます。

resolve(path, urlconf=None)

path はあなたがひも解きたい URL パスです。 reverse() と一緒で、 urlconf パラメータ に関して考える必要はありません。この関数が返すのは ResolverMatch オブジェクトで、これは解決された URL の様々なメタデータにアクセスできる クラスです。

もし、 URL がひも解かれなかったら、関数は Http404 という例外を発生させます。

class ResolverMatch
func

URL を提供するのに使われるビュー関数です。

args

これは、ビュー関数に渡されて、 URL からパースされた 引数です。

kwargs

このキーワード引数はビュー関数に渡され、 URL からパースされた 引数です。

url_name

URL にマッチした URL パターンの名前です。

app_name

アプリケーションの名前空間で、 URL にマッチした URL パターンの 為に使われます。

namespace

インスタンスの名前空間で、 URL にマッチした URL パターンの 為に使われます。

namespaces

インスタンスのフルの名前空間の、個別の名前空間の要素を リストにしたもので、 URL パターンにマッチした URL のために 用いられます。すなわち、もし名前空間が foo:bar であるなら、 このリストは ['foo', 'bar'] になります。

ResolverMatch オブジェクトは、 URL にマッチする URL パターンに ついての情報を提供し、それの問い合わせを行うことが出来ます。:

# Resolve a URL
match = resolve('/some/path/')
# Print the URL pattern that matches the URL
print match.url_name

ResolverMatch オブジェクトは、三つのものに対して割当てられます。:

func, args, kwargs = resolve('/some/path/')
三つの割当は、逆方向への互換性のためにあります。 resolve() は Django 1.3 では、 三つのものを含んで(ビュー関数と、引数、キーワード引数)いて、 ResolverMatch object (名前空間とパターン情報の提供も同じように) は DJango の前バージョンのものでは使えません。

一つの resolve() の使い方としては、 Http404 エラーが出ているかどうかを、リダイレクトする前にテストする ような用途です。:

from urlparse import urlparse
from django.core.urlresolvers import resolve
from django.http import HttpResponseRedirect, Http404

def myview(request):
    next = request.META.get('HTTP_REFERER', None) or '/'
    response = HttpResponseRedirect(next)

    #リクエストとレスポンスを必要に合わせて変更してください。
    #依存するローカルな環境のクッキーもセットしてください。

    view, args, kwargs = resolve(urlparse(next)[2])
    kwargs['request'] = request
    try:
        view(*args, **kwargs)
    except Http404:
        return HttpResponseRedirect('/')
    return response
get_script_prefix()
get_script_prefix()

通常、 reverse() を 使うか、 permalink() を URL を アプリケーション内で定義するために用います。しかし、もしアプリケーションが 自身の URL の階層の一部分を構成するのならば、 URL を生成する機会が必要です。 このようなケースで、 Web サーバー内の Django プロジェクトの ベース URL を 見つけられる必要があり(通常、 reverse() がこのような必要性を満たしてくれます)、この場合、 get_script_prefix() を呼ぶと、Django プロジェクトにへ URL スクリプトのプレフィクスを返します。 もし、 Django プロジェクトが Web サーバーのルートに存在するなら、 これは常に "/" になります、しかしこれは変更可能です、 django.root を使うことでインスタンスで出来ます。( Django と Apache と mod_python を見てください。)

ビューを書く

revision-up-to:17812 (1.4)

ビュー関数、あるいは単に ビュー とは、簡単にいえばウェブリクエストを引数 にとり、ウェブレスポンスを返す関数です。レスポンスはウェブページを表す HTML コンテンツでもよいし、リダイレクトでも、 404 エラーでも、 XML ドキュメント でも、画像でも、何でもかまいません。ビューの中には、レスポンスを生成する上 で必要なロジックを自由に書けます。ビューのコードは、 Python パス上にあるか ぎり、どこに置いてもかまいません。他にはなんの制限も「黒魔術」もありません。 慣習では、 プロジェクトディレクトリかアプリケーションディレクトリの下に views.py という名前のファイルを作成して、そこにビューのコードを置くこと になっています。

簡単なビュー

以下に示すのは、現在の日付や時刻を HTML 形式で返すビューの例です:

from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

Let’s step through this code one line at a time:

  • まず、 django.http モジュールから HttpResponse クラスを import しています。 Python の datetime ライブラリもロードしておきます。

  • 次に、 current_datetime という関数を定義しています。これがビュー 関数です。ビュー関数は第一引数に HttpRequest オブジェクトを取ります。慣習的に、この引数の名前は request にして います。

    ビュー関数はどんな名前でもかまいません。Django にビュー関数として認識 してもらうために、何らかの特殊な命名規則に従う必要はないのです。ここ では、 current_datetime という名前を付けて、どんな機能のビューか 分かりやすくしています。

  • ビューは、生成したレスポンスコンテンツの入った HttpResponse オブジェクトを返します。ビュー関数 は HttpResponse オブジェクトを返さねばなりません (例外も返してよ いのですが、それについては後で説明します)。

Django のタイムゾーン設定

Django には TIME_ZONE 設定があり、デフォルト値は America/Chicago に設定されています。お住まいの地域がここでなければ、 変更しておいてください。

URL をビューにマップする

このビュー関数は、現在の日付と時刻が入った HTML ページを生成して返します。 何らかの URL でこのビューを表示したければ、 URLconf を作成する必要があり ます。 URL ディスパッチャ の説明を読んでください。

エラーを返す

Django では、簡単に HTTP エラーコードを返せます。エラー応答は、すでに述べた HttpResponseNotFound, HttpResponseForbidden, HttpResponseServerError といったサブクラスのインスタンスを作成して、 以下の例のように通常の HttpResponse の代わりに返すだ けです:

def my_view(request):
    # ...
    if foo:
        return HttpResponseNotFound('<h1>Page not found</h1>')
    else:
        return HttpResponse('<h1>Page was found</h1>')

全ての HTTP レスポンスコードごとに特別なサブクラスがあるわけではありません。 多くは共通化できるからです。しかし HttpResponse のドキ ュメントにあるように、 HttpResponse のコンストラクタに HTTP ステータスコードを渡すことで、好きなステータスコードを返すクラスを作れ ます。例:

def my_view(request):
    # ...

    # Return a "created" (201) response code.
    return HttpResponse(status=201)

ただし、 404 エラーは他の HTTP エラーよりはるかに良く使われるエラーなので、 もっと簡単に扱う方法を提供しています。

Http404 例外
class django.http.Http404

HttpResponseNotFound` のようなエラーを返す場合、以下 のように、エラーページの中身になる HTML を指定せねばなりません:

return HttpResponseNotFound('<h1>Page not found</h1>')

これはちょっと不便ですね。それに、サイト全体で一貫した 404 エラーページを用 意しておく方が賢明です。そこで、 Django には Http404 例外があります。 ビュー関数のどこかで Http404 例外を送出すると、 Django はこのエラーを捕 捉して、サイト標準のエラーページを HTTP エラーコード 404 で返します。

例を示しましょう:

from django.http import Http404

def detail(request, poll_id):
    try:
        p = Poll.objects.get(pk=poll_id)
    except Poll.DoesNotExist:
        raise Http404
    return render_to_response('polls/detail.html', {'poll': p})

Http404 例外を使うには、 404 エラーの送出時に表示されるテンプレートを作 成しておかねばなりません。このテンプレートの名前は 404.html で、テンプ レートツリーの一番上に配置せねばなりません。

エラービューのカスタマイズ
404 (ページが見つかりません) ビュー

Http404 例外を送出すると、 Django は 404 エラー処理用の特殊なビューをロー ドします。デフォルトでは、このビューは django.views.defaults.page_not_found に設定されています。 django.views.defaults.page_not_found404.html という名前のテンプ レートをロードしてレンダします。

このため、テンプレートディレクトリの再上階層に 404.html という名前のテ ンプレートを作成しておかねばなりません。このテンプレートは全ての 404 エラー に対して用いられます。デフォルトの 404 ビューはテンプレートに request_path という変数を渡します。これはエラーになった URL です。

page_not_found ビューは 99% の Web アプリケーションの要求を満たすはずで

すが、 404 ビューを自作したい場合には、URLconf で以下のようにして handler404 を指定します:

handler404 = 'mysite.views.my_custom_404_view'

舞台裏では、 Django はルート URLconf の handler404 を介して 404 ビューを 捜し出します。定義がなければ django.views.defaults.page_not_found にフォ ールバックします。

404 ビューについて、知っておかねばならないことが 4 つあります:

  • 404 ビューは、リクエストされた URL に対して、 Django が URLconf の全 ての正規表現を調べた結果、一致するものをみつけられなかった場合にも呼 び出されます。
  • 404 ビューを自作せず、ただデフォルトのビューを使う場合でも、一つだけ やらねばならないこととして、 404.html という名前のテンプレートを 作成せねばなりません。
  • 404 ビューに渡されるコンテキストは django.template.RequestContext なので、テンプレートには TEMPLATE_CONTEXT_PROCESSORS で追加した変数も 渡ります。 (例えば MEDIA_URL)
  • (settings モジュールで) DEBUGTrue にすると、 404 ビューは 呼び出されず、代わりにトレースバックが表示されます。
500 (サーバエラー) ビュー

404 エラーと同様に、 Django はビューのコード上で実行時エラーに遭遇した場合 の挙動も特別扱いしています。ビューを実行した結果、例外が送出されると、 Django はデフォルトで django.views.defaults.server_error というビューを 呼び出します。このビューは 500.html というテンプレートをロードしてレン ダします。

このため、テンプレートディレクトリの再上階層に 500.html という名前のテ ンプレートを作成しておかねばなりません。このテンプレートは全ての 500 エラー に対して用いられます。デフォルトの 500 ビューはテンプレートに一切変数を渡さ ず、空の Context インスタンスを渡してレンダリングを実行しますが、これは さらなるエラーが発生するのを防ぐためです。

server_error ビューは 99% の Web アプリケーションの要求を満たすはずです が、 500 ビューを自作したい場合には、URLconf で以下のようにして handler500 を指定します:

handler500 = 'mysite.views.my_custom_error_view'

舞台裏では、 Django はルート URLconf の handler500 を介して 500 ビューを 捜し出します。何も定義していなければ、 django.views.defaults.server_error にフォールバックします。

500 ビューについて、知っておかねばならないことが 2 つあります:

  • 500 ビューを自作せず、ただデフォルトのビューを使う場合でも、一つだけ やらねばならないこととして、 500.html という名前のテンプレートを 作成せねばなりません。
  • (settings モジュールで) DEBUGTrue にすると、 500 ビューは 呼び出されず、代わりにトレースバックが表示されます。
403 (閲覧が禁止されています) ビュー
リリースノートを参照してください

404 ビュー、 500 ビューと同じスタイルで、 Django は 403 Forbidden エラーを 処理するためのビューを持っています。ビューが 403 例外を起こしたら、 Django はデフォルトでは django.views.defaults.permission_denied ビューを呼びま す。

このビューは 403.html テンプレートを最上階層のテンプレートディレクトリ からロードし、レンダします。ファイルがない場合、 RFC 2616 (HTTP 1.1 仕様) により “403 Forbidden” テキストを返します。

404 や 500 ビューと同じように、 handler403 を URLconf に設定することで django.views.defaults.permission_denied をオーバーライドできます:

handler403 = 'mysite.views.my_custom_permission_denied_view'

ビューのデコレータ

Django には、HTTP の様々な機能をビューに適用するためのいくつかのデコレータ が用意されています。

HTTP メソッドの制限

django.views.decorators.http 内の以下のデコレータはリクエストメソッド によるアクセス制限に使用できます。このデコレータは、条件を満たしていない 場合 django.http.HttpResponseNotAllowed を返します。

require_http_methods(request_method_list)

特定のリクエストメソッドのみを許可するためのデコレータの利用方法です:

from django.views.decorators.http import require_http_methods

@require_http_methods(["GET", "POST"])
def my_view(request):
    # I can assume now that only GET or POST requests make it this far
    # ...
    pass

リクエストメソッドは大文字にする必要があります。

require_GET()

ビューに GET メソッドのみを許可するデコレータです。

require_POST()

ビューに POST メソッドのみを許可するデコレータです。

require_safe()
リリースノートを参照してください

ビューに GET と HEAD メソッドのみを許可するデコレータです。 これらのメソッドは、リクエストされたリソースを取得する意外の目的で使用 すべきではないので、一般的に “safe” (安全) と見なされています。

Note

Django は、HEAD リクエストのレスポンスからヘッダは変更せず、 コンテンツを自動的に削除するため、GET リクエストのビューと同様に処理 できます。リンクチェッカー等のソフトウェアは、 HEAD リクエストに依存しているので、 require_GET よりも require_safe を使うほうが良いでしょう。

ビューの条件処理

django.views.decorators.http 内の以下のデコレータは特定のビューの キャッシュ制御に使用できます。

condition(etag_func=None, last_modified_func=None)
etag(etag_func)
last_modified(last_modified_func)

これらのデコレータは ETagLast-Modified ヘッダの生成に 使用します。詳細については ビューの条件処理 を参照してください。

GZip 圧縮

django.views.decorators.gzip 内のデコレータはビュー単位でコンテンツの 圧縮を制御します。

gzip_page()

このデコレータは、ブラウザが gzip 圧縮に対応している場合に圧縮します。 Vary ヘッダをセットするので、 Accept-Encoding ヘッダに基づいてキャッシュに保管されます。

Vary ヘッダ

django.views.decorators.vary 内のデコレータにより特定のリクエストヘッダ に基づきキャッシュを制御できます。

vary_on_headers(*headers)

Vary ヘッダは、キャッシュメカニズムがキャッシュキーを生成する際に考慮 すべきリクエストヘッダを定義します。

詳細については Vary ヘッダを使う を参照してください。

ファイルアップロード

revision-up-to:17812 (1.4)

多くの Web サイトにとって、ファイルアップロードのサポートは不可欠ですね。 Django がアップロードされたファイルを扱うとき、ファイルデータは最終的に request.FILES に入ります (request オブジェクトの詳細は リクエスト/レスポンスオブジェクト のドキュメ ントを参照してください)。このドキュメントでは、ファイルがどのようにしてディ スクやメモリ上に保存されるかを説明し、そのデフォルトの動作をカスタマイズす る方法について説明します。

ファイルアップロードの基本

FileField を含む以下のような簡単なフォームを考えて みましょう:

from django import forms

class UploadFileForm(forms.Form):
    title = forms.CharField(max_length=50)
    file  = forms.FileField()

このフォームからの入力を扱うビューは、ファイルデータを request.FILES で受け取ります。 request.FILES は ファイルデータの入った辞書で、辞書のキーはフォームクラス中の FileField (または ImageFieldFileField のサブクラス) の名前です。従って、 上の例では、 request.FILES['file'] でファイルデータにアクセスできます。

もしリクエストメソッドが POST であり、尚且つ <form> において アトリビュート enctype="multipart/form-data" を含むリクエストが ポストされたのであれば、 request.FILES はデータのみを含んでいる事に注意して下さい。 そうでない場合 request.FILES は空です。

ほとんどの場合は、「 アップロードされたファイルをフォームに結びつける 」の節で説明した方法に従っ て、 request からデータを取り出してフォームに渡すだけでアップロードファ イルを処理できます:

from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
# アップロードファイルを処理する関数を import します
from somewhere import handle_uploaded_file

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
            return HttpResponseRedirect('/success/url/')
    else:
        form = UploadFileForm()
    return render_to_response('upload.html', {'form': form})

request.FILES を明示的にフォーム のコンストラクタに渡さねばならないので注意してください。 これはフォームにファイルデータを結びつけるために必要な手順です。

アップロードファイルの処理
class UploadedFile

パズルの最後のピースは request.FILES からの実際のデータファイルをハンドリングすることです。 この辞書の各エントリーはアップロードされたファイルをシンプルなラッパで 包んだ UploadedFile オブジェクトです。 通常、アップロードされた内容にアクセスする為にこれらのメソッドのいずれか を使う事になるでしょう:

read()

アップロードされたデータ全体をファイルから読み出します。このメソッ ドを使うときに十分注意してください。というのも、アップロードされた ファイルが巨大だと、メモリに読み込む際にシステムの容量を越してしま うかもしれないからです。そのようなときは、後述の chunks() を使う とよいでしょう。

multiple_chunks()

ファイルが大きくて、複数のチャンクに分けて読み出すべきである場合に True を返します。デフォルトの設定では、 2.5 Mbytes より大きなファ イルに対して True を返します。サイズの閾値は設定でき、後で説明 します。

chunks

ファイルのチャンクを返すジェネレータです。 multiple_chunks()True の場合には、 read() ではなくこのメソッドを使ってくださ い。

実際には、常に chunks() を使うのがよいでしょう。後述の例を参照 してください。

name

my_file.txt のような、アップロードされたファイルの名前です。

size

アップロードファイルのサイズ(単位バイト)です。

UploadedFile オブジェクトは他にもいくつかメソッドや属性を備えています。 詳しくは UploadedFile オブジェクト を参照してください。

まとめると、アップロードファイルの一般的な処理例は以下の通りです:

def handle_uploaded_file(f):
    destination = open('some/file/name.txt', 'wb+')
    for chunk in f.chunks():
        destination.write(chunk)
    destination.close()

上の例では、巨大なファイルを read() してシステムの容量を超えないように、 UploadedFile.chunks() を使っています。

アップロードされたファイルの保存先

アップロードされたファイルデータは、処理され保存される前に、システムのどこ かに一時的に記憶されていなければなりません。

デフォルトの設定では、アップロードされたファイルデータが 2.5 Mbytes より小 さければ、 Django はファイルデータ全体をメモリに保持します。そのため、ファ イルデータの保存処理はメモリからディスクへの書き込みだけで実現され、高速で す。

しかし、ファイルデータが大きすぎる場合、 Django はファイルデータをシステム のテンポラリディレクトリに一時ファイルとして保存します。従って、 *nix ライ クのプラットフォームでは、 Django は /tmp/tmpzfp6I6.upload のような ファイルを生成します。ファイルデータがとても大きければ、 Django がデータを ディスクにストリーム書き込みするにつれて、一時ファイルのサイズが増えてゆく のを観察できるでしょう。

2.5 Mbytes や /tmp といった仕様は、単に「妥当なデフォルト値」にすぎませ ん。アップロード時の挙動をカスタマイズしたり完全に置き換えたりしたければ、 この後の詳細説明に進んでください。

アップロードファイルハンドラの挙動を変更する

ファイルアップロードの挙動は、以下の 3 つの設定で制御できます:

FILE_UPLOAD_MAX_MEMORY_SIZE
アップロードされたファイルをメモリに保存する上限のサイズです。 設定値よりも大きなファイルがアップロードされると、ファイルデータは ディスクに書き込まれます。 デフォルト値は 2.5 Mbytes です。
FILE_UPLOAD_TEMP_DIR

FILE_UPLOAD_MAX_MEMORY_SIZE より大きなファイルがアップロー ドされたときにファイルデータを保存するディレクトリです。

デフォルト値はシステム標準の一時ファイルディレクトリです (UNIX ライクのシステムでは /tmp です)。

FILE_UPLOAD_PERMISSIONS

アップロードされたファイルに設定するファイルモードで、数字で表現 (例: 0644) します。ファイルモードの意味は os.chmod() のドキュメントを参照してください。

この値を設定しないか、 None にすると、アップロードされたファイ ルのモードはオペレーティングシステムに依存します。ほとんどのプラッ トフォームでは、一時ファイルのファイルモードは 0600 で、メモリ からファイルにデータを書き出すときにはシステム標準の umask を使います。

Warning

ファイルモードにあまりくわしくないのなら、先頭の 0 がとても 重要だということに注意してください。先頭の 0 は、値が 8 進数で あることを示しています。 644 のように指定すると、全くおかし な挙動になってしまうでしょう。

ファイルモードの先頭には常に 0 をつけてください.

FILE_UPLOAD_HANDLERS

アップロードファイルを処理する実際のハンドラです。 この設定を変更すると、ファイルアップロードの処理を完全にカスタマイ ズでき、 Django のアップロード処理全体の置き換えすらできます。 詳しくは後述の アップロードハンドラ を参照してください。

デフォルト値は以下の通りです:

("django.core.files.uploadhandler.MemoryFileUploadHandler",
 "django.core.files.uploadhandler.TemporaryFileUploadHandler",)

このデフォルトの設定では、アップロードされたファイルをまずメモリに 保存しようと試み、その後ファイルへの保存を試みます。

UploadedFile オブジェクト

File から継承したものの他に、 UploadedFile オブジェクトは、以 下のメソッドや属性を定義しています。

UploadedFile.content_type

content-type ヘッダの内容 (text/plainapplication/pdf など) です。ユーザが指定した他のデータ同様、 この値がアップロードされたファイルのコンテンツタイプを正確に表してい ると信用してはなりません。アップロードされたファイルのコンテンツタイプ が content-type ヘッダと一致しているか確かめておく必要があります。 「値は一応信用するが、検証し」てください。

UploadedFile.charset

content-typetext/* のときに、ブラウザが指定した 文字セット (utf8 など) です。「値は一応信用するが、検証する」よう にしてください。

UploadedFile.temporary_file_path

アップロードファイルがディスクに一時保存されているときにのみ使える メソッドで、一時ファイルの完全なパスを返します。

Note

通常の Python のファイルオブジェクトと同じく、アップロードファイルをイ テレータとして扱うと、ファイルの内容を一行づつ読めます:

for line in uploadedfile:
    do_something_with(line)

しかし、標準の Python ファイルとは 違ってUploadedFile は 改行文字として \n (いわゆる Unix形式) しか認識しません。 \n 以 外の改行で終端されたアップロードファイルを処理する必要があるのなら、ビュ ー内で適切に処理する必要があります。

アップロードハンドラ

ユーザがファイルをアップロードすると、 Django はファイルデータを アップロードハンドラ (upload handler) と呼ばれるクラスに渡します。このク ラスはアップロードされたファイルデータを処理するためのクラスです。 デフォルトのアップロードハンドラは FILE_UPLOAD_HANDLERS で以下の ように定義されています:

("django.core.files.uploadhandler.MemoryFileUploadHandler",
 "django.core.files.uploadhandler.TemporaryFileUploadHandler",)

MemoryFileUploadHandlerTemporaryFileUploadHandler は、Django の デフォルトのファイルアップロード処理、すなわち、小さいファイルはメモリに読 み込み、大きいファイルはディスクに読み込むという動作を実現します。

カスタムのハンドラを書けば、ファイルの処理方法をカスタマイズできます。例え ば、カスタムハンドラによってユーザレベルで容量制限を課したり、データをオン ザフライで圧縮したり、プログレスバーを描画したり、受け取ったデータをローカ ルに保存せず、直接別のストレージに送ったりできます。

アップロードハンドラをオンザフライで変更する

ビューごとに別々のアップロード処理を行いたい場合があります。その場合、 リクエストごとに request.upload_handlers を変更してアップロードハンドラ のチェインをオーバライドできます。デフォルトでは、 request.upload_handlers には FILE_UPLOAD_HANDLERS に指定した ハンドラのリストが入っていますが、これを他のリストに変更できます。

例えば、 ProgressBarUploadHandler というハンドラを書いて、 Ajax ウィジェットに何らかのアップロード状態のフィードバックを返させたいとしましょ う。以下のようにすれば、アップロードハンドラチェインに自作のハンドラを付加 できます:

request.upload_handlers.insert(0, ProgressBarUploadHandler())

この場合は、プログレスバーのハンドラを他のハンドラ よりも前に 実行したい ので、 (append() ではなく) list.insert() を使うことになるでしょう。 アップロードハンドラチェインは、順番に実行されることを思い出してください。

完全にアップロードハンドラチェインを置き換えてしまいたければ、単にリストを 代入してください:

request.upload_handlers = [ProgressBarUploadHandler()]

Note

アップロードハンドラチェインを変更できるのは、 request.POSTrequest.FILES にアクセスする よりも前 だけです。アップロードの処 理が始まってしまった後でハンドラを変更しても何の意味もありません。 request.POSTrequest.FILES を読み出した後で request.upload_handlers を変更しようとすると、 Django はエラーを送 出します。

従って、アップロードハンドラチェインはビュー処理の出来るだけ早い段階で 変更しておくことになるでしょう。 また request.POST は通常与えられる CsrfViewMiddleware によって許可されます。 これはビューの中でアップロードハンドラの変更をする為に csrf_exempt() を使う必要がある事を 意味します。 またそのとき csrf_protect() を リクエストの実際のプロセスの関数上で使う必要があります。 このときハンドラがCSRFチェックが行われる前にファイルアップロードを受け取 り始める可能性がある事に注意して下さい。 Example code:

from django.views.decorators.csrf import csrf_exempt, csrf_protect

@csrf_exempt
def upload_file_view(request):
    request.upload_handlers.insert(0, ProgressBarUploadHandler())
    return _upload_file_view(request)

@csrf_protect
def _upload_file_view(request):
    ... # Process request
カスタムのアップロードハンドラを書く

ファイルアップロードハンドラは、全て django.core.files.uploadhandler.FileUploadHandler のサブクラスでなけれ ばなりません。アップロードハンドラはどこに記述してもかまいません。

必須のメソッド

カスタムのファイルアップロードハンドラは以下のメソッドを 必ず 定義せねばなりません:

FileUploadHandler.receive_data_chunk(self, raw_data, start)

ファイルアップロード時に、データの「チャンク」を受け取ったときに呼 び出されます。

raw_data はアップロードされたデータの入ったバイト文字列です。

startraw_data チャンクのファイルデータ中の開始位置です。

このメソッドが返すデータは、次のアップロードハンドラの receive_data_chunk メソッドにフィードされます。この仕組みによって、 あるハンドラにデータを「フィルタ」させ、他のハンドラに入力できます。

receive_data_chunk で受け取ったデータを後続のハンドラに処理させたく ない場合には None を返してください。このメソッドは、アップロードさ れたデータを自分で処理して、他のハンドラにデータを保存させたくない場合に 便利です。

StopUploadSkipFile といった例外を送出すると、アップロード 処理は中断し、アップロードファイルの処理を行いません。

FileUploadHandler.file_complete(self, file_size)

ファイルのアップロードが終了したときに呼び出されます。

このハンドラは request.FILES に入れるための UploadedFile オブジ ェクトを返さねばなりません。後続のアップロードハンドラに UploadedFile を返させたい場合は None を返してください。

オプションのメソッド

カスタムのアップロードハンドラでは、以下のオプションのメソッドや属性を定義 できます:

FileUploadHandler.chunk_size

Django がアップロードファイルをメモリ上に読み込み、ハンドラに渡すときに 使うチャンクのサイズです。バイト単位です。この属性は、 FileUploadHandler.receive_data_chunk で読み込まれるチャンクのサイズ 指定でもあります。

パフォーマンスを最大化するには、チャンクのサイズを 4 の倍数とし、 2GB (231 バイト) 以下とすべきです。複数のハンドラがそれぞれ別々 のチャンクサイズを提供していた場合、 Django は最小のチャンクサイズを使い ます。

デフォルト値は 64*210 バイトまたは 64 KB です。

FileUploadHandler.new_file(self, field_name, file_name, content_type, content_length, charset)

新たなファイルアップロードが開始されるときに呼び出されるコールバックです。 このメソッドは、アップロードハンドラがまだデータを受け取っていない段階で 呼び出されます。

field_name はファイルの <input> フィールドの名前です。

file_name は unicode のファイル名としてブラウザから提供された値です。

content_type'image/jpeg' のような MIME タイプで、ブラウザから 提供された値です。

content_length はファイルの長さで、ブラウザから提供された値です。 ブラウザがファイルサイズを提供しないこともあり、その場合は None です。

charset は (utf8 のような) 文字セットで、ブラウザから提供さ れた値です。 content_length と同様、指定されないこともあります。

他のハンドラにファイルを処理させたくない場合、このメソッドから StopFutureHandlers 例外を送出してもかまいません。

FileUploadHandler.upload_complete(self)
ファイル全体のアップロードが終了したときに呼び出されるコールバックです。
FileUploadHandler.handle_raw_input(self, input_data, META, content_length, boundary, encoding)

このメソッドを使うと、生の HTTP 入力の解析を完全にオーバライドできます。

input_dataread() をサポートするファイルライクオブジェクトです。

METArequest.META と同じです。

content_lengthinput_data に入っているデータの長さです。 input_data から content_length バイト以上を読み出そうとしてはなり ません。

boundary はリクエストの MIME バウンダリです。

encoding はリクエストのエンコーディングです。

アップロードの処理を他のハンドラに継続させたい場合には None を、 リクエストの直接処理に適したデータ構造を新たに生成して返したければ (POST, FILES) のタプルを返してください。

ショートカット関数

revision-up-to:17812 (1.4)

django.shotcuts パッケージでは、MVC の複数のレベルを「橋渡し」するため のヘルパ関数やクラスを定義しています。言い換えると、これらの関数やクラスは、 利便性を実現するために、きちんと制御された形でのカップリングを行えるように しているのです。

render
render(request, template[, dictionary][, context_instance][, content_type][, status][, current_app])
リリースノートを参照してください

与えられたテンプレートとコンテキスト辞書を結合し HttpResponse オブジェクトをレンダされたテキストと ともに返します。

render()render_to_response()context_instance 引数に、使用させる RequestContext を渡した場 合と同じ動作をします。

必須の引数
request
レスポンスを生成する時に使われるリクエストオブジェクト。
template
テンプレートの完全名か、テンプレート名のシーケンス。
省略可能な引数
dictionary
テンプレートコンテキストに追加したい値の入った辞書です。デフォルトでは、 この引数は空の辞書です。辞書の値が呼出可能オブジェクトである場合、ビュー はテンプレートをレンダするの直前にこの値を呼び出します。
context_instance
テンプレートをレンダする時に使われるコンテキストインスタンス。デフォル トではテンプレートは RequestContext インスタンス (requestdictionary の値が入っています) によってレンダリングされます。
content_type
レンダ結果のドキュメントに対して指定する MIME タイプです。デフォルトの 値として、 DEFAULT_CONTENT_TYPE を使います。
status
レスポンスのステータスコード。デフォルトは 200
current_app
現在のビューを含むアプリケーションを示すヒント。詳しくは 名前空間による URL 解決の戦略 を参照してください。

次の例は myapp/index.html テンプレートをレンダし、 MIMETYPE に application/xhtml+xml を使います:

from django.shortcuts import render

def my_view(request):
    # View code here...
    return render(request, 'myapp/index.html', {"foo": "bar"},
        content_type="application/xhtml+xml")

この例も同等の処理をします:

from django.http import HttpResponse
from django.template import RequestContext, loader

def my_view(request):
    # View code here...
    t = loader.get_template('myapp/template.html')
    c = RequestContext(request, {'foo': 'bar'})
    return HttpResponse(t.render(c),
        content_type="application/xhtml+xml")
render_to_response
render_to_response(template_name[, dictionary][, context_instance][, mimetype])

引数に指定したテンプレートとコンテキストを使ってテンプレートをレンダし、 レンダ結果のテキストの入った HttpResponse オブジェ クトを返します。

必須の引数
template
利用したいテンプレートの名前、またはテンプレート名のシーケンスです。 もしシーケンスが与えられると、存在する最初のテンプレートを使います。 テンプレートローダードキュメント に、どのようにしてテンプレートを見つけるかの詳しい情報があります。
省略可能な引数
dictionary
テンプレートコンテキストに追加したい値の入った辞書です。デフォルトでは、 この引数は空の辞書です。辞書の値が呼出可能オブジェクトである場合、ビュー はテンプレートをレンダするの直前にこの値を呼び出します。
context_instance

テンプレートをレンダするときに使うコンテキストインスタンスです。デフォ ルトでは、テンプレートは (dictionary の値が入った) Context インスタンスを使ってレンダされます。 コンテキストプロセッサ を使 いたい場合には、例えば以下のように RequestContext を使ってテンプレートをレンダし てください:

return render_to_response('my_template.html',
                          my_data_dictionary,
                          context_instance=RequestContext(request))
mimetype

レンダ結果のドキュメントに対して指定する MIME タイプです。デフォルトの 値として、 DEFAULT_CONTENT_TYPE を使います。

使用例

以下の例では、 myapp/index.html を MIME タイプ application/xhtml+xml でレンダしています:

from django.shortcuts import render_to_response

def my_view(request):
    # View code here...
    return render_to_response('myapp/index.html', {"foo": "bar"},
        mimetype="application/xhtml+xml")

上の例は、以下の例と等価です:

from django.http import HttpResponse
from django.template import Context, loader

def my_view(request):
    # View code here...
    t = loader.get_template('myapp/template.html')
    c = Context({'foo': 'bar'})
    r = HttpResponse(t.render(c),
        mimetype="application/xhtml+xml")
redirect
redirect(to, [permanent=False, ]*args, **kwargs)

引数として渡された適切な URL への HttpResponseRedirect を返します。

引数には以下を取れます:

  • モデル: 渡されたモデルの get_absolute_url() 関数が呼ばれます。
  • urlresolvers.reverse() の引数としてリバース解決に使うことができる ビュー名。
  • リダイレクトのロケーションとなる URL

デフォルトでは一時的リダイレクトを発行します。 permanent=True を渡すと永続的なリダイレクトを発行します。

redirect() 関数は複数の方法で使えます。

  1. オブジェクトを渡す; 渡したオブジェクトの get_absolute_url() が呼ばれます:

    def my_view(request):
        ...
        object = MyModel.objects.get(...)
        return redirect(object)
    
  2. ビューの名前を渡す。ポジション引数やキーワード引数を渡すこともできます。 URL は reverse() method:: によって リバース参照されます:

    def my_view(request):
        ...
        return redirect('some-view-name', foo='bar')
    
  3. リダイレクト先の URL をハードコードで渡す:

    def my_view(request):
        ...
        return redirect('/some/url/')
    

    完全な URL でも動作します:

    def my_view(request):
        ...
        return redirect('http://example.com/')
    

デフォルトでは redirect() は一時的リダイレクトを返します。上に書いた 形式のいずれも permanent 引数を取ることができます。 True に セットされ ると永続的なリダイレクトを返します。

def my_view(request):
... object = MyModel.objects.get(...) return redirect(object, permanent=True)
get_object_or_404
get_object_or_404(klass, *args, **kwargs)

指定したモデルマネジャに対して get() を呼出します。ただし、マネジャがモデルの DoesNotExist を送出した場合には、 django.http.Http404 を送出します。

必須の引数
klass
オブジェクトの取得対象である、 Model, Manager または QuerySet インスタンスです。
**kwargs
検索パラメタです。 get()filter() と同じ引数を使えます。
使用例

以下の例では、 MyModel から主キーが 1 のオブジェクトを取得しています:

from django.shortcuts import get_object_or_404

def my_view(request):
    my_object = get_object_or_404(MyModel, pk=1)

この例は、以下の例と等価です:

from django.http import Http404

def my_view(request):
    try:
        my_object = MyModel.objects.get(pk=1)
    except MyModel.DoesNotExist:
        raise Http404

注意: get() と同様、オブジェクトが複数見つかった場合には、 MultipleObjectsReturned 例外が送出されます。

get_list_or_404
get_list_or_404(klass, *args, **kwargs)

指定したモデルマネジャに対して filter() を呼び出した結果を返しま す。戻り値のリストが空なら、 django.http.Http404 を送出します。

必須の引数
klass
オブジェクトの取得対象である、 Model, Manager または QuerySet インスタンスです。
**kwargs
検索パラメタです。 get()filter() と同じ引数を使えます。
使用例

以下の例では、 MyModel から published=True のオブジェクトを全て取得して います:

from django.shortcuts import get_list_or_404

def my_view(request):
    my_objects = get_list_or_404(MyModel, published=True)

この例は、以下の例と等価です:

from django.http import Http404

def my_view(request):
    my_objects = MyModel.objects.filter(published=True)
    if not my_objects:
        raise Http404

汎用ビュー (Generic views)

revision-up-to:17812 (1.4)

汎用ビュー を参照してください。

ミドルウェア

revision-up-to:17812 (1.4)

ミドルウェア (Middleware) とは、 Django のリクエスト/レスポンス処理をフック するためのフレームワークです。ミドルウェアは軽量かつ低水準な「プラグイン」 システムで、Django の入出力を操作します。

各ミドルウェアコンポーネントはそれぞれ特定の機能を担っています。例えば、 Django には XViewMiddleware ミドルウェアコンポーネントがありますが、こ れは全ての HEAD リクエストに対して "X-View" HTTP ヘッダを追加します。

このドキュメントでは、 Django についてくる全てのミドルウェアコンポーネント の使用法と、自分で新たにミドルウェアを作る方法を説明します。 Django には、すぐに使える組み込みのミドルウェアが付属しています。 組み込みミドルウェアガイド を参照してください。

ミドルウェアの有効化

ミドルウェアコンポーネントを有効化するには、Django 設定ファイルの MIDDLEWARE_CLASSES リストにコンポーネントを追加します。コンポー ネント名は文字列で指定し、ミドルウェアのクラス名を完全な Python パスで表し ます。例えば、 django-admin.py startproject が生 成するデフォルトの設定ファイルにある MIDDLEWARE_CLASSES は以下の ようになっています:

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
)

リクエストの処理フェーズでは、Django は MIDDLEWARE_CLASSES に指定された順番で (process_request() および process_view`()) ミドルウェアを適用していきます。レスポンスの処理フェーズでは、 (process_response() および process_exception() ) ミドルウェア が逆順に適用されます。この仕組みは、タマネギの構造になぞらえて、ミドルウェ アクラスを「層」だと考えるとよいでしょう:

Middleware application order.

Django はミドルウェアがなくても動作します – 望むなら MIDDLEWARE_CLASSES は空でもよいのです。とはいえ、少なくとも CommonMiddleware は使うように強く勧めます。

ミドルウェアを自作する

ミドルウェアの自作は簡単です。各ミドルウェアコンポーネントは、以下のメソッ ドを少なくとも一つ定義しているような単一の Python クラスです:

process_request
process_request(self, request)

requestHttpRequest オブジェクトです。このメソッ ドはリクエストごとに Django がどのビューを実行するか決定する前に呼び出されます。

process_request()None または HttpResponse オブジェクトのいずれかを返さねばなりません。 None を返した場合、 Django はリクエストの処理を継続し、他のミドルウェアや適切なビューを実行します。 HttpResponse オブジェクトを返した場合、 Django は他の リクエストミドルウェア、ビューミドルウェア、例外ミドルウェア、あるいは URLconf で設定されたビューを呼び出さず、 HttpResponse オブジェクトをそのまま返します。レスポンスミドルウェアは必ず呼び出されます。

process_view
process_view(self, request, view_func, view_args, view_kwargs)

requestHttpRequest オブジェクトです。 view_func は Django がビュー関数としてこれから呼び出そうとしている Python の関数です、 (実際の関数オブジェクトで、関数名を表す文字列ではありま せん)。 view_args にはビューに渡されることになる固定引数が、 view_kwargs にはビューに渡されることになるキーワード引数の辞書が入って います。 view_args と``view_kwargs`` のいずれにも、ビューの第一引数 (request) は入っていません。

process_view() は Django がビュー関数を呼び出す直前に呼び出されます。こ の関数は None または HttpResponse オブジェクトを 返さねばなりません。 None を返した場合、 Django は処理を継続し、他のミ ドルウェアの process_view() を試した後、適切なビュー関数を呼び出します。 HttpResponse オブジェクトを返した場合、 Django は他の リクエストミドルウェア、ビューミドルウェア、例外ミドルウェア、あるいは URLconf で設定されたビューを呼び出さず、 HttpResponse オブジェクトをそのまま返します。レスポンスミドルウェアは必ず呼び出されます。

Note

process_request や``process_view`` からミドルウェアの中の request.POSTrequest.REQUEST にアクセスするとそのミドルウェアの後で実行される任意のビューが リクエストのアップロードハンドラーを動的に変更する ことができなくなるので避けるべきです。

CsrfViewMiddleware クラスは例外と 考えることができます。 csrf_exempt() デコレータと csrf_protect() デコレータでは ビューはCSRF検証が行われる時点で明示的に制御することができるからです。

process_template_response
リリースノートを参照してください
process_template_response(self, request, response)

requestHttpRequest クラスのオブジェクトです。 responseSimpleTemplateResponse クラスのサブクラス (例えば TemplateResponse) 、あるいは render メソッドを実装する任意の response オブジェクトです。

process_template_response()render メソッドを実装する response オブジェクト返さなければいけません。 与えられた responseresponse.template_nameresponse.context_data を変更することができますが、 全くあたらしい SimpleTemplateResponse か同等のものを 作成することも可能です。

process_template_response() は response インスタンスが render() メソッド を持っている時、つまりそのresponse が TemplateResponse クラス、あるいは同等のクラス であるのみ呼び出されます。

明示的にresponseをレンダする必要はありません。 – 全てのテンプレート応答ミドルウェア が呼び出された時に1度だけ自動的にresponseがレンダされます。

応答フェーズの間、ミドルウェアは逆順で実行されます。 process_template_response もそれに含まれます。

process_response
process_response(self, request, response)

requestHttpRequest オブジェクトです。 response は Django のビュー関数の返す HttpResponse オブジェクトです。

process_response()HttpResponse オブジェクトを 返さねばなりません。渡された response オブジェクトを変更して返しても良いですし、 新たに HttpResponse オブジェクトを生成して返すことも可能です。

process_request()process_view() メソッドとは異なって、 process_response() メソッドは必ず呼ばれます。 同じミドルウェアクラスの process_request()process_view() メソッド がスキップされても呼ばれます。これより先に呼ばれるミドルウェアメソッドが httpresponse クラスを返していたからです(つまり、例えば process_response() メソッドは process_request() でセットアップが 完了していることを前提としてはいけない、ということです。) さらに、レスポンスフェーズの間はクラスは逆順、つまり下から上に適用されます。 これは MIDDLEWARE_CLASSES の最後に定義されたクラスが最初に 実行されるという意味です。

process_exception
process_exception(self, request, exception)

requestHttpRequest オブジェクトです。 exception はビュー関数の送出した Exception オブジェクトです。

Django はビューが例外を送出した際に process_exception() を呼び出します。 process_exception()None または HttpResponse オブジェクトのいずれかを返さねばなりませ ん。 HttpResponse オブジェクトを返した場合、その応答 をそのままブラウザに返します。それ以外の場合、デフォルトの例外処理を起動し ます。

ここでも応答フェーズの間はミドルウエアは逆順で実行されます。 process_exception もそれに含まれます。 もしも例外ミドルウェアが応答を返すのであれば、 そのミドルウェアより上位にあるミドルウェアクラスは決して呼ばれることはありません。

__init__

ほとんどのミドルウェアクラスは、実質的に単なる process_* メソッドの置き 場でしかないので、初期化メソッドは必要ありません。ミドルウェアのグローバル な状態を保存するのに __init__ メソッドを使ってもかまいませんが、以下の 点に注意してください:

  • Django はミドルウェアクラスを引数なしで初期化するので、 __init__ には必須の引数を定義できません。
  • process_* メソッドはリクエストごとに呼び出されますが、 __init__ は Web サーバの起動時に 一度 しか呼び出されません。
ミドルウェアを動的に有効にする

ミドルウェアを使うかどうかを実行時に決められると便利なことがあります。ミド ルウェアの __init__ メソッドで django.core.exceptions.MiddlewareNotUsed を送出すると、 Django はそ のミドルウェアを処理から外します。

ガイドライン
  • ミドルウェアのクラスはサブクラスでなくてもかまいません。
  • ミドルウェアのクラスはPython のモジュールパス上のどこにでも置けます。 Django にとって必要なのは MIDDLEWARE_CLASSES にクラスへの パスが指定されていることだけです。
  • Django で使えるミドルウェア を参考にしてく ださい。
  • 自分の書いたミドルウェアコンポーネントが他の人にとっても有用だと思っ たなら、ぜひ コミュニティにコントリビュート してください!知らせてくだされば、 Django に追加するか検討します。

セッションの使い方

revision-up-to:17812 (1.4)

Django は匿名セッション (anonymous session) を完全にサポートしています。 セッションフレームワークを使うと、任意のデータをサイト訪問者単位 (per-site-visitor) で保存したり取得したりできます。セッションフレームワーク はサーバ側にデータを保存し、クッキーの送受信操作を抽象化します。クッキーに はセッション ID だけが保存され、データ自体は送受信されません。 ( クッキーベースのバックエンド を使うことなしには)

セッションを有効にする

セッション機能は ミドルウェア として実装されていま す。

セッションを有効にするには、以下の作業が必要です:

  • MIDDLEWARE_CLASSES を編集して、 'django.contrib.sessions.middleware.SessionMiddleware' を入れます。 django-admiin.py startproject の作成するデフォルトの settings.py では SessionMiddleware が有効になっています。

セッション機能を必要としないのなら、 MIDDLEWARE_CLASSES から SessionMiddleware の行を削り、 INSTALLED_APPS からも 'django.contrib.sessions' を削って下さい。セッションを無効にすると、ほんのわずかだけオーバヘッド を軽減できます。

セッションエンジンの設定

デフォルトでは、 Django はセッションをデータベースに (django.contrib.sessions.models.Session モデルを使って) 保存します。こ の仕様は便利ではありますが、場合によっては、データベース以外の場所、ファイ ルシステムやキャッシュ上にセッションデータを保存する方が高速です。

データベースバックエンドセッションを使う

もし、データベースバックエンドセッション(database-backend session)を使いたけれ ば、 INSTALLED_APPS セッティングに 'django.contrib.sessions' を 加える必要があります。

一度、 Django の manage.py syncdb を走らせて、データベースを構成している と、テーブルが一つセッションデータを保存するために使われています。

キャッシュベースのセッション

パフォーマンスを求めるなら、キャッシュベースのセッションバックエンドを使う のがよいでしょう。

Django のキャッシュシステムにセッションデータを保存するには、まずキャッシュ を設定しておく必要があります。詳しくは キャッシュのドキュメント を参照してください。

Warning

Memcached をキャッシュバックエンドとして使っているなら、キャッシュベー スのセッションを使うべきです。ローカルメモリ型のキャッシュバックエンド は十分な時間データを保持できないので、よい選択肢とはいえません。また、 ファイルやデータベースによるキャッシュバックエンドを使っている場合、何 もかもをキャッシュに放り込むより、直接ファイルやデータベースからデータ を出力する方がはるかに高速です。

一度キャッシュが設定されていれば、キャッシュにデータを保存する二つの方法が 選べます。

  • SESSION_ENGINE"django.contrib.sessions.backends.cache" に、設定すると、シンプルにセッションの保存がキャッシングできます。セッション データは、直接キャッシュの中に保存されます。しかし、セッションデータは 永続的ではありません。キャッシュされたデータはキャッシュが一杯になるか、 キャッシュサーバーが再起動された時に消去されてしまいます。
  • キャッシュのデータを永続的にするために、 SESSION_ENGINE"django.contrib.sessions.backends.cached_db" に設定してください。 これは、ライトスルーキャッシュを用います(write-through cache)。 全ての書き込みがキャッシュへといき、またデータベースにも書き込まれます。 セッションは、キャッシュの中にデータが準備されていなければ、データベース しか読みません。

両方のセッションの保存はどちらも十分に高速ですが、シンプルキャッシュは 永続性を放棄した結果、より早くなっています。ほとんどのケースで、 cached_db バックエンドも必要な程度の早さを発揮しますが、少しでも早さを求めるなら、 そしてセッションデータが時とともに消去されていくのをよしとするなら、 cache バックエンドが適しているケースでしょう。

ファイルベースのセッション

ファイルベースのセッションを使うには、 SESSION_ENGINE 設定を "django.contrib.sessions.backends.file" にします。

また、必要に応じて SESSION_FILE_PATH も設定してください (デフォルト値は tempfile.gettempdir() の戻り値で、たいていは /tmp です)。 Web サーバが SESSION_FILE_PATH の場所にファイルの読書き権限を持っているか 確かめてください。

クッキーベースバックエンドセッションを使う
リリースノートを参照してください

クッキーベースセッションを使うには、 SESSION_ENGINE"django.contrib.sessions.backends.signed_cookies" に設定します。 セッションデータは、 cryptographic signingSECRET_KEY 設定へと Django ツールを使って保存されます。

Note

SESSION_COOKIE_HTTPONLY 設定を True にすると、 JavaScript から、保存されたデータを改ざんすることを妨げることが できるのでお勧めしています。

Warning

セッションデータは認証されていますが、暗号化されていません

クッキーバックエンドを使うと、セッションデータはクライアントから 読むことが出来ます。

MAC ( Message Authentication Code )は、クライアントからのデータの変更から データを守るのに使われます、つまりセッションデータは改ざんされる時に無効 化されるということです。同じような無効化は、クライアントが保存している クッキー(すなわち、ユーザのブラウザが保存しているもの)が、全て保存されない 場合と、データが欠落してしまった場合に起こります。 Django はデータを 圧縮していますが、それは common limit of 4096 bytes を超過しています。

最新である保証がない

MAC がデータの信頼性と(これはあなたのサイトが生成します) データの一貫性(全てがそこにあり、全てが正しいかどうか)を保証する一方、 MAC はデータの最新性を保証しません。すなわち、クライアントに送信した 最後のものが、返ってきているということです。これは、セッションデータが いくつか用いていることを意味します。クッキーバックエンドは 反射攻撃 に耐えて開くだろうということです。 SESSION_COOKIE_AGE よりもクッキーが古い場合、クッキーは ‘stale’ としてのみ検出されます。

パフォーマンス

最後に、大容量のクッキーは、 サイトのスピード に影響を与えます。

ビュー中でセッションを扱う

SessionMiddleware を有効にすると、各々の HttpRequest オブジェクト(Django ビュー関数の最初の引数) は辞書ライクオブジェクトの属性 session を持つようになります。 この属性は読み書き可能です。

ビューのどの部分でも request.session で読み書き可能です 複数回の編集・変更が可能です。

class backends.base.SessionBase

これは、全てのセッションオブジェクトのベースクラス(基底クラス)です。 通常のディクショナリのメソッドをサポートしています。

__getitem__(key)

例: fav_color = request.session['fav_color']

__setitem__(key, value)

例: request.session['fav_color'] = 'blue'

__delitem__(key)

例: del request.session['fav_color'] セッションデータ中に key に対応する値がない場合には KeyError を送出します。

__contains__(key)

例: 'fav_color' in request.session

get(key, default=None)

例: fav_color = request.session.get('fav_color', 'red')

pop(key)

例: fav_color = request.session.pop('fav_color')

keys()
setdefault()
clear()

これは、三つのメソッドを持っています:

flush()

現在のセッションデータをデータベースから削除し、後でクッキーに入れて ユーザに送り返すために新たなセッションキーを生成します。ユーザの使っ ているブラウザに、以前のセッションデータにアクセスさせたくない場合に 使います (例えば django.contrib.auth.logout() で呼び出されま す)。

テストクッキーを設定して、ユーザのブラウザがクッキーをサポートしてい るかどうかを調べられるようにします。クッキーの動作仕様上、次にブラウ ザがリクエストを送信してくるまでテストは行えません。詳しくは後述の 「 テストクッキーを設定する 」を参照してください。

ユーザのブラウザがテストクッキーを受け入れたかどうかに応じて True または False を返します。クッキーの動作仕様上、あらかじめ別のペー ジリクエストで set_test_cookie() を呼び出しておかねばなりません。 後述の「 テストクッキーを設定する 」を参照してください。

テストクッキーを削除します。後始末に使って下さい。

set_expriry(value)

セッションの有効期限をセットします。渡せる値には、以下のバリエーションが あります:

  • value に整数を渡すと、セッションがアクティブでないまま value 秒間経った時点で有効期限が切れます。例えば、 request.session.set_expiry(300) とすると、セッションの有 効期限は 5 分で切れます。
  • valuedatetimetimedelta オブジェクトを渡す と、セッションの有効期限は指定日・時刻に切れます。
  • value0 を渡すと、ユーザセッションクッキーの有効期 限は、ブラウザを閉じた時点で切れます。
  • valueNone を渡すと、セッションの有効期限はグロー バルに設定されているセッションポリシーに戻されます。

セッションの読み込みはアクションの目的が満たされているかは考慮しません。 セッションの満了は、セッションが最後に 変更された かをもとに計算されて います。

get_expiry_age()

セッションの有効期限が切れるまでの秒数を返します。セッションの有効期 限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限 としている場合) は、 settings.SESSION_COOKIE_AGE と等しい値です。

get_expiry_date()

セッションの有効期限が切れるまでの日数を返します。セッションの有効期 限をカスタマイズしていない場合 (またはブラウザを閉じるまでを有効期限 としている場合) は、 SESSION_COOKIE_AGE 秒に相当する日数 です。

get_expire_at_browser_close()

ユーザのセッションクッキーの有効期限がブラウザを閉じるまでに設定され ていれば True を、そうでなければ False を返します。

セッションオブジェクト使用上のガイドライン
  • request.session のキーには通常の Python 文字列を使って下さい。と はいえ、これは厳格な掟 (hard-and-fast rule) ではなく単なる規約です。
  • アンダースコアで始まるセッション辞書のキーは Django の内部使用のため に予約されています。
  • request.session を新たなオブジェクトでオーバライドしたり、属性を いじってはなりません。Python 辞書型のように扱って下さい。
使用例

以下の簡単なビューの例では、ユーザがコメントをポストした後に has_commented という変数を True に設定しています。これにより、一人 のユーザに一つのコメントを何度もポストさせないようにします:

def post_comment(request, new_comment):
    if request.session.get('has_commented', False):
        return HttpResponse("You've already commented.")
    c = comments.Comment(comment=new_comment)
    c.save()
    request.session['has_commented'] = True
    return HttpResponse('Thanks for your comment!')

以下のビューでは、「メンバ」をサイトにログインさせます:

def login(request):
    m = Member.objects.get(username__exact=request.POST['username'])
    if m.password == request.POST['password']:
        request.session['member_id'] = m.id
        return HttpResponse("You're logged in.")
    else:
        return HttpResponse("Your username and password didn't match.")

そして下の例では、上の例で login() したメンバをログアウトさせます:

def logout(request):
    try:
        del request.session['member_id']
    except KeyError:
        pass
    return HttpResponse("You're logged out.")

実際には、標準の django.contrib.auth.logout() は、うっかりデータが漏洩 してしまうのを防ぐために、 request.sessionflush() を呼び出しています。 上の例はセッションオブジェクトの仕組みを説明するためのもので、完全な logout() の実装ではありません。

テストクッキーを設定する

利便性のために、 Django ではユーザのブラウザがクッキーを受け入れるかどうか を調べるための簡単な方法を提供しています。ビュー内で request.sessionset_test_cookie() を呼び出しておき、 それ以後のビュー、すなわち別のビュー呼び出しで test_cookie_worked()`() を呼び出すようにしてください。

set_test_cookie()test_cookie_worked() が別々のビュー呼び出しに 分離されるのは不恰好ですが、これはクッキーの動作上仕方のないことです。ある ブラウザに対して一度クッキーを設定しても、そのブラウザが次にリクエストを送 信するまではクッキーを受け入れたかどうかを確かめる術はないのです。

テストが終わったら、 delete_test_cookie() を呼び出して後始末をしておくのがよいでしょう。

クッキーの動作テストが終わった時点で、この関数を呼び出して下さい。

典型的な使用例を以下に示します:

def login(request):
    if request.method == 'POST':
        if request.session.test_cookie_worked():
            request.session.delete_test_cookie()
            return HttpResponse("You're logged in.")
        else:
            return HttpResponse("Please enable cookies and try again.")
    request.session.set_test_cookie()
    return render_to_response('foo/login_form.html')
ビューの外でセッションを使う

API を使うと、ビューの外からセッションデータを操作できます:

>>> from django.contrib.sessions.backends.db import SessionStore
>>> import datetime
>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')
>>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10)
>>> s['last_login']
datetime.datetime(2005, 8, 20, 13, 35, 0)
>>> s.save()

もし、 session_key が与えられていなければ、自動で生成されます。:

>>> from django.contrib.sessions.backends.db import SessionStore
>>> s = SessionStore()
>>> s.save()
>>> s.session_key
'2b1189a188b44ad18c35e113ac6ceead'

django.contrib.sessions.backends.db バックエンドを使っている場合、各セッ ションは Django のモデルインスタンスで表現されています。 Session モデル は django/contrib/session/models.py で定義されています。 Session は 通常のモデルなので、通常の Django データベース API でアクセスできます:

>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
>>> s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)

セッション情報の辞書を取得するには get_decoded() を呼び出す必要があるの で注意して下さい。というのも、セッション情報はエンコードされた形式で保存さ れているからです。

>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}
セッションはいつ保存されるのか

デフォルトでは、 Django はセッション情報が変更された場合、すなわちセッショ ン情報の入った辞書に値を代入したり、値を削除した場合にのみ、セッションデー タベースを保存します:

# セッションデータは変更されたものとみなされます
request.session['foo'] = 'bar'

# セッションデータは変更されたものとみなされます
del request.session['foo']

# セッションデータは変更されたものとみなされます
request.session['foo'] = {}

# 落とし穴: request.session ではなく request.session['foo'] の変更なの
# で、セッションデータは変更されたものとみなされません。
request.session['foo']['bar'] = 'baz'

上の例の最後のケースでは、セッションオブジェクトに内容が変更されたことを明 示的に教えねばなりません。変更の通知は modified 属性で行います:

request.session.modified = True

この振舞いを変更したければ、 SESSION_SAVE_EVERY_REQUEST 設定を True に設定してください。 SESSION_SAVE_EVERY_REQUESTTrue にすると、 Django はリクエスト一つ一つに対してセッションを保存します。

セッションクッキーはセッションが作成されたり変更されたりした場合にのみ送信 されることに注意してください。 SESSION_SAVE_EVERY_REQUESTTrue にすると、リクエストごとに必ずセッションクッキーを送信するようになります。

同様に、セッションクッキーの expires 部分もセッションクッキーの送信ごと に更新されます。

ブラウザアクセス単位のセッションと永続的セッション

SESSION_EXPIRE_AT_BROWSER_CLOSE 設定を使うと、セッションフレームワーク に、ブラウザアクセス単位のセッションと永続的セッションのどちらを使わせるか を指定できます。

デフォルトでは、 SESSION_EXPIRE_AT_BROWSER_CLOSEFalse に設定さ れています。これはセッションクッキーが SESSION_COOKIE_AGE の間だけブラ ウザに保存されることを示します。ユーザがブラウザを起動するたびにログインし なくてもすむようにしたければ、この設定を使ってください。

SESSION_EXPIRE_AT_BROWSER_CLOSETrue にすると、 Django はブラウ ザアクセス単位のクッキー、すなわちユーザがブラウザを閉じると有効期限が切れ るようなクッキーを使うようになります。ブラウザを起動するたびにユーザにログ イン操作を行わせたい場合、この設定を使ってください。

この設定は、グローバルに有効なデフォルト値です。 request.session のメソッドである「 ビューの外でセッションを使う 」の節で解説した、 set_expiry()`() を使えば、セッション単位で有効期限をオーバ ライドできます。

セッションテーブルの消去

セッションデータは django_session データベーステーブル上に蓄積されます が、 Django はセッションテーブルを自動的に清掃 しません。 つまり、期限切 れの (expired) セッションデータを正しい判断基準の下に削除するのは、アプリケー ション開発者であるあなた自身の仕事なのです。

この問題を理解するには、ユーザがセッションを使ったときに何が起きているかを 考える必要があります。ユーザがログインすると、 Django は django_session データベーステーブルにレコードを 1 行追加します。セッションデータが変更され る度に、このレコード行は更新されてゆきます。ユーザが手動でログアウトすれば、 レコード行は削除されますが、ユーザがログアウト操作を しなかった場合 には、 レコード行は削除されません。

Django は、クリーンアップ用のアクション、 django-admin.py cleanup を提 供しています。このスクリプトはセッションテーブルの全てのエントリの中から、 expire_date の値が過去を指しているものを除去します。もちろん、お使いの アプリケーションが要求する仕様が異なる場合には、別のスクリプトを用意する必 要があるでしょう。

設定

Django 設定ファイル には、セッションの振舞いを操作す るための設定がいくつかあります:

SESSION_ENGINE

デフォルト値: django.contrib.sessions.backends.db

Django がセッションデータを保存する方法を指定します。利用できる値は以下の通 りです:

  • 'django.contrib.sessions.backends.db'
  • 'django.contrib.sessions.backends.file'
  • 'django.contrib.sessions.backends.cache'
  • 'django.contrib.sessions.backends.cached_db'
  • 'django.contrib.sessions.backends.signed_cookies'

詳しくは セッションエンジンの設定 を参照してください。

SESSION_FILE_PATH

デフォルト値: /tmp/

ファイルベースのセッションストレージを使っている場合、この値でセッションデー タの保存場所を指定します。

SESSION_EXPIRE_AT_BROWSER_CLOSE

Default: False

ブラウザを閉じたときにセッションを期限切れにするかどうかを決めます。

SESSION_SAVE_EVERY_REQUEST

デフォルト値: False

リクエストごとにセッションデータを保存するかどうかを決めます。この値が False (デフォルト) の場合、セッションデータの保存は内容が変更された場合、 すなわちセッションデータ辞書に値を設定したり、値を削除したりした場合だけに なります。

技術的な詳細
  • セッション辞書には pickle 化可能な全てのオブジェクトを使えます。詳し くは pickle モジュール を参照してください。
  • セッション情報は django_session という名前のデータベーステーブルに 保存されます。
  • Django は必要なときにしかクッキーを送信しません。従って、セッション情 報を設定しない限り、セッションクッキーの送信を行いません。
URL と Session ID

Django のセッションフレームワークは完全なクッキーベースであり、クッキー以外 の情報を扱いません。従って、 PHP のように URL にセッション ID を入れる方法 を最後の手段に残したりはしていません。これは設計上の意図的な決定です。とい うのも、URL にセッション ID を含めると、みっともない URL になるだけでなく、 “Referer” ヘッダを使ってセッション ID を盗まれるという脆弱性を招くからです。

フォームの操作

revision-up-to:17812 (1.4)

このドキュメントについて

このドキュメントでは、 Django のフォーム処理機能を紹介しています。 フォーム API の特定のフィールドに関する詳細は、 フォーム APIフォームフィールドフォームやフィールドのバリデーション を参照してくだ さい。

django.forms は、 Django のフォーム処理ライブラリです。

フォームによって提出 (submit) されたデータの処理は、Django の HttpRequest クラスだけでも実現できます。しかし、フォー ムライブラリを使うと、フォーム処理に必要な共通のタスクの面倒を見てくれます。 フォームライブラリを使えば、以下のようなことを実現できます:

  1. フォームウィジェットから、 HTML フォームを自動的に生成して表示できます。
  2. 提出されたデータに対して、バリデーション規則 (validation rule) を適用できま す。
  3. バリデーションエラーを検出したときに、フォームをエラーメッセージ付きで表示で きます。
  4. 提出されたデータを、適切な Python のデータ型に変換できます。

概要

このライブラリでは、以下のような概念を扱います:

ウィジェット (Widget)
<input type="text"><textarea> のような、 HTML フォーム ウィジェットに対応するクラスです。ウィジェットから HTML へのレンダ リングもこのクラスで行われます。
フィールド (Field)
データの検証を行うためのクラスです。例えば、 EmailField はデー タが有効な電子メールアドレスかどうか検証します。
フォーム (Form)
フィールドの集まりで、データの検証や HTML への表示方法が実装された ものです。
フォームメディア (Form Media)
フォームをレンダするときに必要な CSS や JavaScript リソースの定義です。

このライブラリは、データベースレイヤやビュー、テンプレートといった他の Django コンポーネントに対してカップリングしていません。このライブラリが依存 しているのは settings と django.utils の二つのヘルパ関数、そして国際化 のためのフックだけです (ただし、このライブラリを使うために国際化の機能を使 わねばならないわけではありません) 。

フォームオブジェクト

フォームオブジェクトは、フォームに含める一連のフィールドや、フォームに入力 した値を受理するために充足しなければならないバリデーション規則をカプセル化 します。フォームクラスは、 django.newforms.Form クラスをサブクラス化し、 Django のデータベースモデルによく似た方法でフォームのフィールドを定義して作 成します。

一例として、個人のウェブサイトでコンタクトフォームの機能を実装するときに使 うフォームを考えてみましょう:

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField()
    sender = forms.EmailField()
    cc_myself = forms.BooleanField(required=False)

フォームは Field オブジェクトの組み合わせでできています。今回の例では、 subject (題名)、 message (メッセージ)、 sender (送信者)、そして cc_myself (自分に CC する)、の 4 つのフィールドをフォームに持たせます。 CharFieldEmailField, BooleanField はフィールド型です。 フィールド型の一覧は フォームフィールド を参照してください。

ModelForm を使えば、フォームを使って Django のモデルを直接追加したり編集したりしたいときに、モデルと重複する記述 をせずにすみます。

ビュー内でフォームを使う

フォームをビュー内で処理するときの標準的なパターンを以下に示します:

def contact(request):
    if request.method == 'POST': # フォームが提出された
        form = ContactForm(request.POST) # POST データの束縛フォーム
        if form.is_valid(): # バリデーションを通った
            # form.cleaned_data を処理
            # ...
            return HttpResponseRedirect('/thanks/') # POST 後のリダイレクト
    else:
        form = ContactForm() # 非束縛フォーム

    return render_to_response('contact.html', {
        'form': form,
    })

このパターンには、 3 つのコードパスがあります:

  1. フォームデータが提出されていなければ、非束縛の ContactForm イン スタンスを生成して、テンプレートに渡します。
  2. フォームデータが提出されていれば、 request.POST を使って束縛フォー ムを生成します。入力データのバリデーションに成功したら、フォームデー タを処理して、ユーザを「ありがとう」ページにリダイレクトします。
  3. フォームデータが提出され、バリデーションに成功しなければ、束縛フォー ムインスタンスをテンプレートに渡します。

束縛 フォームと 非束縛 フォームの違いはとても重要です。非束縛フォー ムには、何らデータが結び付いていません。非束縛フォームをレンダしてユーザに 呈示すると、フォームには空の値かデフォルトの値が表示されます。束縛フォーム にはユーザから提出されたデータが入るので、そのデータが有効であるかどうか調 べられます。入力データが無効な束縛フォームをレンダすると、入力データの何が おかしいのかを示すエラーメッセージが各行に出力されます。

束縛フォームと非束縛フォームの違いについてもっと詳しく知りたければ、 束縛フォームと非束縛フォーム を参照してください。

フォームからアップロードされたファイルを扱う

フォームからアップロードされたファイルを扱う方法は アップロードされたファイルをフォームに結びつける に詳しく書いてあります。

フォームから入力されたデータを処理する

フォームの is_valid()True を返すなら、入力データはフォームに設 定しておいたバリデーション条件を満たしているので、提出されたフォームを安全 に処理できます。この時点でも、 request.POST には直接アクセスできますが、 form.cleaned_data にアクセスする方がよいでしょう。 form.cleaned_data 内のデータはバリデーション済みであるだけでなく、適切 な Python の型に変換されているからです。上の例では、 cc_myself はブール 型の値に変換されています。同様に、 IntegerFieldFloatField は、 それぞれ Python の整数型や浮動小数型の値に変換されています。 読み込み専用のフィールドは入力要素としてでなく、むしろテキストとして表示さ れ、かつそれらはサーバにポストで戻されることがないため、それらのフィールド は、 form.cleaned_data で利用できないということに注意してください ( また カスタマイズした celan() 関数で設定した値は何も影響を与えないでしょう) 。

上の例を拡張すると、フォームデータの処理は以下のように書けます:

if form.is_valid():
    subject = form.cleaned_data['subject']
    message = form.cleaned_data['message']
    sender = form.cleaned_data['sender']
    cc_myself = form.cleaned_data['cc_myself']

    recipients = ['info@example.com']
    if cc_myself:
        recipients.append(sender)

    from django.core.mail import send_mail
    send_mail(subject, message, sender, recipients)
    return HttpResponseRedirect('/thanks/') # Redirect after POST

この例ではメールを送信しています。Django からメールを送信する方法の詳細は メールの送信 を参照してください。

テンプレートを使ってフォームを表示する

フォームは Django のテンプレート言語を使うように設計されています。上の例で は、コンテキスト変数 form を使ってテンプレートに ContactForm インス タンスを渡しています。簡単なテンプレートの例を示します:

<form action="/contact/" method="POST">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>

フォームインスタンスはフィールドのマークアップだけを出力します。前後の <form> タグや、 submit ボタンは自分で追加します。

フォームとクロスサイトリクエストフォージェリ対策

Djangoは使いやすい クロスサイトリクエストフォージェリ対策 を搭載してます. 前述した例のように、 CSRF 保護機能を有 効にした POST を経由して送信するとき、テンプレートタグの csrf_token を使うべきです。しかしながら、 CSRF 保護はテンプレート内のフォームに直接紐づ いていないため、このタグは、このドキュメント内の以下の例では、省略されてい ます。

form.as_p を参照すると、各フィールドとラベルをパラグラフ (<p>) タグ で囲って出力します。上のテンプレートの例を出力すると、以下のようになります:

<form action="/contact/" method="post">
<p><label for="id_subject">Subject:</label>
    <input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message">Message:</label>
    <input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label>
    <input type="text" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label>
    <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
<input type="submit" value="Submit" />
</form>

各フォームフィールドには、 id_<field-name> の形式で id 属性が付加されて おり、すぐそばのラベルで参照されています。これは、画面読み上げソフトウェア のような入出力補助技術でフォームを扱うために重要な仕組みです。 ラベルや idの出力方法はカスタマイズできます

form.as_table を使うと、各フィールドがテーブルの各行になるように出力で きます (自分で <table> タグで囲む必要があります)。また、 form.as_ul を使えば、リストとして出力できます。

フォームテンプレートのカスタマイズ

デフォルトの HTML 出力が気に入らなければ、 Django のテンプレート言語を使っ て、フォームの表示方法をいくらでもカスタマイズできます。例えば、前掲の例は 以下のように拡張できます:

<form action="/contact/" method="post">
    {{ form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.subject.errors }}
        <label for="id_subject">Email subject:</label>
        {{ form.subject }}
    </div>
    <div class="fieldWrapper">
        {{ form.message.errors }}
        <label for="id_message">Your message:</label>
        {{ form.message }}
    </div>
    <div class="fieldWrapper">
        {{ form.sender.errors }}
        <label for="id_sender">Your email address:</label>
        {{ form.sender }}
    </div>
    <div class="fieldWrapper">
        {{ form.cc_myself.errors }}
        <label for="id_cc_myself">CC yourself?</label>
        {{ form.cc_myself }}
    </div>
    <p><input type="submit" value="Send message" /></p>
</form>

各フォームフィールドは、その名前に従って、 {{ form.name_of_field }} で出力でき、フォームウィジェットを表示するための適切な HTML を生成します。 {{ form.name_of_field.errors }} はフォームエラーのリストを以下のような 無番号リストで表示します:

<ul class="errorlist">
    <li>Sender is required.</li>
</ul>

リストには errorlist という CSS があてられていて、表示スタイルを変更で きます。エラーの表示方法をもっと細かく制御したければ、ループを使って以下の ように表現できます:

{% if form.subject.errors %}
    <ol>
    {% for error in form.message.errors %}
        <li><strong>{{ error|escape }}</strong></li>
    {% endfor %}
    </ol>
{% endif %}
フォームフィールドのループ

もしそれぞれのフォームフィルドで同じ HTML を利用するなら、順次それぞれのフィ ールドを繰り替えす {% for %} ループを利用することで、重複するコードを減ら すことができます:

<form action="/contact/" method="post">
    {% for field in form %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }}: {{ field }}
        </div>
    {% endfor %}
    <p><input type="submit" value="Send message" /></p>
</form>

このループの {{ field }} は、 BoundField のインスタンスです。 BoundField は以下の属性も持ち、テンプレート内で利用することができま す。

{{ field.label }}
フィールドのラベルです。例 Email address
{{ field.label_tag }}
フィールドの label をHTML の <label> タグに適した形式にラッピング します。例 <label for="id_email">Email address</label>
{{ field.value }}
フィールドの値です。例 someone@example.com
{{ field.help_text }}
フィールドに関連付けられている任意のヘルプテキストです。
{{ field.errors }}
このフィールドに一致する複数のバリデーションエラーを含んでいる <ul class="errorlist"> が表示されます。 {% for error in field.errors %} ループを利用してエラーの表示をカス タマイズすることができます。この場合、ループ内の各オブジェクトは、エラ ーメッセージを含んでいる単純な文字列です。
field.is_hidden

フォームフィールドが非表示フィールドの場合、この属性は True とな り、そうでなければ、 False になります。テンプレートの変数としては、 特に便利でありませんが、以下に示すような条件文のテストには役立つでし ょう。:

{% if field.is_hidden %}
   {# Do something special #}
{% endif %}
非表示と表示フィールドのループ

もしテンプレート内で、フォームを手動で表示しているなら、 つまり Django のデフ ォルトフォームレイアウトに反対するとき、非表示ではないフィールドより <input type="hidden"> フィールドは注意深くを処理するべきです。 例えば、非表示フィールドは何も表示しないので、エラーメッセージをそのフィールド の横に表示した場合、ユーザの混乱の原因になるでしょう。よって、それらの非表示フ ィールドのエラーに対しては、別の手段で対処するべきです。

Django は非表示、表示フィールドに対して、ループを可能にするフォームに、 hidden_fields()visible_fields() という独立した2つのメソッドを規定 しています。上記の例に対して、これら2つのメソッドを使った場合の、変更点は以下 のとおりである。:

<form action="/contact/" method="post">
    {# Include the hidden fields #}
    {% for hidden in form.hidden_fields %}
    {{ hidden }}
    {% endfor %}
    {# Include the visible fields #}
    {% for field in form.visible_fields %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }}: {{ field }}
        </div>
    {% endfor %}
    <p><input type="submit" value="Send message" /></p>
</form>

この例では、非表示フィールドに対してのエラーは処理されません。たいていの場合、 非表示フィールドのエラーは、フォームの改ざんを表します。なぜなら、普通のフォー ムのインタラクションを、非表示フィールドに変更すべきではないからある。しかしな がら、フォームのエラーに対応するエラー表示を簡単に挿し込むこともできるでしょう。

hidden_fieldsvisible_fields メソッドは Django 1.1 で新しく 追加されました。
フォームテンプレートの再利用

複数の場所で同じ描画ロジックのフォームを利用するなら、独立したテンプレートにフォ ームのループと include タグを保存し、それを他のテンプレート内で再利用す ることで、重複を減らすことができます:

<form action="/contact/" method="post">
    {% include "form_snippet.html" %}
    <p><input type="submit" value="Send message" /></p>
</form>

# In form_snippet.html:

{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }}: {{ field }}
    </div>
{% endfor %}

もしテンプレートに渡されたフォームオブジェクトが、コンテキスト内で異なった名前 を持っているなら、 include タグの引数に with を利用することでそれを 別名にすることができます:

<form action="/comments/add/" method="post">
    {% include "form_snippet.html" with form=comment_form %}
    <p><input type="submit" value="Submit comment" /></p>
</form>

もし、頻繁にこのようなことをするなら、 inclusion tag をカスタマイズ することを検討すべきです。

その他のトピック

ここではフォームの基本を説明しましたが、フォームライブラリのできることはもっ とたくさんあります:

フォームセット (formsets)
revision-up-to:17812 (1.4)

フォームセットとは、同じページで複数のフォームを扱うための抽象化レイヤで、 いわばデータグリッドのようなものです。フォームセットを説明するために、まず 以下のようなフォームを考えましょう:

>>> from django import forms
>>> class ArticleForm(forms.Form):
...     title = forms.CharField()
...     pub_date = forms.DateField()

このフォームを使って、ユーザが一度に複数の記事を作成できるようにしたい場合 があったとします。そのために、 ArticleForm からフォームセットを生成しま す:

>>> from django.forms.formsets import formset_factory
>>> ArticleFormSet = formset_factory(ArticleForm)

ArticleFormSet という名前のフォームセットクラスができました。このフォー ムセットには、フォームセットに入っているフォームを一つ一つ取り出して、それ ぞれを普通のフォームとして表示する機能があります:

>>> formset = ArticleFormSet()
>>> for form in formset:
...     print form.as_table()
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>

出力を見て分かる通り、空のフォームが一つだけ表示されています。 今表示されている空っぽのフォームの合計は、 extra パラメータ によってコントロールされます。 formset_factory のデフォルトの設定で、「追加のフォーム表示数 (extra)」 を 1 に設定しているからです。二つの空っぽのフォームを出す例は:

>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
リリースノートを参照してください

Django 1.3 で重要視されるのは、 フォームセットのインスタンスがイテレート (iterate)できないということです。フォームセットの表示をするために、 forms アトリビュート(attribute)をイテレートします。:

>>> formset = ArticleFormSet()
>>> for form in formset.forms:
...    print form.as_table()

formset.forms をイテレートすることは、フォームが作成された順番で フォームを並べるのと同じことです。通常、フォームセットのイテレータは この順番でフォームを表示します、しかしこの順番を __iter__() メソッドを使って別の順番へと変更することができます。

フォームセットは、インデックスを入れこむこともできます。フォームセットは 組み込まれたフォームを返します。もし、 __iter__ を上書きしたならば、 __getitem__ も、フォームとのマッチングのために上書きする必要があります。

フォームセットに初期データを指定する

初期データは、フォームセットのユーザビリティに影響する大きな要素です。上に 示したように、 formset_factory には追加のフォーム表示数を指定できます。 この「追加」とは、初期データを渡したときに表示されるフォームの中で、追加で 表示されている空のフォーム数という意味です。以下の例をよく見てください:

>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
>>> formset = ArticleFormSet(initial=[
...     {'title': u'Django is now open source',
...      'pub_date': datetime.date.today(),}
... ])

>>> for form in formset:
...     print form.as_table()
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-12" id="id_form-0-pub_date" /></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title" /></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>

上の例では、今度は 3 つのフォームが表示されました。初期データとして渡した 1 つと、 2 つの追加フォームです。初期データとして、辞書のリストを渡しているこ とにも注意してください。

フォームの最大表示数を制限する

formset_factorymax_num パラメタを指定すると、フォームセット中に 表示されるフォームの最大数を制御できます:

>>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1)
>>> formset = ArticleFormset()
>>> for form in formset:
...     print form.as_table()
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
リリースノートを参照してください

もし、 max_num の値が存在するオブジェクトの合計より大きい場合、 extra 次第で、空のフォームがフォームセットに加えられます。 フォームの合計の長さは max_num を超えることはできません。

max_num の値が None (通常です)であった場合、表示されるフォームの数には 制限がありません。 max_num の値が 0 から None になったことを 覚えておいてください。 version 1.2 から 0 は有効な値となりました。

フォームセットのバリデーション

フォームセットのバリデーションは、普通の Form とほぼ同じです。フォーム セットにも is_valid メソッドがあり、フォームセット中の全てのフォームを 簡単に検証できます:

>>> ArticleFormSet = formset_factory(ArticleForm)
>>> data = {
...     'form-TOTAL_FORMS': u'1',
...     'form-INITIAL_FORMS': u'0',
...     'form-MAX_NUM_FORMS': u'',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
True

この例では、フォームセットにデータを渡さなかったので、有効なフォームを返し ています。フォームセットは賢くて、データの変更されなかったフォームを無視し てくれます。あるフォーム上の記事を変更しようとして、失敗した場合の挙動を以 下に示します:

>>> data = {
...     'form-TOTAL_FORMS': u'2',
...     'form-INITIAL_FORMS': u'0',
...     'form-MAX_NUM_FORMS': u'',
...     'form-0-title': u'Test',
...     'form-0-pub_date': u'1904-06-16',
...     'form-1-title': u'Test',
...     'form-1-pub_date': u'', # <-- this date is missing but required
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {'pub_date': [u'This field is required.']}]

確認できるように、 formset.errors はリストで、 そのエントリーは、フォームセットの中のフォームのものです。 バリデーションは、二つのフォームそれぞれに働いて、 リストの二つ目のアイテムにエラーメッセージが表示されています。

また、初めのデータと入力されたデータが異なっているかどうかも チェックできます。(すなわち、フォームは何のデータもなしに送信されない) ということです。

>>> data = {
...     'form-TOTAL_FORMS': u'1',
...     'form-INITIAL_FORMS': u'0',
...     'form-MAX_NUM_FORMS': u'',
...     'form-0-title': u'',
...     'form-0-pub_date': u'',
... }
>>> formset = ArticleFormSet(data)
>>> formset.has_changed()
False
ManagementForm を理解する

上の例でフォームセットに与えた初期値には、追加のデータ( form-TOTAL_FORMS , form-INITIAL_FORMS , form-MAX_NUM_FORMS )が入っていたことに気 付いたでしょうか。これはフォームセットで内部的に処理されているフォーム、 ManagementForm で扱うためのデータです。追加のデータ抜きでフォームセット を使おうとすると、例外が送出されます:

>>> data = {
...     'form-0-title': u'Test',
...     'form-0-pub_date': u'',
... }
>>> formset = ArticleFormSet(data)
Traceback (most recent call last):
...
django.forms.util.ValidationError: [u'ManagementForm data is missing or has been tampered with']

ManagementForm のデータは、表示するフォームインスタンスの数を追跡するた めに使われます。 JavaScript でフォームを動的に追加する場合、 ManagementForm データのカウントも増やさねばなりません。

マネジメントフォームはフォームセット自身のアトリビュートとして使用可能です。 テンプレートにフォームセットをレンダリングする際、 {{ my_formset.management_form }} をレンダリングすることでマネジメント データを含むことができます。(フォームセットのところは適切な名前に変えて 使ってください)

total_form_countinitial_form_count

BaseFormSet は二つの ManagementForm に類似したメソッドを持っています、 total_form_countinitial_form_count です。

total_form_count は、フォームセットの中のフォームの合計の数を返します。 initial_form_count はフォームセットの中のフォームのうち、データが 入力されているものだけを返します、また幾つのフォームが必要かを判断するのに 使えます。おそらくこれらのメソッドを上書きする必要に迫られることはないでしょ う。まずは、実行する前に何を実行するのかを理解しておいたほうがよいでしょう。

リリースノートを参照してください
empty_form

BaseFormSetempty_form という追加のアトリビュートを提供します。 これは、 JavaScript を使った動的なフォーム生成を簡単にするために __prefix__ のプレフィクスをフォームインスタンスとともに返します。

カスタムのフォームセットバリデーション

Form クラスと同様、フォームセットには clean メソッドがあります。こ のメソッドには、フォームセットレベルで扱う独自のバリデーションを定義します:

>>> from django.forms.formsets import BaseFormSet

>>> class BaseArticleFormSet(BaseFormSet):
...     def clean(self):
...         """Checks that no two articles have the same title."""
...         if any(self.errors):
...             # Don't bother validating the formset unless each form is valid on its own
...             return
...         titles = []
...         for i in range(0, self.total_form_count()):
...             form = self.forms[i]
...             title = form.cleaned_data['title']
...             if title in titles:
...                 raise forms.ValidationError("Articles in a set musthave distinct titles.")
...             titles.append(title)

>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
>>> data = {
...     'form-TOTAL_FORMS': u'2',
...     'form-INITIAL_FORMS': u'0',
...     'form-MAX_NUM_FORMS': u'',
...     'form-0-title': u'Test',
...     'form-0-pub_date': u'1904-06-16',
...     'form-1-title': u'Test',
...     'form-1-pub_date': u'1912-06-23',
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
False
>>> formset.errors
[{}, {}]
>>> formset.non_form_errors()
[u'Articles in a set must have distinct titles.']

フォームセットの clean メソッドは、全てのフォームに対して Form.clean メソッドが呼出された後に実行されます。フォームセットに関する エラーは、フォームセットの non_form_errors() メソッドで取り出せます。

フォームの並び順や削除の扱い

フォームセットを扱う上でよくあるユースケースは、フォームインスタンスの並び 順や削除の処理です。フォームセットはこれらの処理を実行してくれます。 formset_factory には can_order および can_delete という二つの パラメタがあり、指定するとフォームにフィールドを追加して、並び順や削除フラ グを操作する簡単な手段を提供します。

can_order

デフォルト値: False

並べ替え機能とともに、フォームセットを作ってみましょう:

>>> ArticleFormSet = formset_factory(ArticleForm, can_order=True)
>>> formset = ArticleFormSet(initial=[
...     {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
...     {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> for form in formset:
...     print form.as_table()
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
<tr><th><label for="id_form-0-ORDER">Order:</label></th><td><input type="text" name="form-0-ORDER" value="1" id="id_form-0-ORDER" /></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
<tr><th><label for="id_form-1-ORDER">Order:</label></th><td><input type="text" name="form-1-ORDER" value="2" id="id_form-1-ORDER" /></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
<tr><th><label for="id_form-2-ORDER">Order:</label></th><td><input type="text" name="form-2-ORDER" id="id_form-2-ORDER" /></td></tr>

このオプションを指定すると、各フォームにフィールドが追加されます。フィール ドの名前は ORDER で、型は forms.IntegerField です。初期データを使っ てフォームを生成した場合、 ORDER フィールドには自動的に数値が割り当てら れます。ユーザがこの値を変更するとどうなるか見てみましょう:

>>> data = {
...     'form-TOTAL_FORMS': u'3',
...     'form-INITIAL_FORMS': u'2',
...     'form-0-title': u'Article #1',
...     'form-0-pub_date': u'2008-05-10',
...     'form-0-ORDER': u'2',
...     'form-1-title': u'Article #2',
...     'form-1-pub_date': u'2008-05-11',
...     'form-1-ORDER': u'1',
...     'form-2-title': u'Article #3',
...     'form-2-pub_date': u'2008-05-01',
...     'form-2-ORDER': u'0',
... }

>>> formset = ArticleFormSet(data, initial=[
...     {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
...     {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> formset.is_valid()
True
>>> for form in formset.ordered_forms:
...     print form.cleaned_data
{'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': u'Article #3'}
{'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': u'Article #2'}
{'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': u'Article #1'}
can_delete

デフォルト値: False

削除機能とともに、フォームセットを作ってみましょう:

>>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
>>> formset = ArticleFormSet(initial=[
...     {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
...     {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> for form in formset:
....    print form.as_table()
<input type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS" />
<input type="hidden" name="form-INITIAL_FORMS" value="2" id="id_form-INITIAL_FORMS" />
<input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" />
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
<tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
<tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
<tr><th><label for="id_form-2-DELETE">Delete:</label></th><td><input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" /></td></tr>

can_order と同様、 DELETE という名前のついたフィールドが追加されま す。このフィールドは forms.BooleanField です。削除フラグフィールドをマー クしたデータを投入すると、削除フラグの立っているフォームに deleted_forms でアクセスできます:

>>> data = {
...     'form-TOTAL_FORMS': u'3',
...     'form-INITIAL_FORMS': u'2',
...     'form-MAX_NUM_FORMS': u'',
...     'form-0-title': u'Article #1',
...     'form-0-pub_date': u'2008-05-10',
...     'form-0-DELETE': u'on',
...     'form-1-title': u'Article #2',
...     'form-1-pub_date': u'2008-05-11',
...     'form-1-DELETE': u'',
...     'form-2-title': u'',
...     'form-2-pub_date': u'',
...     'form-2-DELETE': u'',
... }

>>> formset = ArticleFormSet(data, initial=[
...     {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
...     {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
... ])
>>> [form.cleaned_data for form in formset.deleted_forms]
[{'DELETE': True, 'pub_date': datetime.date(2008, 5, 10), 'title': u'Article #1'}]
フォームセットにフィールドを追加する

フォームセットには、追加のフィールドを簡単に追加できます。フォームセットの ベースクラスは add_fields メソッドを提供しています。このメソッドをオー バライドして、独自にフィールドを追加したり、デフォルトのフィールドや属性を 再定義したり、フィールドを削除したりできます:

>>> class BaseArticleFormSet(BaseFormSet):
...     def add_fields(self, form, index):
...         super(BaseArticleFormSet, self).add_fields(form, index)
...         form.fields["my_field"] = forms.CharField()

>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
>>> formset = ArticleFormSet()
>>> for form in formset:
...     print form.as_table()
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
<tr><th><label for="id_form-0-my_field">My field:</label></th><td><input type="text" name="form-0-my_field" id="id_form-0-my_field" /></td></tr>
ビューやテンプレートでフォームセットを使う

ビュー内でのフォームセットの扱いは簡単で、普通の Form クラスと同じよう に使うだけです。気をつけておかねばならないのは、テンプレート内で management_form を使うという点です。ビューの例を以下に示します:

def manage_articles(request):
    ArticleFormSet = formset_factory(ArticleForm)
    if request.method == 'POST':
        formset = ArticleFormSet(request.POST, request.FILES)
        if formset.is_valid():
            # do something with the formset.cleaned_data
    else:
        formset = ArticleFormSet()
    return render_to_response('manage_articles.html', {'formset': formset})

manage_articles.html テンプレートは以下のようになります:

<form method="post" action="">
    {{ formset.management_form }}
    <table>
        {% for form in formset %}
        {{ form }}
        {% endfor %}
    </table>
</form>

ただし、下記のようなショートカットを使えば、フォームセット自体に管理フォー ムを扱わせられます:

<form method="post" action="">
    <table>
        {{ formset }}
    </table>
</form>

このショートカットは、フォームセットの as_table を呼び出した時と同じ内 容を出力します。

can_deletecan_order を手動で出力する。

もし、テンプレートの中で手動でフィールドを出力するなら、 can_delete パラメータは {{ form.DELETE }} で出力できます:

<form method="post" action="">
    {{ formset.management_form }}
    {% for form in formset %}
        {{ form.id }}
        <ul>
            <li>{{ form.title }}</li>
            {% if formset.can_delete %}
                <li>{{ form.DELETE }}</li>
            {% endif %}
        </ul>
    {% endfor %}
</form>

同じように、もしフォームセットが並べ替え機能を所持するなら( can_order=True )、これもまた {{ form.ORDER }} で呼び出すことができます。

複数のフォームセットを一つのビュー内で使う

お望みなら、複数のフォームセットを一つのビューで扱えます。フォームセットは フォームとほとんど同じく動作します。つまり、 prefix を使ってフォームセッ トのフォームフィールド名にプレフィクスをつければ、複数のフォームセットを 一つのビューに入れても問題なく動作するのです。複数のフォームセットがどのよ うに動作するか、以下の例で示しましょう:

def manage_articles(request):
    ArticleFormSet = formset_factory(ArticleForm)
    BookFormSet = formset_factory(BookForm)
    if request.method == 'POST':
        article_formset = ArticleFormSet(request.POST, request.FILES, prefix='articles')
        book_formset = BookFormSet(request.POST, request.FILES, prefix='books')
        if article_formset.is_valid() and book_formset.is_valid():
            # do something with the cleaned_data on the formsets.
    else:
        article_formset = ArticleFormSet(prefix='articles')
        book_formset = BookFormSet(prefix='books')
    return render_to_response('manage_articles.html', {
        'article_formset': article_formset,
        'book_formset': book_formset,
    })

これで、フォームセットは通常通りレンダできます。重要なのは、 prefix を POST リクエストの場合とそうでない場合の両方に指定して、正しくレンダさせるこ とです。

モデルからフォームを生成する
revision-up-to:17812 (1.4) unfinished
ModelForm
class ModelForm

データベース駆動のアプリケーションを構築しているのなら、 Django のモデルに 対応したフォームが必要な場合があるでしょう。例えば、 BlogComment モデル を作っていて、読者がコメントを入力できるようなフォームを作成したいような場 合です。こうしたケースでは、すでにモデルにフィールドを定義しているので、新 たにフォームクラス用にフィールドを定義するのは無駄な作業でしかありません。

この理由から、 Django はモデルからフォームクラスを生成するためのヘルパクラ スを提供しています。

以下に例を示します:

>>> from django.forms import ModelForm

# フォームクラスを生成
>>> class ArticleForm(ModelForm):
...     class Meta:
...         model = Article

# 記事を追加するためのフォームを作成
>>> form = ArticleForm()

# 既存の記事を変更するためのフォームを作成
>>> article = Article.objects.get(pk=1)
>>> form = ArticleForm(instance=article)
フィールド型

モデルから生成されるフォームクラスは、モデルの各フィールドに対応したフォー ムフィールドを持ちます。モデルフィールドには、それぞれデフォルトのフォーム フィールド型が定義されています。例えば、モデルの CharField 型には、 CharField 型のフォームフィールドが対応しています。モデルの ManyToManyField には、 MultipleChoiceField が対応しています。以下に 対応の一覧表を示します:

モデルフィールド型 フォームフィールド型
AutoField フォーム上では表現されていません
BigIntegerField IntegerFieldmin_value が -9223372036854775808 、 max_value が 9223372036854775807 にセットされています。
BooleanField BooleanField
CharField CharFieldmax_length にはモ デルフィールドの max_length 値が設 定されます。
CommaSeparatedIntegerField CharField
DateField DateField
DateTimeField DateTimeField
DecimalField DecimalField
EmailField EmailField
FileField FileField
FilePathField CharField
FloatField FloatField
ForeignKey ModelChoiceField (下記参照)
ImageField ImageField
IntegerField IntegerField
IPAddressField IPAddressField
GenericIPAddressField GenericIPAddressField
ManyToManyField ModelMultipleChoiceField (下記参照)
NullBooleanField CharField
PhoneNumberField USPhoneNumberField (django.contrib.localflavor.us)
PositiveIntegerField IntegerField
PositiveSmallIntegerField IntegerField
SlugField SlugField
SmallIntegerField IntegerField
TextField widget=TextareaCharField
TimeField TimeField
URLField URLFieldverify_exists には モデルフィールドの verify_exists 値が設定されます。
BigIntegerField は Django 1.2 で新たに定義されました。

お気付きかもしれませんが、 ForeignKeyManyToManyField といったモ デルフィールドは特別扱いされています:

  • ForeignKeydjango.forms.ModelChoiceField で表現されて います。 ModelChoiceField は、選択肢がモデルの QuerySet であ るような ChoiceField です。
  • ManyToManyFielddjango.forms.ModelMultipleChoiceField で表現されています。 ModelMultipleChoiceField は、選択肢がモデル の QuerySet であるような MultipleChoiceField です。

さらに、生成されるフォームフィールドには、以下の属性が付加されます:

  • モデルフィールドに blank=True が設定されていると、フォームフィー ルドの requiredFalse に設定されます。それ以外の場合には、 required=True です。
  • フォームフィールドの label にはモデルフィールドの verbose_name の値を使います。このとき先頭の文字は大文字に変換され ます。
  • フォームフィールドの help_text にはモデルフィールドの help_text の値を使います。
  • モデルフィールドに choices が設定されている場合、フォームフィール ドの widgetSelect に設定されます。また、選択肢にはモデル フィールドの choices の値を使います。通常、選択肢の中には、空の 選択肢が加えられ、フォームの表示時にデフォルトで選択されています。 フィールドが必須のフィールドである場合、ユーザは必ず空の選択肢以外か ら選択せねばなりません。モデルフィールドが blank=False で、かつ default 値が明に設定されている場合、空の選択肢は表示されません (default の値が選択された状態で表示されます)。

あるモデルからフォームを作成する場合、モデルのフォームフィールドに対応する フォームフィールドをオーバライドできます。後述の デフォルトのフィールド型をオーバライドする を参照してください。

詳細な例

以下のような一連のモデルを考えましょう:

from django.db import models
from django.forms import ModelForm

TITLE_CHOICES = (
    ('MR', 'Mr.'),
    ('MRS', 'Mrs.'),
    ('MS', 'Ms.'),
)

class Author(models.Model):
    name = models.CharField(max_length=100)
    title = models.CharField(max_length=3, choices=TITLE_CHOICES)
    birth_date = models.DateField(blank=True, null=True)

    def __unicode__(self):
        return self.name

class Book(models.Model):
    name = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)

class AuthorForm(ModelForm):
    class Meta:
        model = Author

class BookForm(ModelForm):
    class Meta:
        model = Book

上に挙げた例中の ModelForm サブクラスは、以下のフォームクラスとほぼ同じ になります (違いは save() メソッドの動作だけです。これについてはすぐ後 で説明します):

from django import forms

class AuthorForm(forms.Form):
    name = forms.CharField(max_length=100)
    title = forms.CharField(max_length=3,
                widget=forms.Select(choices=TITLE_CHOICES))
    birth_date = forms.DateField(required=False)

class BookForm(forms.Form):
    name = forms.CharField(max_length=100)
    authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
is_valid() メソッドと errors

最初に ModelFormis_valid() を呼び出すか、 あるいは errors 属性にアクセスしたときに モデルのバリデーション と同様にフォームバリデーション が行われます。 これには ModelForm コンストラクタに渡したモデルをクリーニングするという 副作用があります。例えば、あなたのフォームに対して is_valid() を呼ぶと 日付フィールドが実際の日付フィールドに変換されてしまいます。

save() メソッド

ModelForm から生成されたフォームは save() メソッドを備えています。 このメソッドは、フォームに結びつけられたデータから、モデルオブジェクトを生 成してデータベースに保存します。 ModelForm のサブクラスは既存のモデルイ ンスタンスをキーワード引数 instance にしてインスタンス化できます。 instance を指定してモデルフォームを生成すると、モデルフォームの save() はこのインスタンスを更新して保存します。 instance を指定しな ければ、 save() はモデルフォームで指定しているモデルの新たなインスタン スを生成します:

# POST データから新たなフォームインスタンスを生成
>>> f = ArticleForm(request.POST)

# フォームデータから新たな Article オブジェクトを生成
>>> new_article = f.save()

# 既存の Article オブジェクトからフォームを生成
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(instance=a)
>>> f.save()

# 既存の Article オブジェクトを編集するためのフォームを作成します。
# ただし、 POST データを使ってフォームに値を設定します。
>>> a = Article.objects.get(pk=1)
>>> f = ArticleForm(request.POST, instance=a)
>>> f.save()

form.errors が True であると評価されると、 save()ValueError を送出す るので注意してください。

save() メソッドはオプション commit キーワード引数を持っています。こ の引数には True または False を指定します。 save()commit=False で呼び出すと、データベースに保存する前のモデルオブジェクト を返します。返されたオブジェクトに対して、最終的に save() を呼び出すか どうかは自由です。この機能は、オブジェクトを実際に保存する前に何らかの処理 を行いたい場合や、特殊なオプション付きで モデルオブジェクトを保存したい 場合に便利 です。 commit はデフォルトでは True に設定されています。

モデルが他のモデルに対する多対多のリレーションを持っている場合、 commit=False を使うともう一つの副作用があります。多対多のリレーションを 持つモデルから生成したフォームを保存する際、 Django は多対多のリレーション に対するデータをすぐに保存できません。なぜなら、 save(commit=False) の 対象であるオブジェクトはまだデータベースに保存されていないため、オブジェク トに対する多対多の関係を保存するためのテーブルを更新できないからです。

この問題を回避するために、Django は commit=False でフォームを保存した直 後に、 save_m2m() メソッドを ModelForm のサブクラスへ追加します。フォーム から生成したインスタンスを手動で保存した後で save_m2m() を呼び出せば、 多対多のフォームデータを保存できます。以下に例を示します:

# POST データから新たなフォームインスタンスを生成
>>> f = AuthorForm(request.POST)

# インスタンスを生成、ただし保存はしない
>>> new_author = f.save(commit=False)

# new_author のフィールド値を変更
>>> new_author.some_field = 'some_value'

# 新たなインスタンスを保存
>>> new_author.save()

# 最後に、多対多のフォームデータを保存
>>> f.save_m2m()

save_m2m() の呼び出しが必要なのは、 save(commit=False) を使った場合 だけです。単に save() を呼び出すだけなら、多対多のデータを含む全てのデー タが保存され、他に何らかのメソッドを呼び出す必要はありません。以下に例を示 します:

# POST データから新たなフォームインスタンスを生成
>>> a = Author()
>>> f = AuthorForm(request.POST, instance=a)

# 新たな Author インスタンスを生成して保存。他にはなにもしなくてよい
>>> new_author = f.save()

save() および save_m2m() メソッド以外は、 ModelForm は他の forms で作られたフォームと全く同じように動作します。例えば、 データの検証は is_valid() で行えますし、 is_multipart() メソッドを使えばフォームがマルチパートのファイルアップロードを要求している かどうか (そして request.FILES をフォームに渡さなければならないかどうか) 判別できます。詳しくは、 アップロードされたファイルをフォームに結びつける を参照してください。

モデルの一部のフィールドだけからフォームを生成する

場合によっては、フォームを生成するときに、モデルの一部のフィールドだけを表 示したいことでしょう。モデルフィールドの一部だけを使って ModelForm を作 るには、以下の 3 つの方法があります:

  1. モデルフィールドに editable=False を定義します。その結果、 モデルフォームを使って生成したフォームは 全て このフィールドを含ま なくなります。
  2. ModelForm サブクラスで、内部クラス Metafields 属性を 設定します。この属性にはフィールド名からなるリストを設定します。設定 すると、指定されたフィールドだけを含むフォームを生成します。 fieldsに指定された名前の順番はフォームがレンダーされる時に尊重されます。
  3. ModelForm サブクラスで、内部クラス Metaexclude 属性を 設定します。この属性にはフィールド名からなるリストを設定します。設定 すると、指定されたフィールドを含まないフォームを生成します。

例えば、 (上で定義した) Author モデルから、 nametitle フィールドだけを含むようなフォームを作成したければ、以下の ようにして fields または exclude を指定します:

class PartialAuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title')

class PartialAuthorForm(ModelForm):
    class Meta:
        model = Author
        exclude = ('birth_date',)

Author モデルには 'name', 'title', 'birth_date' の 3 つ のフィールドしかないので、上のフォームは全く同じフォームフィールド を持ちます。

Note

ModelForm を使ってフォームを生成するときに fieldsexclude を指定すると、生成されたフォームの save() を呼び出した ときに、フォームに含まれていないフィールドのデータは設定されません。 また、除外フィールドをフォームに手動で追加し直してもモデルインスタンス から初期化されることはありません。

このため、フォームに含まれていないフィールドに対応するモデルフィールド が、空の値を許さないように定義されていて、かつデフォルトの値が指定され ていない場合、モデルインスタンスが不完全なために Django がオブジェクト の保存を抑止し、 save() は失敗します。これを避けるには、フォームの インスタンスを生成するときに、不足しているフィールドでかつ必須のフィー ルドに対する初期値を指定してください:

author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()

あるいは、 save(commit=False) を使って、必須のフィールドの値を手動 で設定してください:

form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()

save(commit=False) については、 フォームを保存する も参照してください。

デフォルトのフィールド型をオーバライドする
widgets 属性はDjango 1.2で新たに導入されました。

上の フィールド型 で説明したデフォルトのフィールド型は、いわゆる気の利い たデフォルト値にすぎません。モデル上で DateField として定義されている フィールドは、フォーム上でも DateField として表現されてほしいというのが 普通でしょう。とはいえ、 ModelForm は、あるモデルフィールドのフォーム フィールド型を変更できるという柔軟性を備えています。

フィールドに対するカスタムウィジェットを指定するには、 Meta インナークラス の widgets 属性を使います。 これはフィールド名をウィジェットクラスあるいは インスタンスにマッピングさせるディクショナリです。

例えば、 AuthorCharFieldname 属性を、 デフォルトの <input type="text"> では無く <textarea> で表現したい のであれば、 フィールドのウィジェットをオーバーライドします

from django.forms import ModelForm, Textarea

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title', 'birth_date')
        widgets = {
            'name': Textarea(attrs={'cols': 80, 'rows': 20}),
        }

widgets ディクショナリはウィジェットのインスタンス(たとえば、 Textarea(...) )かクラス (例えば、 Textarea) を指定可能です。

さらにフィールドをカスタマイズしたい – 型、ラベルなど – のであれば、 通常の Form と同様にフィールドの宣言によって行うことができます。 宣言されたフィールドは、 model 属性から生成さ れたデフォルトの フィールドをオーバライドします。

例えば、 pub_date フィールドに MyDateFormField を使いたければ、 以下のようにして実現できます:

>>> class ArticleForm(ModelForm):
...     pub_date = MyDateFormField()
...
...     class Meta:
...         model = Article

フィールドのデフォルトのラベルをオーバーライドしたいのであれば、 label パラメータをフォームフィールドで宣言します

>>> class ArticleForm(ModelForm):
...     pub_date = DateField(label=u'出版日')
...
...     class Meta:
...         model = Article

Note

このように明示的にフォームフィールドをインスタンス化すると、 Djangoはそのフィールドの振る舞いを完全に定義したいのだと判断します: 従って、(max_lengthrequired のような)デフォルトの属性が 対応するモデルから持ってこられません。 もしもモデルで定義された振る舞いを維持したいのであれば、 フォームフィールドを宣言する際に適切な引数を明示的に設定する必要があります。

例えば、 Article が次のように定義されているならば:

class Article(models.Model):
    headline = models.CharField(max_length=200, null=True, blank=True,
                                help_text="Use puns liberally")
    content = models.TextField()

headline に対するカスタムバリデーションを行う必要があると同時に blankhelp_text も維持する必要があるので、 ArticleForm は このようになります

class ArticleForm(ModelForm):
    headline = MyFormField(max_length=200, required=False,
                           help_text="Use puns liberally")

    class Meta:
        model = Article

フィールドとその引数に関しての詳細な情報は、 フォームフィールドドキュメント を参照してください。

フィールドの並びを変更する

デフォルトの動作としては、 ModelFrom はモデルに定義されたのと同じ順番で フィールドをレンダリングして、 ManyToManyField インスタンスに関しては 最後に現れるようにレンダリングします。 レンダリングされるフィールドの並びを変更したいのであれば、 fields 属性を Meta クラスで使います。

fields 属性はレンダリングされるモデルフィールドのサブセットと その並び順 を定義します。例えば次のようなモデルがあると、

class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=100)

author フィールドが最初にレンダリングされます。 titleフィールドを最初にレンダリングしたいのであれば、以下の ModelForm を定義することができます。

>>> class BookForm(ModelForm):
...     class Meta:
...         model = Book
...         fields = ('title', 'author')
clean() メソッドのオーバライド

バリデーションの動作を追加するために、モデルフォームの clean() メソッド を通常のフォームと同じ方法でオーバライドできます。

In this regard, model forms have two specific characteristics when compared to forms:

デフォルトの``clean()`` メソッドは、モデルの uniqueunique_together 、あるいは unique_for_date|month|year に指定した内容に従って、オブジェクトの 一意性をチェックします。従って、 clean() をオーバライドして、なおかつ デフォルトのバリデーションも行いたいときは、親クラスの clean() メソッドを 必ず呼び出してください。

Also, a model form instance bound to a model object will contain a self.instance attribute that gives model form methods access to that specific model instance.

フォームクラスの継承

フォームクラスと同様、 ModelForm も継承によって再利用できます。フォーム クラスの継承は、一つのモデルからいくつもフォームを導出して、フォーム毎にフィー ルドを追加したり、メソッドを追加したりする際に便利です:

>>> class EnhancedArticleForm(ArticleForm):
...     def clean_pub_date(self):
...         ...

上記のコードは、独自に pub_date フィールドの検証とクリーニングを行うほ かは、 ArticleForm と全く同じフォームを生成します。

親クラスの内部クラス Meta をサブクラス化すれば、親クラスの Meta.fieldsMeta.excludes リストを変更できます:

>>> class RestrictedArticleForm(EnhancedArticleForm):
...     class Meta(ArticleForm.Meta):
...         exclude = ('body',)

上記のコードは、 EnhancedArticleForm を追加して、 ArticleForm.Meta フィールドを変更することで、 body フィールドを除去しています。

ただし、フォームクラスの継承にはいくつか注意すべき点もあります。

  • 属性の名前解決には、通常の Python の名前解決規則が適用されます。すなわち、 内部クラス Meta を持つ複数の基底クラスを持つようなサブクラスを定義す ると、最初のクラスの Meta だけを使います。従って、 Meta の解決は まずサブクラスの Meta 、そして最初の親クラスの Meta の順に行われ ます。
  • 技術的な理由から、サブクラスは ModelFormForm を同時に継承で きません。

これらの注意点は、サブクラスを作成する際に何かトリッキーなことをしない限り は当てはまらないはずです。

モデルのバリデーションとの相互作用

バリデーションプロセスの一部として、 ModelForm はフォームの各フィールドに 対応するモデルフィールドの clean() メソッドを呼び出します。 モデルフィールドを除外したのであれば、それらフィールドのバリデーションが 行われません。 フィールドのクリーニングとバリデーションがどのように行われて いるのかに関する詳細は フォームバリデーション ドキュメントを参照してください。 また、モデルの clean() メソッドは一意性のチェックが行われる前に呼ばれます。 モデルの clean() フックに関する詳細な情報については、 オブジェクトのバリデーション を参照してください。

モデルフォームセット

通常のフォームセット と同様、モデル由来のフォー ムをうまく扱えるように拡張された特殊なフォームセットクラスがあります。上の Author モデルを使って説明しましょう:

>>> from django.forms.models import modelformset_factory
>>> AuthorFormSet = modelformset_factory(Author)

これで、 Author モデルに関連づけられたデータを扱えるフォームセットが生 成されます。 AuthorFormSet は、個々のフォームが Form ではなく ModelForm なだけで、通常のフォームセットと同じように使えます:

>>> formset = AuthorFormSet()
>>> print formset
<input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" />
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></td></tr>
<tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title">
<option value="" selected="selected">---------</option>
<option value="MR">Mr.</option>
<option value="MRS">Mrs.</option>
<option value="MS">Ms.</option>
</select></td></tr>
<tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0-birth_date" id="id_form-0-birth_date" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></td></tr>

Note

modelformset_factoryformset_factory を使ってフォームセット を生成します。つまり、モデルフォームセットは単に特定のモデルを扱えるよ うに拡張したフォームセットにすぎないのです。

クエリセットを変更する

デフォルトでは、モデルからフォームセットを生成すると、そのクエリセットはモ デルの全てのオブジェクト、すなわち Author.objects.all() です。このクエ リセットは、以下のように変更できます:

>>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))

サブクラスを作って、 __init__ の中で self.queryset を設定する方法で も変更できます。:

from django.forms.models import BaseModelFormSet

class BaseAuthorFormSet(BaseModelFormSet):
    def __init__(self, *args, **kwargs):
        super(BaseAuthorFormSet, self).__init__(*args, **kwargs)
        self.queryset = Author.objects.filter(name__startswith='O')

ファクトリ関数を呼ぶときに、 BaseAuthorFormSet を渡してベースクラスにし てください:

>>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet)

モデルについての 全ての 既存のインスタンスを含まないフォームセットを 返したいのであれば、 空の QuerySetを指定することができます

>>> AuthorFormSet(queryset=Author.objects.none())
フォームセットに含めるフィールドを fieldsexclude で制御する

デフォルトでは、モデルフォームセットは、モデル中の editable=False でな い全てのフィールドを使おうとします。ただし、フォームセットレベルでこの挙動 はオーバライドできます:

>>> AuthorFormSet = modelformset_factory(Author, fields=('name', 'title'))

このように、 fields を使えば、フォームセットに組み込むフィールドを指定 したものだけに制限できます。一方:

>>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',))

このように、 exclude を使えば、指定したフィールドをフォームセットから除 外できます。

初期値を用意する
リリースノートを参照してください

通常のフォームセットと同様に、 modelformset_factory が返すモデルフォームセット をインスタンス化するときに initial パラメターを指定することでフォームセット に含まれるフォームの 初期データを指定する ことが 可能です。 しかし、モデルフォームセットでは初期値は拡張フォームにのみ適用され、既存の オブジェクトインスタンスにはバインドされません。

フォームセット内のオブジェクトを保存する

ModelForm と同様、フォームセット内のデータからモデルへの保存を行えます。 保存するには、フォームセットの save() メソッドを呼び出します:

# POST データからフォームセットインスタンスを生成します。
>>> formset = AuthorFormSet(request.POST)

# フォームデータが有効なものと課程して、データを保存します。
>>> instances = formset.save()

save() メソッドはデータベースに保存されたインスタンスを返します。インス タンスがフォームセットに結びつけられたデータで変更されなかった場合、そのイ ンスタンスはデータベースに保存されず、戻り値 (上の例の instances) にも 含まれません。

フォームからフィールドが欠けている場合(例えば、excludedされているなどの 理由により) 、そのフィールドは save() メソッド でセットされません。 この制約は通常の ModelForms でも適用される物ですがこれに関するより詳細な 情報は モデルの一部のフィールドだけからフォームを生成する で見つけること ができます。

save()commit=False を渡せば、データベースは触らずに、モデルイン スタンスだけを返させられます:

# データベースに保存しません
>>> instances = formset.save(commit=False)
>>> for instance in instances:
...     # インスタンスごとに必要な操作を行います。
...     instance.save()

この方法を使えば、データベースにインスタンスを保存する前に、各々のインスタ ンスにデータを付加できます。また、フォームセットに ManyToManyField が含 まれている場合は、 formset.save_m2m() を使って多対多のリレーションを正 しく保存させる必要があるでしょう。

編集可能なオブジェクトの数を制限する
リリースノートを参照してください

通常のフォームセットと同様に、 max_numextra パラメータを使って modelformset_factory 表示されるフォームの数を制限することができます。

max_num は既存のオブジェクトが表示されることを妨げることはしません:

>>> Author.objects.order_by('name')
[<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]

>>> AuthorFormSet = modelformset_factory(Author, max_num=1)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> [x.name for x in formset.get_queryset()]
[u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman']

max_num の値が既存の関連するオブジェクトよりも大きい場合、 extra で指定 した数までの追加のブランクフォームがフォームセットに追加されますが、 フォームの 全数は max_num を超えることはありません:

>>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2)
>>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
>>> for form in formset:
...     print form.as_table()
<tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100" /><input type="hidden" name="form-0-id" value="1" id="id_form-0-id" /></td></tr>
<tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100" /><input type="hidden" name="form-1-id" value="3" id="id_form-1-id" /></td></tr>
<tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100" /><input type="hidden" name="form-2-id" value="2" id="id_form-2-id" /></td></tr>
<tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></td></tr>
リリースノートを参照してください

max_num の値が None (デフォルト)だと、表示されるフォームの数には制限 が課せられません。

ビュー内でモデルフォームセットを使う

モデルフォームセットは、フォームセットと良く似ています。例として、 ユーザが Author モデルインスタンスを編集できるようなフォームセットを考 えましょう:

def manage_authors(request):
    AuthorFormSet = modelformset_factory(Author)
    if request.method == 'POST':
        formset = AuthorFormSet(request.POST, request.FILES)
        if formset.is_valid():
            formset.save()
            # do something.
    else:
        formset = AuthorFormSet()
    render_to_response("manage_authors.html", {
        "formset": formset,
    })

このように、ビューの構造は通常のフォームセットを使ったときとほとんど変わり ません。違うのは、 formset.save() を使って、データをデータベースに保存 していることくらいです。 formset.save() は、 フォームセット内のオブジェクトを保存する で解説しています。

model_formsetclean() をオーバーライドする

ModelFroms と同様に、デフォルトの動作として model_formsetclean() メソッドはフォームセットの中のフォームがモデルのユニーク属性 ( uniqueunique_togeter 、あるいは unique_for_date|month|year) を侵害していないことを検証します。 model_formsetclean() メソッドをオーバーライドした上でこの検証の 仕組みを維持したいのであれば、 親クラスの clean メソッドを呼ぶ必要が あります。:

class MyModelFormSet(BaseModelFormSet):
    def clean(self):
        super(MyModelFormSet, self).clean()
        # example custom validation across forms in the formset:
        for form in self.forms:
            # your custom formset validation
カスタムクエリセットを使う

前にも述べた通り、モデルフォームセットで使用されるデフォルトのクエリセットを オーバーライドすることができます

def manage_authors(request):
    AuthorFormSet = modelformset_factory(Author)
    if request.method == "POST":
        formset = AuthorFormSet(request.POST, request.FILES,
                                queryset=Author.objects.filter(name__startswith='O'))
        if formset.is_valid():
            formset.save()
            # Do something.
    else:
        formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
    return render_to_response("manage_authors.html", {
        "formset": formset,
    })

この例では POSTGET の両方において queryset パラメータを 渡すことができます。

テンプレートでフォームセットを使う

Djangoテンプレートでフォームセットをレンダーするには3つの方法があります。

最初の方法はフォームセットにほとんどの作業を任せることです

<form method="POST" action="">
    {{ formset }}
</form>

第2の方法はフォームセットのレンダリングを手動で行いますが、フォーム 自体のレンダリングはそれらに任せる方法です

<form method="post" action="">
    {{ formset.management_form }}
    {% for form in formset.forms %}
        {{ form }}
    {% endfor %}
</form>

フォームを手動でレンダリングするのであれば、上で示したように管理フォーム (management form) をレンダリングするしてください。 管理フォームドキュメント を 参照のこと。

第3の方法は、各フィールドを手動でレンダリングする方法です

<form method="post" action="">
    {{ formset.management_form }}
    {% for form in formset %}
        {% for field in form %}
            {{ field.label_tag }}: {{ field }}
        {% endfor %}
    {% endfor %}
</form>

もしも第3の方法を使って {% for %} ループでフィールドを反復したくない のであれば、 プライマリキーフィールドをレンダリングする必要があります。 例えば、 モデルの nameage フィールドをレンダリングするのであれば:

<form method="post" action="">
    {{ formset.management_form }}
    {% for form in formset %}
        {{ form.id }}
        <ul>
            <li>{{ form.name }}</li>
            <li>{{ form.age }}</li>
        </ul>
    {% endfor %}
</form>

明示的に {{ form.id}} をレンダリングしなければならないことに注意してください。 これによりモデルフォームセットが POST の場合正しく動作します ( この例はプライマリキーが id であると仮定しています。 もしも id 以外の プライマリキーを明示的に定義してあるのならば、 必ずそれをレンダリングして下さい)。

インラインフォームセット

インラインフォームセット(inline formsets)はモデルフォームセットの頂点に位置する 小さな抽象化レイヤーです。これは外部キーで関連するオブジェクトを動作させること を簡素化しています。 以下の2つのモデルがある物とします

class Author(models.Model):
    name = models.CharField(max_length=100)

class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=100)

特定の作者(author) の本を扱うフォームセットを生成したければ、以下のようにし ます:

>>> from django.forms.models import inlineformset_factory
>>> BookFormSet = inlineformset_factory(Author, Book)
>>> author = Author.objects.get(name=u'Mike Royko')
>>> formset = BookFormSet(instance=author)

Note

inlineformset_factorymodelformset_factory を使っており、 can_delete=True がセットされています。

同じモデルに対して複数の外部キーを張っている場合

同じモデルに対する複数の外部キーを張っている場合、キー間のあいまいさを無く すために、 fk_name を手動で設定する必要があります。以下のモデルを例に考 えてみましょう:

class Friendship(models.Model):
    from_friend = models.ForeignKey(Friend)
    to_friend = models.ForeignKey(Friend)
    length_in_months = models.IntegerField()

このモデルの問題を解決するには、 fk_nameinlineformset_factory に設定してください:

>>> FrienshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend")
ビューでインラインフォームセットを使う

ユーザーに対してモデルの関連オブジェクトを編集させるためのビューを提供したい ことがあるかと思います。 以下のようにすると可能です

def manage_books(request, author_id):
    author = Author.objects.get(pk=author_id)
    BookInlineFormSet = inlineformset_factory(Author, Book)
    if request.method == "POST":
        formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
        if formset.is_valid():
            formset.save()
            # Do something.
    else:
        formset = BookInlineFormSet(instance=author)
    return render_to_response("manage_books.html", {
        "formset": formset,
    })

POSTGET の両方のケースで instance を渡していることに注目 してください。

フォームメディア( Form Media )
revision-up-to:17812 (1.4)

魅力的で使いやすい Web フォームをレンダしたいなら、 HTML だけでは能力不足で しょう。CSS スタイルシートが必要でしょうし、ファンシーな “Web2.0” 的ウィジェッ トを使いたければ、各ページに JavaScript を仕込む必要もあるでしょう。あるペー ジでどのCSS と JavaScript の組み合わせが必要かは、そのページで使われている ウィジェットによって異なります。

そこで、 Django のメディア定義が登場します。 Django は様々なメディアファイ ルをそのメディアファイルを必要とするフォームやウィジェットに関連付けられる ようにしています。例えば、カレンダーを使って DateField をレンダしたいので、 カスタムの Calendar ウィジェットを定義したとします。このウィジェットには、 カレンダーをレンダするときに必要な CSS や JavaScript を関連付けておけます。 Calendar ウィジェットをフォーム上で使うときに、 Django は必要な CSS や JavaScript ファイルを特定して、それらのファイル名のリストを Web ページに簡 単に組み込める形式で提供します。

Django admin とメディアファイル

Django の admin アプリケーションは、カレンダーやフィルタ機能つきのセレ クタといった、様々なカスタムウィジェットを定義しています。これらのウィ ジェットは、それぞれが必要なメディアを定義していて、 Django は admin サ イトを表示するときに、デフォルトのウィジェットの代りにカスタムウィジェッ トを表示しています。 admin のテンプレートは、ページごとに必要なメディア ファイルだけを取り込み、ウィジェットをレンダするようになっています。

Django の admin アプリケーションのウィジェットを使いたいのなら、どうぞ ご自由に!ウィジェットは、全て django.contrib.admin.widgets で定義 されています。

どの JavaScript ツールキットを使えばいいの ?

JavaScript ツールキットは世の中に沢山あり、そのほとんどが(カレンダーの ような)アプリケーションの操作性を向上させられるウィジェットを定義して います。 Django は特定の JavaScript ツールキットを贔屓にしないよう慎重 に設計されています。どのツールキットにも、お互いに長所や短所があります。 自分にとって使いやすいツールキットを使ってください。 Django はどんな JavaScript ツールキットでも組み込めます。

メディア定義を静的に行う

メディア定義の簡単な方法は、クラスで静的に行うというものです。この方法では、 メディア定義を内部クラスとして宣言します。必要なメディアファイルの情報は、 内部クラスのプロパティとして定義します。

簡単な例を示しましょう:

class CalendarWidget(forms.TextInput):
    class Media:
        css = {
            'all': ('pretty.css',)
        }
        js = ('animations.js', 'actions.js')

このコードでは、 TextInput をベースにして CalendarWidget を定義して います。 CalendarWidget をフォーム内で使うと、フォームは CSS ファイル pretty.css と JavaScript ファイル animations.js および actions.js を組み込むよう指示を受けます。

このような静的なメディア定義は、実行時に media というウィジェットのプロ パティに変換されます。 CalendarWidget インスタンスのメディア情報は、プ ロパティを介して以下のように取り出せます:

>>> w = CalendarWidget()
>>> print w.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>

Media には、以下のようなオプションがあります。必須のものはありません。

css

出力媒体ごとの CSS ファイル要件を定義した辞書です。

この辞書の値はメディアファイル名を列挙したタプルまたはリストです。メディア ファイルのパスを指定する方法は メディアパスの節 を参照してください。

キーは出力媒体の名前です。このキーは、 CSS ファイルのメディアタイプ宣言で使 われるのと同じ、すなわち ‘all’, ‘aural’, ‘braille’, ‘embossed’, ‘handheld’, ‘print’, ‘projection’, ‘screen’, ‘tty’ そして ‘tv’ です。 メディアタイプごとに別々のスタイルシートを使いたければ、各メディアごとに CSS ファイルのリストを指定してください。以下の例では、スクリーン (screen) と印刷 (print) 用の CSS オプションを定義しています:

class Media:
    css = {
        'screen': ('pretty.css',),
        'print': ('newspaper.css',)
    }

一つの CSS ファイルグループが複数のメディアタイプをカバーできる場合、辞書の キーにメディアタイプをカンマ区切りのリストにして指定してください。以下の例 では、テレビ (tv) およびプロジェクタ (projector) に同じメディアファイル要件 を指定しています:

class Media:
    css = {
        'screen': ('pretty.css',),
        'tv,projector': ('lo_res.css',),
        'print': ('newspaper.css',)
    }

‘print’ の CSS 定義を使ってレンダリングを実行すると、以下のような HTML を出 力します:

<link href="http://media.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" />
<link href="http://media.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" />
<link href="http://media.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" />
js

必要な JavaScript ファイルを列挙したタプルです。メディアファイルのパスを指 定する方法は メディアパスの節 を参照してください。

extend

メディア宣言を親クラスから継承するかどうかを決めるブール値です。

デフォルトの設定では、静的メディア宣言を使うオブジェクトは全て、親クラスの ウィジェットで定義されているメディアを継承します。この継承は、親クラスでど んなメディアファイル要件を宣言したかに関係なく行われます。例えば、上の例の カレンダーウィジェットを、以下のように拡張したとします:

>>> class FancyCalendarWidget(CalendarWidget):
...     class Media:
...         css = {
...             'all': ('fancy.css',)
...         }
...         js = ('whizbang.js',)

>>> w = FancyCalendarWidget()
>>> print w.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>

FancyCalendarWidget は、親ウィジェットの全てのメディアを継承します。こ のやり方で親モデルのメディア宣言を継承したくないのなら、 extend=FalseMedia クラスの宣言に追加します:

class FancyCalendar(Calendar):
    class Media:
        extend = False
        css = {
            'all': ('fancy.css',)
        }
        js = ('whizbang.js',)

>>> w = FancyCalendarWidget()
>>> print w.media
<link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>

メディア宣言の継承をより細かく制御したければ、 動的なプロパティ を使って メディア宣言を定義してください。動的プロパティを使えば、どのメディアファイ ルを継承し、どのファイルを継承しないかを完全に制御できます。

動的プロパティでのメディア定義

media プロパティを直接定義すれば、メディアファイル要件をより洗練された やり方で制御できます。この方法では、 forms.Media のインスタンスを 返すようなプロパティを定義します。 forms.Media のコンストラクタは cssjs といったキーワード引数をとり、それぞれ静的なメディア定義 で使われているのと同じ形式の値を指定できます。

例えば、先の CalendarWidget の静的メディア定義を動的なやり方で実現する と、以下のように書けます:

class CalendarWidget(forms.TextInput):
    def _media(self):
        return forms.Media(css={'all': ('pretty.css',)},
                           js=('animations.js', 'actions.js'))
    media = property(_media)

動的なメディアプロパティの戻り値を構築するための詳しい方法は、 Media オブジェクト の節を参照してください。

メディア定義のパス
リリースノートを参照してください

メディアファイルの場所を指定するためのパスは、相対でも絶対でもかまいません。 パスが '/', 'http://', 'https://' のいずれかで開始していれば、 絶対パス指定として、値をそのまま使います。それ以外のパスの前には適切な プレフィクス(prefix)を指定します。 staticfiles app の部分的な紹介として、 “静的なファイル”(イメージや CSS, JavaScript, など)に完全な Web ページを 表示するための二つの新しい設定が追加されました。: STATIC_URL and STATIC_ROOT がそれです。 適切なプレフィクスを使うために、 Django は STATIC_URLNone ではないかどうかを確かめ、 MEDIA_URL を使うために自動的に 巻き戻ります。例えば、もしサイトの MEDIA_URL'http://uploads.example.com/' であって STATIC_URLNone であった場合:

>>> class CalenderWidget(forms.TextInput):
        class Media:
            css = {
                'all: ('/css/pretty.css',),
            }
            js = ('animations.js', 'http://othersite.com/actions.js')

>>> w = CalendarWidget()
>>> print w.media
<link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://uploads.example.com/animations.js"></script>
<script type="text/javascript" src="http://othersite.com/actions.js"></script>

ですが、もし STATIC_URL'http://static.example.com/' なら ば:

>>> w = CalendarWidget()
>>> print w.media
<link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://static.example.com/animations.js"></script>
<script type="text/javascript" src="http://othersite.com/actions.js"></script>
Media オブジェクト

ウィジェットやフォームの media 属性を調べると、 forms.Media オブジェク トが返されます。すでに解説した通り、 Media オブジェクトの文字列表現は、 HTML ページの <head> ブロックでメディアファイルを取り込むときに必要な HTML コードです。

とはいえ、 Media オブジェクトには他にもいくつか興味深いプロパティがあり ます。

Media サブセット

特定のタイプのメディアファイル情報だけを出力したければ、添え字表記を使って 以下のように欲しいメディアだけを指定できます:

>>> w = CalendarWidget()
>>> print w.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>

>>> print w.media['css']
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />

添え字表記を使ってアクセスすると、新たな Media オブジェクトが返されます。 ただし、このオブジェクトには指定したメディアしか入っていません。

Media オブジェクトを組み合わせる

Media オブジェクトは加算できます。二つの Media オブジェクトを加算す ると、結果の Media オブジェクトには両方のメディアファイル情報が入ります:

>>> class CalendarWidget(forms.TextInput):
...     class Media:
...         css = {
...             'all': ('pretty.css',)
...         }
...         js = ('animations.js', 'actions.js')

>>> class OtherWidget(forms.TextInput):
...     class Media:
...         js = ('whizbang.js',)
>>> w1 = CalendarWidget()
>>> w2 = OtherWidget()
>>> print w1.media + w2.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>
フォームのメディア

メディアファイル定義を持てるのはウィジェットだけではありません。フォームに もまた、メディアを定義できます。フォームのメディアファイル定義には、ウィジェ ットと同じ規則が適用されます。すなわち、静的・動的な宣言ができ、宣言内容に は絶対・相対パスの解釈や継承といった規則がウィジェット同様に当てはまります。

どちらにメディア情報を定義したかに関係なく、フォームオブジェクトには 必ず media プロパティがあります。このプロパティのデフォルト値は、 フォームを構成する全てのウィジェットのメディアファイル定義を加算したもので す:

>>> class ContactForm(forms.Form):
...     date = DateField(widget=CalendarWidget)
...     name = CharField(max_length=40, widget=OtherWidget)

>>> f = ContactForm()
>>> f.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>

フォーム固有のメディア宣言を付加したい場合、例えば、フォームのレイアウトを 決める CSS を指定したい場合には、以下のようにメディア定義を追加します:

>>> class ContactForm(forms.Form):
...     date = DateField(widget=CalendarWidget)
...     name = CharField(max_length=40, widget=OtherWidget)
...
...     class Media:
...         css = {
...             'all': ('layout.css',)
...         }
>>> f = ContactForm()
>>> f.media
<link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" />
<link href="http://media.example.com/layout.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
<script type="text/javascript" src="http://media.example.com/actions.js"></script>
<script type="text/javascript" src="http://media.example.com/whizbang.js"></script>

See also

フォーム API リファレンス
フォームフィールド、フォームウィジェット、フォームやフィールドのバリ デーションを含むすべてのAPIリファレンスをカバーしています。

Django テンプレート言語

revision-up-to:17821 (1.4)

このドキュメントについて

このドキュメントでは、Django テンプレートシステムの文法について説明して います。技術的な観点からのテンプレートシステムの仕組みや拡張方法に関す る説明は、 Python プログラマのための Django テンプレート言語ガイド を参照してください。

Django のテンプレート言語は、釣合いの取れたパワーと簡便さを実現するように、 また HTML を扱いなれた人にとっては快適になるように設計されています。 SmartyCheetahTemplate のようなテキストベースのテンプレート言語を経験 したことがあるなら、 Django のテンプレートはしっくりくるはずです。

設計哲学

プログラミングの知識があったり、 PHP のようなプログラムコードを直接 HTML に混ぜ込む言語を使ったことがあるなら、 Django のテンプレートシステ ムが単に HTML に Python を埋め込んだものでないことに疑問を持つでしょう。 しかし、これは設計上意図して決まっていることです。テンプレートシステム はプレゼンテーション層を表現するためのもので、プログラムロジックではな いのです。

Django のテンプレートシステムは、プログラムの構成部品に似たタグ、例えば ブールテストのための if タグやループ処理のための for タグを備えています。しかし、これらのタグは単に同じ意味の Python コードとして実行されるのではなく、テンプレートシステムは Python の式を解釈実行したりはしません。テンプレートシステムがサポートしている のは、以下で定義されているデフォルトのタグ、フィルタおよびその構文だけ です (もちろん、必要に応じてテンプレート言語を 拡張する のは可能です)。

テンプレート

テンプレートは単なるテキストファイルでできています。 テンプレートはあらゆる テキストベースのデータ形式 (HTML, XML, CSV など) を生成できます。

テンプレートには、テンプレートを処理する際に実際の値に置き換えられる 変数 (variable) と、テンプレート上でロジックを制御する タグ (tag) が入っています。

以下に示すのは、基本的な項目をいくつか組み込んだ最小限のテンプレートです。 各項目についてはこのドキュメントの後の部分で詳しく説明します:

{% extends "base_generic.html" %}

{% block title %}{{ section.title }}{% endblock %}

{% block content %}
<h1>{{ section.title }}</h1>

{% for story in story_list %}
<h2>
  <a href="{{ story.get_absolute_url }}">
    {{ story.headline|upper }}
  </a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}

設計哲学

なぜ (Zope における TAL のような) XML ベースのテキストベースのテンプレー トではなく、テキストベースのテンプレートを使うのでしょうか ? それは、 Django のテンプレート言語を XML/HTML テンプレート以外にも使いたいと考え ているからです。 World Online では、email や JavaScript、 CSV にテンプ レートを使っています。テンプレートはテキストベースの形式なら何にでも使 えるのです。

そう、もう一つあります: 人間に XML を編集させるなんて、サディスティック でしかありません!

変数

変数 (variable) は {{ variable }} のような形式になります。テンプレート エンジンが変数名を見つけると、変数を評価して値を置き換えたものを出力します。 変数名は英字と数字とアンダースコア("_")の組み合わせです。ドット(".") も変数のなかに出現します、ですがそれには特別な意味があり、それは下記に示すと おりです。 大切なことは、 変数名の中にスペースを入れたり句読点を含まないことです

変数の属性値にアクセスするには、ドット (.) 表記を使います。

舞台裏

技術的には、テンプレートシステムが dot を見つけた場合、以下の順で値の評 価を試みます:

  • 辞書の照合 (lookup)
  • 属性の照合
  • メソッドの呼び出し
  • リストをインデクス指定して照合

上の例では、 {{ section.title }}section オブジェクトの title 属性に置き換えられます。

実在しない変数を使うと、テンプレートシステムは TEMPLATE_STRING_IF_INVALID の設定値を挿入します。デフォルトの値は '' (空文字列) です。

フィルタ

変数を表示するために手を加えたい場合には フィルタ (filter) を使います。

フィルタは {{ name|lower }} のように書きます。この例では、変数 {{ name }} の値は lower フィルタ、すなわち文字を小文字に変換するフィルタ を通してから表示します。フィルタの適用は (|) で表します。

フィルタは「連鎖 (chain)」できます。フィルタを連鎖させると、あるフィルタか らの出力を別のフィルタに渡せます。例えば、 {{ text|escape|linebreaks }} は、テキストの内容をエスケープして、改行を <p> タグに置き換える時の慣用 句としてよく使われています。

フィルタによっては引数をとります。フィルタの引数は {{ bio|truncatewords:"30" }} のような形式で表します。この例では、変数 bio の最初の 30 語を表示します。

フィルタの引数にスペースが入っている場合は、二重引用符で囲ってください。例 えば、カンマとスペースでリストを結合するには {{ list|join:", " }} のようにします。

組み込みフィルタリファレンス では、 全ての組み込みフィルタについて説明しています。 組み込みフィルタでできることを知ってもらうために、よく使うテンプレートフィ ルタをいくつか挙げましょう:

default

入力が空や False の場合、引数に指定したデフォルト値を使いま す。そうでなければ、入力をそのまま使います

使用例:

{{ value|default:"nothing" }}

value が存在しなかったり空だったりすると、 “nothing” を出力 します。

length

入力値の長さを返します。文字列とリストいずれにも作用します。

使用例:

{{ value|length }}

value['a', 'b', 'c', 'd'] なら、 4 を出力します。

striptags

[X]HTML タグを全てはぎとります。

使用例:

{{ value|striptags }}

value"<b>Joel</b> <button>is</button> a <span>slug</span>" なら、 "Joel is a slug" を出力します。

これらはほんの一部に過ぎません。全ての組み込みフィルタの一覧は 組み込みフィルタリファレンス を参照 してください。

テンプレートフィルタは自作できます。 テンプレートタグやフィルタを自作する を参照してください。

See also

Django のアドミンインターフェイスはすべてのテンプレートタグと 利用可能なフィルタに関してはこちらのサイトで完全な参照を得られます。 /ref/contrib/admin/admindocs

タグ

タグは {% tag %} のように書きます。タグの考え方は、変数よりもやや複雑 です。出力されるテキストを生成するものもありますし、ループやロジックを実行 して、処理の流れを制御するものもあります。また、外部の情報を取り込んで、後 に出て来る変数から使えるようにするものもあります。

タグによっては、開始タグと終了タグ ({% tag %} ... tag contents ... {% endtag %}) を必要とするものがありま す。

Django にはたくさんの組み込みタグが付属しています。組み込みタグの解説は 組み込みタグリファレンス にあります。 組み込みタグでできることを知ってもらうために、よく使うタグをいくつか挙げま しょう:

for

アレイの各要素に渡ってループします。例えば、アスリート (athlete) の リストを athlete_list で渡して表示するには、以下のようにします:

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>
if and else

変数を評価して、値が「真」 (値が存在して、空の配列でなく、ブール値 が偽でない) の場合、ブロック内のコンテンツを出力します:

{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% else %}
    No athletes.
{% endif %}

上の例では、 athlete_list が空でなければ、アスリートの人数を {{ athlete_list|length }} で表示します。

if タグの中で、他のフィルターや変数を使うにはを使うこともできます。:

{% if athlete_list|length > 1 %}
     Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
     Athlete: {{ athlete_list.0.name }}
{% endif %}
block and extends
テンプレートの継承 は、テンプレート内の”繰り返し” を減らすことができます。

これらはほんの一部に過ぎません。全ての組み込みフィルタの一覧は 組み込みタグリファレンス を参照してく ださい。

テンプレートタグは自作できます。 テンプレートタグやフィルタを自作する を参照してください。

See also

Djangoのアドミンインターフェイスはすべてのテンプレートタグと 利用可能なフィルタに関してはこちらのサイトで完全な参照を得られます。 /ref/contrib/admin/admindocs

コメント

テンプレート中で行内の一部をコメントアウトするには、コメント構文 {# #} を使います。

例えば、以下のテンプレートをレンダすると 'hello' になります:

{# greeting #}hello

コメント内には任意のテンプレートコードを入れられます。コメント内の テンプレートコードが無効なものであってもエラーにはなりません:

{# {% if foo %}bar{% else %} #}

この構文を使えるのは、一行のコメントの場合だけです ({##} の間に は改行を入れられません)。複数行のコメントアウトを行いたければ、後述の comment タグを使ってください。

テンプレートの継承

Django のテンプレートエンジンにおいて、テンプレートの継承 (inheritance) は 最もパワフル – かつ最も難解 – な部分です。テンプレートの継承は、自分のサ イトで共通に使われる全ての要素の入った、ベースとなる「骨組みの」テンプレー トを作っておき、その中に子のテンプレートでオーバライドできる ブロック(block) を定義できます。

テンプレートの継承を理解するには、まず例を挙げるのが一番でしょう:

<!DOCTYPE html>
 <html lang="ja">
  <head>
      <link rel="stylesheet" href="style.css" />
      <title>{% block title %}My amazing site{% endblock %}</title>
  </head>

  <body>
      <div id="sidebar">
          {% block sidebar %}
          <ul>
              <li><a href="/">Home</a></li>
              <li><a href="/blog/">Blog</a></li>
          </ul>
          {% endblock %}
      </div>

      <div id="content">
          {% block content %}{% endblock %}
      </div>
  </body>
  </html>

このテンプレートは、単純な 2 カラム形式のページで使うような HTML のスケルト ンドキュメントです。これを base.html と呼びましょう。空のブロックをコン テンツで埋めるのは「子 (child)」のテンプレートの仕事です。

この例では、 block タグを使って 3 つのブロックを定義し、子テンプ レートが値を埋められるようにしています。 block タグの役割は、テンプレー ト中のタグで囲まれた部分を子テンプレートでオーバライドできることをテンプレー トエンジンに知らせることにあります。

子テンプレートは以下のようになります:

{% extends "base.html" %}

{% block title %}My amazing blog{% endblock %}

{% block content %}
{% for entry in blog_entries %}
    <h2>{{ entry.title }}</h2>
    <p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

extends タグが継承のカギです。このタグはテンプレートエンジンに対 して、自分自身が他のテンプレートを拡張 (extend) していることを教えます。テ ンプレートシステムがこのテンプレートを処理する際、システムはまず親となるテ ンプレート – ここでは “base.html” を探します。

さて、この時点で、テンプレートエンジンは base.html 内に三箇所の block が定義されていることに気づき、これらのブロックを子テンプレー トの該当するブロックで置き換えます。 blog_entries の値に応じて、出力は 以下のようになります:

 <!DOCTYPE html>
     <html lang="ja">
     <head>
    <link rel="stylesheet" href="style.css" />
    <title>My amazing blog</title>
</head>

<body>
    <div id="sidebar">
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
    </div>

    <div id="content">
        <h2>Entry one</h2>
        <p>This is my first entry.</p>

        <h2>Entry two</h2>
        <p>This is my second entry.</p>
    </div>
</body>
</html>

子テンプレートには sidebar ブロックが定義されていないので、親テンプレー トの値がそのまま使われます。親テンプレートの {% block %} タグの内容は、 常にフォールバックの値として使われます。

テンプレートの継承は必要に応じて何段階にもできます。継承を使うよくある場合 の一つに、以下のような三段階のアプローチがあります:

  • サイトの主なルック & フィールを決める base.html テンプレートを作 成します。
  • サイトの各「セクション」ごとに base_SECTIONNAME.html テンプレート を作成します。たとえば、 base_news.html , base_sports.html と いった具合です。これらのテンプレートでは base.html を拡張して、セ クション固有のスタイルやデザインを取り込んでおきます。
  • ニュース記事やブログエントリといった各種ページ用の個々のテンプレート を作成します。これらのテンプレートでは適切なセクションテンプレートを 拡張します。

このようなアプローチを取れば、コードの最利用性を最大限に高め、セクション毎 のナビゲーションのような項目を簡単に共通のコンテンツ領域に追加できます。

継承を扱うときの小技をいくつか挙げておきます:

  • テンプレートで {% extends %} を使う場合は、テンプレート中の最初の テンプレートタグにせねばなりません。さもなければテンプレート継承はう まく動作しません。

  • ベースのテンプレートで {% block %} を多用すればするほど、よりよい テンプレートになります。子テンプレートは親テンプレートのブロックを必 ずしも全て定義しなくてもよいことを思い出して下さい。ブロックをたくさ ん用意しておき、適切なデフォルト値を入れておいて、子テンプレートで必 要な値だけを再定義すればよいのです。フックは少ないよりも沢山ある方が よいのです。

  • 同じような内容を含むテンプレートをいくつも作っていることに気づいたら、 それはすなわちその内容を親テンプレートの {% block %} に入れるべき だということです。

  • 親テンプレートのブロックに入っているコンテンツを取り出す必要がある場 合、 {{ block.super }} とするとうまくいきます。親テンプレートのブ ロックをオーバライドするのではなく、内容を追加したい場合に便利です。 {{ block.super }} で挿入されたデータは、通常、親テンプレートで 既にエスケープされているので、自動的にエスケープされません (HTML の自動エスケープ を参照)。

  • 可読性を高めるために、例えば以下のように、 {% endblock %} にブロッ クの 名前 を指定できます:

    {% block content %}
    ...
    {% endblock content %}
    

    大きなテンプレートの編集で、どこで {% block %} タグが閉じているか 探すのに便利です。

最後に、同じテンプレート中に同じ名前の block を複数定義できないこ とに注意して下さい。この制限は、ブロックタグが「双方向」に作用するため、す なわち、あるブロックタグは何らかの値を埋めるための穴であるだけでなく、穴を 埋める 親テンプレートの コンテンツも定義しているために存在しています。同 じ名前の block が一つのテンプレート内に複数あると、そのテンプレー トの親テンプレートは、該当するブロックの内容を子テンプレートのどの block 設定で置き換えればよいのか分からなくなってしまいます。

HTML の自動エスケープ

テンプレートから HTML を生成するときには、変数内の文字が HTML のレンダリン グ結果を壊してしまうというリスクが常に付きまといます。例えば、以下のような テンプレートフラグメントを考えてみましょう:

こんにちは {{ name }} さん

一件、このコードはユーザ名を表示するだけの無害なものに見えますが、名前を以 下のような値にすると、何が起こるでしょう:

<script>alert('hello')</script>

テンプレートは以下のようにレンダされます:

Hello, <script>alert('hello')</script>

その結果、 JavaScript の警告ボックスを表示できてしまいます!

同様に、名前に以下のようにして '<' 文字をいれると同でしょう:

..code-block::html

   <b>username

レンダ結果は以下のようになります:

Hello, <b>username

これで、以降のWebページは全部ボールド表示になってしまいます!

言うまでもなく、ユーザが入力したデータは盲目に信頼してはならず、直接 Web ペー ジに挿入すべきでもありません。悪意のあるユーザはこの手の穴を使って悪さをす るものです。こうしたセキュリティホールは、 クロスサイトスクリプティング (XSS) 攻撃と呼ばれています。

クロスサイトスクリプティングを防ぐには、二つの方法があります:

  • まず、信頼できない変数は全て (後述の) escape フィルタを通します。 このフィルタは危険を及ぼす可能性のある HTML 文字を無害な文字に変換し ます。 Django では、初期の数年はこの方法をデフォルトとして採用してい ましたが、ユーザ、すなわち開発者やテンプレートの作者に、全てをエスケー プするよう気配りする負荷をかけるという問題がありました。
  • もう一つは、自動 HTML エスケープを使うというものです。この節の後半で は、自動エスケープのからくりについて述べています。

開発版の Django では、デフォルトの設定として、全てのテンプレートは変数タグ を自動的にエスケープします。具体的には、以下の 5 つの文字がエスケープされます:

  • <"&lt;" に変換されます。
  • >"&gt;" に変換されます。
  • "'" (クオート) は '&#39;' に変換されます。
  • '"' (二重クオート) は '&quot;' に変換されます。
  • "&""&amp;" に変換されます。

この動作はデフォルトで適用されていることを強調しておきます。Django テンプレー トシステムを使っているかぎり、エスケープに関する問題からは守られているのです。

自動エスケープを切るには

サイト単位やテンプレート単位、変数単位でデータの自動エスケープを切るには、 いくつかの方法があります。

どんなときに、自動エスケープを切る必要があるのでしょうか。テンプレート変数 の中には、生の HTML としてレンダするように 意図された データがあります。 そうした場合にはコンテンツがエスケープされてほしくはないでしょう。例えば、 データベースに HTML を保存していて、テンプレートに直接埋め込みたい場合を考 えてみましょう。また、 Django のテンプレートシステムを使って、 HTML 以外 のデータ、例えば電子メールメッセージなどを生成したい場合がそうです。

変数単位の制御

変数個々に自動エスケープを無効にするには、 safe フィルタを使います:

エスケープされる: {{ data }}
エスケープされない: {{ data|safe }}

safe という言葉を、 これ以上エスケープしないよう保護(safe)する とか、 HTML として解釈しても安全(safe)である という意味だと考えてください。 例えば、 data'<b>' が入っていた場合、出力は以下のようになります:

エスケープされる: &lt;b&gt;
エスケープされない: <b>
テンプレートブロック単位の制御

テンプレートで自動エスケープを制御するには、テンプレート (または テンプレートの一部) を、以下のように autoescape タグで囲みます:

{% autoescape off %}
    こんにちは {{ name }} さん
{% endautoescape %}

autoescape タグは、 on または off を引数にとります。 テンプレートのある範囲を自動エスケープして、さらにその一部で自動エスケープ を切りたい場合には、以下のように入れ子にできます:

Auto-escaping is on by default. Hello {{ name }}

{% autoescape off %}
    This will not be auto-escaped: {{ data }}.

    Nor this: {{ other_data }}
    {% autoescape on %}
        Auto-escaping applies again: {{ name }}
    {% endautoescape %}
{% endautoescape %}

自動エスケープのタグは、他のブロックタグと同様、タグを設定したテンプレート を継承している他のテンプレートや、 include で取り込んだテンプレートでも 有効です。例えば:

# base.html

{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}


# child.html

{% extends "base.html" %}
{% block title %}This & that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}

自動エスケープがベースのテンプレートで無効化されているので、子テンプレート でも自動エスケープは無効化されます。結果として、 greeting 変数の値が <b>Hello!</b> の時には以下の HTML がレンダされます:

<h1>This & that</h1>
<b>Hello!</b>
注意点

一般に、テンプレートの作者は自動エスケープをあまり意識するべきではありませ ん。 Python サイドの開発者 (ビューやカスタムフィルタ) の作者が、どのデータ をエスケープすべきでないかを考え、データを適切にマークして、テンプレートに うまく表示されるようにすべきなのです。

テンプレートを作成していて、自動エスケープが有効な環境で使われるかどうか分 からないような場合には、エスケープの必要な変数全てに escape フィルタを 追加してください。自動エスケープがオンの場合、 escape フィルタがデータ を 二重にエスケープする ような危険性はありません。 escape フィルタは 変数の自動エスケープには影響しないのです。

文字列リテラルと自動エスケープ

先に説明したように、フィルタの引数は文字列であってもかまいません:

{{ data|default:"文字列リテラルだよ" }}

文字列リテラルは、自動エスケープ されずに テンプレート内に挿入されます。 文字列リテラルは、 safe フィルタを通して渡されたかのように振る舞います。 このような仕様になっているのは、テンプレートの作者が文字列リテラルがどのよ うに処理されるかを制御でき、テンプレートを書くときにテキストが正しくエスケー プされるよう配慮できるからです。

従って、以下のようにテンプレートを書いてください:

{{ data|default:"3 &lt; 2" }}

以下のようにはしないでください:

{{ data|default:"3 < 2" }}  <-- ダメ。こんな書き方をしてはいけません

引数にリテラルを使っても、変数自体に対するエスケープの挙動には影響しません。 変数はテンプレート作者の制御の範囲外にあり、自動的にエスケープされます。

メソッドの呼び出しにアクセスする

オブジェクトに備え付けられたほとんどのメソッドの呼び出しはテンプレートの 中からでも使うことができます。これは、テンプレートがただのクラスの属性( フィールド名のように)とビューでの変数を通したアクセス以上のものであると いうことです。例えば、Djangoでの例ではORMは “entry_set” 文法を提供していて、Foreign キーに関係するオブジェクトの集合を見つけることができます。従って、 “comment”と呼ばれるモデルが”task”というモデルとフォーリンキーで繋がってい るとき、ループを用いることで”task”を通して全ての”comment”オブジェクトにア クセスすることができます。ちょうど、こんな風に。:

{% for comment in task.comment_set.all %}
    {{ comment }}
{% endfor %}

似たように、 QuerySetscount() メソ ッドというオブジェクトの個数を数えるために提供しています。従って、タスク と関連する全てのコメントの個数を取得することも出来ます。:

{{ task.comment_set.all.count }}

そして、もちろん簡単にモデル自身で定義されたメソッドにもアクセスすること ができます:

# モデル内で
class Task(models.Model):
    def foo(self):
        return "bar"

# テンプレート内で
{{ task.foo }}

なぜなら、Django ではテンプレートのプログラム的な使用を厳しく制限してい て、テンプレートの中からメソッドを呼び出すことは出来ないからです。データは ビューの中で作られ、テンプレートでは表示のためだけに使うべきだからです。

カスタムタグとカスタムフィルタのライブラリ

アプリケーションによっては、カスタムのタグやフィルタライブラリを提供してい ます。こうしたタグをテンプレートで使いたい場合、 load タグを使い ます:

{% load comments %}

{% comment_form for blogs.entries entry.id with is_public yes %}

上の例では、 load タグは comments という名前のタグライブラリを読み 込んでいます。このタグライブラリを読み込むと、 comment_form タグを使え るようになります。カスタムライブラリのリストを探したければ、自分のサイトの admin でドキュメント置場を参照してください。

load タグは複数のライブラリ名を同時に読み込めます。ライブラリ名は スペースで区切って下さい:

{% load comments i18n %}

カスタムのテンプレートライブラリを作成する方法は テンプレートタグやフィルタを自作する を参照してください。

カスタムのライブラリとテンプレートの継承

カスタムタグやフィルタライブラリをロードした場合、タグやフィルタは現在のテ ンプレートだけで利用でき、テンプレート継承パス上の親テンプレートや子テンプ レートでは利用できません。

例えば、 foo.html{% load comments %} というタグを入れておいても、 子テンプレート ({% extends "foo.html" %} を使っているテンプレート) で comments という名前のテンプレートタグやフィルタを使えるわけでは ありません 。子テンプレート側で独自に {% load comments %} を入れてお く必要があります。

これはメンテナンス性を高めるための仕様です。

クラスベース汎用ビュー

リリースノートを参照してください

Note

Django 1.3 の前は、汎用ビューは関数として実装されていました。ここで述べる クラスベース汎用ビューが採用されたので、関数ベース汎用ビューは廃止されま した。

関数ベース汎用ビューの詳細は トピックガイド詳細リファレンス を参照してください。

Web アプリケーションの作成は、同じパターンを何度も何度も繰り返し書くことに なるため、退屈なものです。 Django は、こうした単調作業をモデルやテンプレー トのレイヤで軽減しようとしていますが、 Web 開発者はビューレベルでも退屈さを 感じています。

Django の 汎用ビュー (generic views) はその苦労を無くすために開発されま した。ビューの開発時に見かける、特定の共通するイディオムとパターンを汎用ビュー という形で抽象化しています。余計なコードを書かずによく定義されるビューを素早く 実装できます。

我々はオブジェクトのリスト表示などの、ありふれたタスクを知っています。 任意の オブジェクトをリスト表示するコードも提供できます。その上、リスト表示させたい モデルは URLconf に追加の引数として渡せます。

Django の汎用ビューで以下のようなことができます:

  • 別のページへリダイレクトし、与えられたテンプレートをレンダリングするような、 よくある簡単なタスクの処理。
  • リストと単一オブジェクトの詳細ページを表示。カンファレンスを管理するアプリケー ションを作っているなら、 TalkListViewRegisteredUserListView に リストビューを、単一の発表に関するページに詳細ビューが使えます。
  • 日付ベースのオブジェクトを年/月/日のアーカイブで表示。詳細と最新ページで 関連付けて表示します。 Django のブログ の年月日ごとのアーカ イブはこれで作られています。
  • 認証あり、または無しでユーザにオブジェクトを生成、更新、削除を許可。

汎用ビューは開発者が遭遇する、よくあるタスクを果たすための簡単なインターフェース を提供しています。

簡単な使い方

クラスベース汎用ビュー (と、 Django が提供する基底クラスを継承したすべてのクラス ベースビュー) は、 2 つの方法で設定します。サブクラス化か、引数を直接 URLconf に 渡すとできます。

クラスベースビューをサブクラス化するとき、引数 (template_name など) やメソッ ド (get_context_data など) をオバーライドします。そうして新しい値やメソッド を提供できます。ここで、テンプレート about.html を単に表示するビューを例と します。 Django の汎用ビュー TemplateView をサブクラス化して、テンプレート名をオーバーライドするとできます:

# some_app/views.py
from django.views.generic import TemplateView

class AboutView(TemplateView):
    template_name = "about.html"

あとは、このビューを URLconf に追記するだけです。クラスベースビュー自体はクラス なので、 URLconf では代わりに as_view メソッドを使います。このメソッドが、 クラスベースビューの入り口になります:

# urls.py
from django.conf.urls import patterns, url, include
from some_app.views import AboutView

urlpatterns = patterns('',
    (r'^about/', AboutView.as_view()),
)

クラスベースビューで簡単な引数を少し変えるだけなら、 as_view を呼び出す ときの引数としても渡せます:

from django.conf.urls import patterns, url, include
from django.views.generic import TemplateView

urlpatterns = patterns('',
    (r'^about/', TemplateView.as_view(template_name="about.html")),
)

同じオーバーライドのパターンが url 属性で使えます。 urlRedirectView などのシンプルな 汎用ビューで使われています。

オブジェクトの汎用ビュー

TemplateView は確かに便利です。しかし、 Django の汎用ビューが真価を発揮するのは、データベースの内容についてビューを 提示するときです。驚くほど簡単にオブジェクトのリスト、詳細ビューを生成できる組み 込みの汎用ビューが、 Django には少数付属しています。それらはよくあるタスクだから です。

それでは汎用ビューの 1 つ、 “オブジェクトリスト (object list)” ビューを見てみま しょう。以下のようなモデルを使います:

# models.py
from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    class Meta:
        ordering = ["-name"]

    def __unicode__(self):
        return self.name

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField('Author')
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

全ての出版社 (publisher) のリストページを構築するため、以下のような URLconf を 使います:

from django.conf.urls import patterns, url, include
from django.views.generic import ListView
from books.models import Publisher

urlpatterns = patterns('',
    (r'^publishers/$', ListView.as_view(
        model=Publisher,
    )),
)

書くべき Python コードは以上です。しかしテンプレートも書く必要があります。 as_view への引数に template_name キーを含めることにより、どのテンプレートを 使用するべきであるかビューに明示的に伝えることができます。明示的なテンプレートが ない場合 Django は、オブジェクトの名前からテンプレートを推論します。今回の場合、 推論されるテンプレートは "books/publisher_list.html" となるでしょう。 “books” という部分はモデルを定義しているアプリケーションの名前からきています。 “publisher” は単にモデル名が lowercase になったものです。

Note

ここで、 TEMPLATE_LOADERSdjango.template.loaders.app_directories.Loader テンプレートローダを 有効にすると、テンプレートは以下の場所になります:

/path/to/project/books/templates/books/publisher_list.html

このテンプレートは、 object_list 変数を含むコンテキストに対してレンダリング されます。 object_list はすべての出版社オブジェクトからなります。とても 単純なテンプレートにするなら以下のようになるでしょう:

{% extends "base.html" %}

{% block content %}
    <h2>Publishers</h2>
    <ul>
        {% for publisher in object_list %}
            <li>{{ publisher.name }}</li>
        {% endfor %}
    </ul>
{% endblock %}

本当にこれだけです。汎用ビューに渡される “info” 辞書を変更することで、クールな 機能をすべて使用できます。汎用ビューとオプションの詳細は generic views reference に記されています。この ドキュメントの残りでは、よくある汎用ビューのカスタマイズ、拡張の方法を記して います。

汎用ビューの拡張

疑いようも無く、汎用ビューを使用すると開発スピードは大幅に上がります。しかし多 くのプロジェクトでは、汎用ビューでは物足りないときがあります。確かに、新米の Django 開発者からくる質問で典型的なのは、汎用ビューをより幅広い状況で扱うことに ついてです。

1.3 リリース以前は単なるビュー関数で、困惑させるようなオプション群を備えていま した。これが汎用ビューを設計し直した理由の 1 つです。より良い汎用ビューの拡張 方法は、汎用ビューをサブクラス化して、属性とメソッドをオーバーライドすること です。 URLconf で大量の設定を渡すことではありません。

“フレンドリー” なテンプレートコンテキストを作る

サンプルの出版社リストテンプレートでは、 object_list 変数にすべての出版社 オブジェクトが格納されています。現状でもうまく動作しますが、テンプレートの作者に とって “フレンドリー” ではありません。ここでテンプレート作者には、出版社オブジェ クトを扱うことだけを知らせるべきです。

モデルオブジェクトを扱っているなら、これはもう完了しています。オブジェクトか クエリセットを扱っているとき、 Django は表示されているオブジェクトの 冗長名(verbose name) を使って、コンテキストを追加します。オブジェクトのリストの 場合は、複数の冗長名を使います。これはデフォルトの object_list 変数に加えて 提供されますが、同じデータが含まれています。

冗長名 (または複数の冗長名) がまだマッチしていない場合は、手動でコンテキスト変数 の名前を設定することができます。汎用ビューの context_object_name 属性で使用 するコンテキスト変数を明記できます。この例では簡単な変更だけで良いので、 URLconf でオーバーライドします:

urlpatterns = patterns('',
    (r'^publishers/$', ListView.as_view(
        model=Publisher,
        context_object_name="publisher_list",
    )),
)

便利な context_object_name を提供するのは常によいことです。テンプレートの デザインを担当する同僚は、あなたに感謝することでしょう。

追加のコンテキスト

汎用ビューで提供されるもの以上に、追加の情報を提示したいときがあります。例えば、 各出版社の詳細ページに、書籍 (book) の全リストを表示したいときなどです。汎用 ビュー DetailView はコンテキストに出版社 オブジェクトを提供していますが、テンプレートに追加の情報を与えることはできなさ そうです。

しかしそうではありません。 DetailView を サブクラス化して、 get_context_data メソッドに独自の実装を提供できます。 DetailView のデフォルトの実装では、 表示されているオブジェクトをテンプレートに追加します。より多く表示するためには オーバーライドします:

from django.views.generic import DetailView
from books.models import Publisher, Book

class PublisherDetailView(DetailView):

    context_object_name = "publisher"
    model = Publisher

    def get_context_data(self, **kwargs):
        # コンテキストを取得するために、先に基底クラスの機能を呼び出します。
        context = super(PublisherDetailView, self).get_context_data(**kwargs)
        # 全書籍のクエリセットを追加します。
        context['book_list'] = Book.objects.all()
        return context
オブジェクトのサブセットを表示

さて、ずっと使ってきた model 引数を詳しく見ていきましょう。 model 引数 は、ビューが操作するデータベースモデルを指定します。単一のオブジェクト、もしくは 複数のオブジェクトを操る、すべての汎用ビューで利用可能です。しかし model 引数以外にも、ビューで操作するオブジェクトを指定する方法があります。 queryset 引数を使って、オブジェクトのリストを指定することができます:

from django.views.generic import DetailView
from books.models import Publisher, Book

class PublisherDetailView(DetailView):

    context_object_name = "publisher"
    queryset = Publisher.objects.all()

model = Publisher という書き方は queryset = Publisher.objects.all() を 単に略記したものです。 queryset はフィルタされたオブジェクトのリストを定義 するものです。これを使ってビューにあるオブジェクトをより特定することができます。 QuerySet については クエリを生成する を参照してください。 より詳細には クラスベースビューのリファレンス を参照してください。

簡単な例として、出版日 (publication date) 順の書籍のリストを最新のものから取得 してみます:

urlpatterns = patterns('',
    (r'^publishers/$', ListView.as_view(
        queryset=Publisher.objects.all(),
        context_object_name="publisher_list",
    )),
    (r'^books/$', ListView.as_view(
        queryset=Book.objects.order_by("-publication_date"),
        context_object_name="book_list",
    )),
)

かなり簡単な例ですが、うまく考えを表しています。もちろんオブジェクトを再整理する 以上のことをしたいでしょう。特定の出版社についての書籍を渡したい場合も、同じテク ニックが使えます (URLconf で引数を渡すのでなくサブクラス化を使う例はこちら):

from django.views.generic import ListView
from books.models import Book

class AcmeBookListView(ListView):

    context_object_name = "book_list"
    queryset = Book.objects.filter(publisher__name="Acme Publishing")
    template_name = "books/acme_list.html"

フィルタされた queryset 以外に、テンプレート名を指定しています。そうしな いと、汎用ビューは同じテンプレートを “ありきたりな” オブジェクトリストとして使い 回します。たぶん期待とは違うことでしょう。

これは、ある出版社固有の書籍を扱ううえでエレガントな方法ではありません。他の 出版社のページを追加したいなら、 URLconf に手動で追記する必要があるからです。 追記したうちいくつかは不当 (unreasonable) になるでしょう。詳しくは次のセクション で扱います。

Note

/books/acme/ をリクエストするの際に 404 になったときは、 ‘ACME Publishing’ という名の Publisher が実際に存在するか確かめてください。 こういったケースに備えて、汎用ビューは allow_empty というパラメータを 持っています。詳細は クラスベースビューのリファレンス を参照して ください。

動的フィルタリング

他によくあるニーズは、 URL のキーでオブジェクトをフィルタしてから、オブジェクト をリストページに渡すことです。すでに出版社名は URLconf にハードコードしてい ますが、ある任意の出版社について書籍をすべて表示するビューを書きたいなら、どう しますか?

扱いやすいように、 ListViewget_queryset() メソッドを持って おり、オーバーライドできます。以前は queryset 属性の値を返すだけでしたが、 今ではより多くのロジックを追加できます。

クラスベースビューが呼ばれたとき、有用なオブジェクトは self に格納されていま す。これはこの仕事するうえで重要です。リクエスト (self.request) と同様に、 URLconf でキャプチャされた、位置指定引数 (self.args) とキーワード引数 (self.kwargs) を含みます。

URLconf は以下のようになり、キャプチャ用の正規表現グループ (captured group) がつきます:

from books.views import PublisherBookListView

urlpatterns = patterns('',
    (r'^books/(\w+)/$', PublisherBookListView.as_view()),
)

次は PublisherBookListView ビュー自身を書きます:

from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book, Publisher

class PublisherBookListView(ListView):

    context_object_name = "book_list"
    template_name = "books/books_by_publisher.html"

    def get_queryset(self):
        publisher = get_object_or_404(Publisher, name__iexact=self.args[0])
        return Book.objects.filter(publisher=publisher)

見ての通り、クエリセットの選別 (selection) をするロジックを、とても簡単に追加 できます。 self.request.user を使ってカレントユーザをフィルタするなど、他の 複雑なロジックも追加できます。

コンテキストにも同時に、出版社オブジェクトを追加できます。なのでテンプレートで 使えます:

class PublisherBookListView(ListView):

    context_object_name = "book_list"
    template_name = "books/books_by_publisher.html"

    def get_queryset(self):
        self.publisher = get_object_or_404(Publisher, name__iexact=self.args[0])
        return Book.objects.filter(publisher=self.publisher)

    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super(PublisherBookListView, self).get_context_data(**kwargs)
        # Add in the publisher
        context['publisher'] = self.publisher
        return context
追加の処理をさせる

最後の共通パターンは、汎用ビューを呼び出す前か後に、追加の処理をさせることです。

Author オブジェクト中に last_accessed フィールドがあるとします。著者 (author) オブジェクトが最後に問い合わせされた時刻を記録します:

# models.py

class Author(models.Model):
    salutation = models.CharField(max_length=10)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()
    headshot = models.ImageField(upload_to='/tmp')
    last_accessed = models.DateTimeField()

DetailView クラスはもちろん、このフィールドについては知りません。 しかし再び、このフィールドの更新を維持するためのカスタムビューを書けます。

初めに、カスタムビューを指定するために URLconf に著者の詳細に関する 1 行を追加 します:

from books.views import AuthorDetailView

urlpatterns = patterns('',
    #...
    (r'^authors/(?P<pk>\d+)/$', AuthorDetailView.as_view()),
)

ここで新しいビューを書きます。 get_object はオブジェクトを取得するメソッド なので、これをオーバーライドして呼び出しをラップします:

import datetime
from books.models import Author
from django.views.generic import DetailView
from django.shortcuts import get_object_or_404

class AuthorDetailView(DetailView):

    queryset = Author.objects.all()

    def get_object(self):
        # 基底クラスを呼び出す
        object = super(AuthorDetailView, self).get_object()
        # 最終アクセス日時を記録する
        object.last_accessed = datetime.datetime.now()
        object.save()
        # オブジェクトを返す
        return object

Note

実際には、このコードには books/author_detail.html テンプレートが必要 です。

Note

ここで URLconf は pk という正規表現グループを使います。この名前は DetailView がクエリセットをフィルタするときに使う、プライマリキーの値に なるデフォルト名です。

これを変更したいなら self.kwargs に新しい名前のパラメーターを追加して、 self.querysetget() でそれを使って呼び出す必要があります。

HTML 以上のこと

今のところ、レスポンスを生成するためのテンプレートレンダリングに焦点をあててい ました。しかし、これが汎用ビューにできることのすべてではありません。

どの汎用ビューも一連の Mixin から構成されています。それぞれの Mixin はビュー全体 の一部を提供します。そのうち例えば TemplateResponseMixin はテンプレートを使って HTML レスポンスをレンダリングするよう設計されています。様々な動作をする独自の Mixin を書くこともできます。

例えば、単純な JSON Mixin は以下のようになるでしょう:

from django import http
from django.utils import simplejson as json

class JSONResponseMixin(object):
    def render_to_response(self, context):
        "Returns a JSON response containing 'context' as payload"
        return self.get_json_response(self.convert_context_to_json(context))

    def get_json_response(self, content, **httpresponse_kwargs):
        "`HttpResponse` オブジェクトのコンストラクタ"
        return http.HttpResponse(content,
                                 content_type='application/json',
                                 **httpresponse_kwargs)

    def convert_context_to_json(self, context):
        "コンテクスト辞書を JSON オブジェクトに変換"
        # Note: これは *非常に (EXTREMELY)* 単純です。実際には、任意のオブジ
        # ェクト (Django のモデルインスタンスやクエリセットなど) を JSON に
        # シリアライズするには、より複雑な処理をする必要があります。
        return json.dumps(context)

これで、 JSON を返す DetailView を、 JSONResponseMixinBaseDetailView を Mixin して構築できます。 (テンプレートレンダリングの前に DetailView が Mixin されています):

class JSONDetailView(JSONResponseMixin, BaseDetailView):
    pass

その後このビューは、他の DetailView と 全く同じようにデプロイできます。 (レスポンスのフォーマットを除いて)

さらに大胆なことをするなら、 HTML 、 JSON コンテンツの 両方を 返せる DetailView サブクラスを作ることもでき ます。これはクエリ引数や HTTP ヘッダなど、いくつかの HTTP リクエストのプロパティ に依存します。 JSONResponseMixinSingleObjectTemplateResponseMixin を 合わせて、ユーザがリクエストしたレスポンスタイプに応じて、該当するサブクラスに 任せるために render_to_response() をオーバーライドします:

class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
    def render_to_response(self, context):
        # Look for a 'format=json' GET argument
        if self.request.GET.get('format','html') == 'json':
            return JSONResponseMixin.render_to_response(self, context)
        else:
            return SingleObjectTemplateResponseMixin.render_to_response(self, context)

JSONResponseMixinSingleObjectTemplateResponseMixinrender_to_response を、ローカルのそれでオーバーライドすることで、Python は メソッドのオーバーライドを解決します。

クラスベースビューのデコレート

クラスベースビューの拡張には、 Mixin 以外を使う方法があります。デコレータを 使う方法です。

URLconf のデコレート

クラスベースビューをデコレートする 1 番単純な方法は、 as_view() メソッドの結果をデコレートする ことです。ビューをデプロイした URLconf に置くのが 1 番楽でしょう:

from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView

from .views import VoteView

urlpatterns = patterns('',
    (r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
    (r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
)

このアプローチでは、インスタンスごとにデコレータを適用します。ビューのインス タンス全てをデコレートしたいなら、他のアプローチが必要です。

クラスのデコレート

クラスベースビューの全インスタンスをデコレートするには、クラスの定義そのものを デコレートします。クラスの dispatch() メソッドにデコレータを適用することでできます。

クラスメソッドは単なる関数とは違います。メソッドに関数デコレータを適用することは できません。関数デコレータをメソッドデコレータに変換する必要があります。 method_decorator デコレータは関数デコレータをメソッドデコレータに変換する ので、これをインスタンスメソッドで使えます。例を以下に示します:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

class ProtectedView(TemplateView):
    template_name = 'secret.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(ProtectedView, self).dispatch(*args, **kwargs)

この例で、 ProtectedView の全インスタンスはログインが必要になります。

Note

method_decorator*args**kwargs をパラメータとして、デコレ ートされたクラスメソッドに渡します。メソッドが互換性を持つパラメータのセット を許可していない場合は、 TypeError 例外が送出されます。

関数ベース汎用ビューを移行する

Django 1.2 のすべての 関数ベース汎用ビュー には類似 する クラスベース汎用ビュー が、 Django 1.3 に あります。関数ベース汎用ビューで提供されている機能セットは、クラスベース版で 再現可能です。

移行の仕方

汎用ビューを汎用クラスで置き換える

現行使われている関数ベース汎用ビューは、そのクラスベース版に置き換えるべきです:

旧 : 関数ベース汎用ビュー 新 : クラスベース汎用ビュー
django.views.generic.simple.direct_to_template django.views.generic.base.TemplateView
django.views.generic.simple.redirect_to django.views.generic.base.RedirectView
django.views.generic.list_detail.object_list django.views.generic.list.ListView
django.views.generic.list_detail.object_detail django.views.generic.detail.DetailView
django.views.generic.create_update.create_object django.views.generic.edit.CreateView
django.views.generic.create_update.update_object django.views.generic.edit.UpdateView
django.views.generic.create_update.delete_object django.views.generic.edit.DeleteView
django.views.generic.date_based.archive_index django.views.generic.dates.ArchiveIndexView
django.views.generic.date_based.archive_year django.views.generic.dates.YearArchiveView
django.views.generic.date_based.archive_month django.views.generic.dates.MonthArchiveView
django.views.generic.date_based.archive_week django.views.generic.dates.WeekArchiveView
django.views.generic.date_based.archive_day django.views.generic.dates.DayArchiveView
django.views.generic.date_based.archive_today django.views.generic.dates.TodayArchiveView
django.views.generic.date_based.object_detail django.views.generic.dates.DateDetailView

これを行うには、汎用ビュー関数への参照を、クラスベースビューを as_view() で インスタンス化したものに置き換えます。例えば、旧スタイルの direct_to_template は:

('^about/$', direct_to_template, {'template': 'about.html'})

TemplateView のインスタンスで置き換えられます:

('^about/$', TemplateView.as_view(template_name='about.html'))
direct_to_template ビューの template 引数

direct_to_template ビューの template 引数は template_name に改名され ました。他のビューとの一貫性を保つためです。

詳細ビューの object_id 引数

object_detail ビューの object_id 引数は、 DetailViewpk に改名されました。

template_object_name

template_object_namecontext_object_name に改名されました。コンテ キストデータが、テンプレートのレンダリング以外の目的 (例えば JSON 出力の追加) に使えるからです。

リストビューの _list サフィックス

関数ベースの ListView でコンテキスト変数名は、 template_object_name の値に _list サフィックスが追加されたものでした。クラスベースの ListView では、 context_object_name の値がそのまま使用されています。デフォルトの コンテキストオブジェクト名を生成するときにのみ、 '_list' サフィックスが適応 されます。

object_list ビューのコンテキストデータ

MultipleObjectMixin に提供されるコンテキスト は、 object_list のそれとは全く異なります。ほとんどのページネーション関連の 変数が、単一の page_obj オブジェクトに置き換えられています。以下の変数はもう 提供されていません:

  • first_on_page
  • has_next
  • has_previous
  • hits
  • last_on_page
  • next
  • page_range
  • page
  • pages
  • previous
  • results_per_page
extra_context

関数ベース汎用ビューは extra_context 引数を提供していました。これはレンダリ ング時に、コンテキストへ追加のオブジェクトを渡すために使われていました。

クラスベースビューは extra_context 引数を提供しません。代わりにビューを継承 して、 get_context_data() をオーバーライドします。例を挙げます:

class MyListView(ListView):
    def get_context_data(self, **kwargs):
        context = super(MyListView, self).get_context_data(**kwargs)
        context.update({
            'foo': 42,
            'bar': 37
        })
        return context
生成、更新ビューの post_save_redirect

生成、更新ビューの post_save_redirect は、 ModelFormMixinsuccess_url に改名 されました。

mimetype

いくつかの関数ベース汎用ビューは mimetype 引数を提供していました。これは レスポンスの MIME タイプを管理するために使われていました。

クラスベースビューは mimetype 引数を提供しません。代わりにビューを継承して TemplateResponseMixin.render_to_response() をオーバーライドします。 そして TemplateResponse コンストラクタの引数に渡します。例を挙げます:

class MyListView(ListView):
    def render_to_response(self, context, **kwargs):
        return super(MyListView, self).render_to_response(context,
                        content_type='application/json', **kwargs)
context_processors

いくつかの関数ベース汎用ビューは context_processors 引数を提供していました。 テンプレートのレンダリング時に使う、コンテキストプロセッサを指定できます。

クラスベースビューは context_processors 引数を提供しません。代わりにビューを 継承して TemplateResponseMixin.render_to_response() をオーバーライド します。そして、使いたいプロセッサをインスタンス化した、コンテキストインスタンス を渡します。例を挙げます:

class MyListView(ListView):
    def render_to_response(self, context, **kwargs):
        return super(MyListView, self).render_to_response(
                RequestContext(self.request,
                               context,
                               processors=[custom_processor]),
                **kwargs)

ファイルの管理

revision-up-to:17812 (1.4)

このドキュメントでは、 Django のファイルアクセス API について解説します。

デフォルトの構成では、 Django は MEDIA_ROOTMEDIA_URL に基づいてファイルをローカルのファイルシステムに保存し ます。このドキュメントの以降の例では、デフォルトの構成での動作を想定してい ます。

ただし、 Django には ファイルストレージシステム をカスタマイズして、ファイルの保存方法を完全にカスタマイズする方法がありま す。このドキュメントの後半部分では、ストレージシステムの仕組みを説明します。

モデル内でファイルを扱う

モデル内で FileFieldImageField を使うと、 Django はフィールドに対し てファイルを操作するための API を提供します。

以下のような、写真の保存に ImageField を使っている モデルを考えましょう:

class Car(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    photo = models.ImageField(upload_to='cars')

Car インスタンスには photo という属性ができ、この属性を使ってモデル に結びつけられたファイルの詳細を取得できます:

>>> car = Car.object.get(name="57 Chevy")
>>> car.photo
<ImageFieldFile: chevy.jpg>
>>> car.photo.name
u'cars/chevy.jpg'
>>> car.photo.path
u'/media/cars/chevy.jpg'
>>> car.photo.url
u'http://media.example.com/cars/chevy.jpg'

このオブジェクト (例中の car.photo) が File オブジェクトで、後で述 べるメソッドや属性を備えています。

Note

モデルがデータベースに保存される一環としてファイルは保存されます。 なので、モデルの保存が終わるまで実際のファイル名は信用できません。

File オブジェクト

内部的には、 Django はファイルを表現する必要がある場合には常に django.core.files.File を使います。このオブジェクトは Python の 組み込みファイルオブジェクト に対する薄いラッパで、 Django 固有の機能が追加されています。

普段は、単に (モデルに結びつけられたファイルや、アップロードされたファイル として) Django から渡される File オブジェクトを使うだけでしょう。

File オブジェクトを自分で生成したければ、 Python 組み込みの file オブジェクトを使うのが最も簡単です:

>>> from django.core.files import File

# Create a Python file object using open()
>>> f = open('/tmp/hello.world', 'w')
>>> myfile = File(f)

これで、 django.core.files.File クラスの属性やメソッドの全てを 使えます。

ファイルストレージ

舞台裏では、 Django はファイルの保存方法に関する決定をファイルストレージシ ステムに委ねています。ファイルストレージシステムは、ファイルシステムの構造 や、ファイルの開き方、データの読み出し方などを知っているオブジェクトです。

Django のデフォルトのファイルストレージは DEFAULT_FILE_STORAGE に設定します。明示的にストレージシステムを指定しなければ、デフォルトのファ イルストレージとしてこの設定の値を使います。

組み込みのファイルストレージシステムの詳細は下記を参照してください。また、 ファイルストレージシステムを自作する方法は カスタムのストレージシステムを作成する を参照してください。

ストレージオブジェクト

ほとんどの場合は File オブジェクトを使い (File オブジェクトに実際 のストレージの操作を肩代りさせ) ますが、ストレージシステムの直接操作もでき ます。カスタムのファイルストレージクラスのインスタンスを生成したり、グロー バルなデフォルトのストレージシステムに設定したりできるのです:

>>> from django.core.files.storage import default_storage
>>> from django.core.files.base import ContentFile

>>> path = default_storage.save('/path/to/file', ContentFile('new content'))
>>> path
u'/path/to/file'

>>> default_storage.filesize(path)
11
>>> default_storage.open(path).read()
'new content'

>>> default_storage.delete(path)
>>> default_storage.exists(path)
False

ファイルストレージの API については ファイルストレージ API を参照してくだ さい。

組み込みのファイルシステムストレージクラス

Django には組み込みの FileSystemStorage クラスが付属しています (このク ラスは django.core.files.storage で定義されています)。 FileSystemStorage は基本的な機能を持ったローカルファイルシステムストレー ジの実装です。初期かメソッドは以下の二つの引数をとります:

引数 説明
location 省略可能です。ファイルを保存するディレクトリの絶対 パスです。省略すると、 MEDIA_ROOT の 設定値を使います。
base_url 省略可能です。保存されているファイルを公開する URL です。省略すると、 MEDIA_URL の設定値を 使います。

例えば、以下のコードは、アップロードされたファイルを MEDIA_ROOT の設定 値と関係なく、 /media/photos 以下に保存します:

from django.db import models
from django.core.files.storage import FileSystemStorage

fs = FileSystemStorage(location='/media/photos')

class Car(models.Model):
    ...
    photo = models.ImageField(storage=fs)

カスタムのストレージシステム でも同じで、 FileFieldstorage にストレージのインスタンスを 渡します。

Djangoアプリケーションのテスト

revision-up-to:11321 (1.1) unfinished

今日の Web 開発者にとって、自動化されたテストはバグ潰しの工程で極めて有用な ツールです。複数のテストを集めた テストスイート を使えば、Web開発におけ るいくつもの問題を解決したり回避したりできます:

  • 新たなコードを書く際、コードが期待通りに動作するかテストできます。
  • 以前のコードを修正したりリファクタする場合、テストによって、コードの変 更がアプリケーションに意図しない影響を及ぼさないか調べられます。

Web アプリケーションは、 HTTP レベルのリクエスト処理、フォームの検証と処理、 そしてテンプレートレンダリングまで、複数のロジックレイヤから構成されていま す。そのため、Webアプリケーションのテストは複雑なタスクです。 Django のテス ト実行フレームワークと関連ユーティリティを使えば、仮想的なリクエストを発行 したり、テストデータを挿入したり、アプリケーションの出力を調べて、コードが 期待通りに動作しているか検証したりできます。

しかも素晴らしいことに、テストはとても簡単なのです。

このドキュメントは前後半の 2 つの節に別れています。前半では Django における テストの書き方を、後半ではテストの実行方法を説明します。

テストを書く

Django でテストを書く方法は主に 2 つあり、それぞれ Python の標準ライブラリ についてくる二つのテストフレームワークに対応しています。フレームワークは以 下の 2 つです:

  • doctest – 関数やクラスの docstring (ドキュメンテーション文字列) に埋め込まれたテストで、例えば以下のように Python の対話インタプリタ セッションを模した方法で書かれています:

    def my_func(a_list, idx):
        """
        >>> a = ['larry', 'curly', 'moe']
        >>> my_func(a, 0)
        'larry'
        >>> my_func(a, 1)
        'curly'
        """
        return a_list[idx]
    
  • ユニットテスト (unit test) – 以下の例のように、テストを unittest.TestCase` のサブクラスのメソッドとして表現したものです:

    import unittest
    
    class MyFuncTestCase(unittest.TestCase):
        def testBasic(self):
            a = ['larry', 'curly', 'moe']
            self.assertEquals(my_func(a, 0), 'larry')
            self.assertEquals(my_func(a, 1), 'curly')
    

好みに応じて、どちらのテストを使ってもかまいませんし、両方のテストを組み合 わせてもかまいません。また、後でほんの少しだけ説明しますが、他のテストフレー ムワークを使っても構いません。

doctest を書く

doctest は、Python の標準モジュール、 doctest によるテストです。 doctest は docstring (ドキュメンテーション文字列) から、 Python の対話インタプリタ セッションの形式をとる部分を探し出して実行します。 doctest の詳しい構造につ いての解説はこのドキュメントの範囲を超えた話なので、公式ドキュメントを参照 してください。

docstring とは?

docstring の詳しい説明 (と、効果的な docstring の書き方) は、 PEP 257 (訳注: PEP 257 の和訳は http://www.python.jp/doc/contrib/peps/pep-0257.txt にあります) に書かれ ています:

docstring とは、モジュールや関数、クラス、メソッド定義のブロック中 の先頭に置かれた文字列リテラルです。 docstring を定義すると、オブジェ クトの __doc__ という特殊な属性になります。

例えば、下の関数には、関数の説明の入った docstring があります:

def add_two(num):
    "引数に指定した数に 2 を加えて返します。"
    return num + 2

テストはそれ自体素晴らしいドキュメントになることも多いので、テストをそ のまま docstring に入れておけば、ドキュメント化とコードのテストの 両方を 効率的に行えます。

テストランナは、 Django アプリケーションの中の以下のファイルから doctest を 探して実行します:

  • models.py ファイル。モジュールレベル、かつ/またはモデルレベルの doctest を記述します。一般には、アプリケーションレベルの doctest はモ ジュールの docstring として記述し、モデルレベルの docstring はモデル クラスの docstring として記述します。
  • アプリケーションディレクトリ、すなわち models.py の入ったディレク トリ下に置かれた tests.py という名前のファイル。このファイルは、 モデルに関係しないような doctest を書きたい場合のフックとして使えます。

モデル定義で doctest を使った例を示します:

# models.py

from django.db import models

class Animal(models.Model):
    """
    鳴き声から動物を調べるテスト

    # 動物インスタンスを生成する
    >>> lion = Animal.objects.create(name="lion", sound="roar")
    >>> cat = Animal.objects.create(name="cat", sound="meow")

    # speak() を呼び出す
    >>> lion.speak()
    'The lion says "roar"'
    >>> cat.speak()
    'The cat says "meow"'
    """

    name = models.CharField(max_length=20)
    sound = models.CharField(max_length=20)

    def speak(self):
        return 'The %s says "%s"' % (self.name, self.sound)

テストを実行する と、テストユーティリティは上の docstring を探し出して、Python の対話セッションに見える部分を検出し、そこに 書かれた命令を実行して、docstring に書かれた結果と実際の実行結果が一致する かどうかを確かめます。

モデルテストの場合、テストランナが独自にテストデータベースを作成します。す なわち、データベースに対してアクセスするテスト – 例えば、モデルインスタン スを生成して保存するようなテスト – が、実運用のためのデータベースに影響を 及ぼすことはありません。 doctest はいずれも「白紙状態」、すなわち、各モデル のデータベーステーブルが空の状態で実行されます (詳しくは、後述のフィクスチャ の節を参照してください) 。この機能を使うには、 Django がデータベースに接続 するときのユーザに CREATE DATABASE の権限を持たせておかねばならないので 注意してください。

doctest の詳しい動作原理は、 標準ドキュメントの doctest の項 を参照してください。

ユニットテストを書く

Django の単体テストもまた、doctest と同様、標準ライブラリモジュールの unittest を使います。このモジュールは、 doctest とは違った、 クラスベース のやり方でテストを定義します。

doctest と同様、 Django のテストランナは、以下の二つの場所からユニットテス トを探します:

  • models.py ファイル。テストランナはこのモジュールから unittest.TestCase のサブクラスを探します。
  • アプリケーションディレクトリ、すなわち models.py の入ったディレク トリ下に置かれた tests.py という名前のファイル。上と同様に、テス トランナはこのモジュールから unittest.TestCase のサブクラスを探し ます。

以下の unittest.TestCase のサブクラスは、前節の doctest と同じテストを 実現しています:

import unittest
from myapp.models import Animal

class AnimalTestCase(unittest.TestCase):

    def setUp(self):
        self.lion = Animal.objects.create(name="lion", sound="roar")
        self.cat = Animal.objects.create(name="cat", sound="meow")

    def testSpeaking(self):
        self.assertEquals(self.lion.speak(), 'The lion says "roar"')
        self.assertEquals(self.cat.speak(), 'The cat says "meow"')

テストを実行する と、テストユーティリティはデフォル トの動作として、 models.pytests.py に入っている全てのテストケー ス (つまり unittest.TestCase のサブクラス) を捜し出し、そこからテストス イートを自動的に構築して、スイートを実行します。

開発バージョンの Django には、あるモジュールのテストスイートを定義する方法 をもう一つ提供しています: models.pytests.pysuite() メ ソッドを定義している場合、 Django のテストランナはこのメソッドを使ってテス トスイートを構築します。この仕様は、ユニットテストにおいて おすすめのテストスイート構築方法 に従っています。複雑なテストスイー トの構築方法についての詳細は Python のドキュメントを参照してください。

unittest の詳細は 標準ライブラリドキュメントの unittest の項 を参照 してください。

どちらのテストを使うべきか

Django は標準的な Python テストフレームワークの両方をサポートしているので、 どちらを選ぶかは、開発者個々人の好み次第です。もちろん、 両方 を同時に使っ てもかまいません。

とはいえ、テストを初めて書く開発者にとっては、この選択は混乱 のもとになるでしょう。そこで、どちらのテストを使うべきかを決める手がかりに なるよう、 doctest と単体テストの主な違いについて示します:

  • そこそこ Python に慣れているなら、 doctest の方がより「Python的 (pythonic)」に感じることでしょう。 doctest はテストをできるだけ楽に書け るように設計されているので、クラスやメソッドを書くときのオーバヘッドが ほとんどありません。単に docstring にテストを書くだけでよいのです。それ に、モジュールに対してドキュメントを自動生成させられるという利点もあり ます。つまり、 doctest を上手に書けば、ドキュメント作成とテストを同時に 片付けられて一石二鳥、というわけです。

    また、テストにまだ慣れていない開発者は、 doctest を使った方が早くテスト について学べることでしょう。

  • Java での開発経験のある開発者なら、 unittest フレームワークはとても 理解しやすいはずです。 unittest は Java の JUnit に影響を受けている ので、他の言語で JUnit から派生したテストフレームワークを使ったことがあ るのなら、unittest はかなりしっくりくるはずです。

  • 同じコードを含むような一連のテストを書くときには、 unittest フレー ムワークのクラスとメソッドによる設計が気に入るでしょう。共通のタスクを 抽象化して、メソッド化できるからです。また、 unittest フレームワー クは unittest はテストの初期化/終了処理のルーチンをサポートしてい るので、テストケースを実行するときの環境を高い水準でコントロールできま す。

繰り返しになりますが、(一つのアプリケーションの中であっても) 両方のシステム を並べて使えることを忘れないでください。どちらのテストシステムにも、状況に 応じて適した部分があるので、大抵のプロジェクトでは、最終的には両方のテスト システムを使うことになるものです。

テストを実行する

テストを実行するには、プロジェクトの manage.py ユーティリティを使います:

$ ./manage.py test

特定のアプリケーションに対してテストを実行したければ、コマンドラインにアプ リケーションの名前を追加します。例えば、 INSTALLED_APPSmyproject.pollsmyproject.animals というアプリケーションが入って おり、 animals の単体テストを実行したいだけなら、以下のようにします:

$ ./manage.py test animals

animals ではなく、 myproject.animals なので注意してください。

実行したいテストを選べるようになりました。

単体テストを実行する際、どのテストを実行するかを指定できます。あるアプリケー ション用のテストケースを実行する場合 (例えば、上で解説した AnimalTestCase の場合) は、コマンドラインにテストケースの名前を追加してください:

$ ./manage.py test animals.AnimalTestCase

テストケース中の 個別の テストメソッドを実行したければ、メソッド名を指定して ください:

$ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
テストデータベース

データベースを必要とするテスト (モデルのテスト) に、「本番の (実運用環境の)」 データベースは必要ありません。テストの際には、空の別のデータベースが作成さ れます。

テストがパスするか失敗するかに関わらず、テストデータベースは全てのテストを 実行し終えると消去されます。

デフォルトでは、テストデータベースの名前は、 DATABASE_NAME に指 定したデータベース名の前に test_ を付けたものです。 SQLite データベース エンジンを使っている場合、デフォルトではテストをメモリ上のデータベースで行 います(すなわち、データベースをメモリ上に生成し、ファイルシステムを全く経由 しません!) 。テストデータベースの名前をデフォルト意外の値にしたければ、 TEST_DATABASE_NAME 設定を使って指定します。

テスト用に別のデータベースを使うことを除けば、テストランナは設定ファイルの データベースに関する他の設定、 DATABASE_ENGINE, DATABASE_USER, DATABASE_HOST などをそのまま使います。 テストデータベースは DATABASE_USER の権限で作成されるので、この ユーザは新たに生成されたデータベースを操作する権限を備えていなければなりま せん。

テスト用データベースの文字セットエンコーディング設定を細かく調整したいのな ら、 TEST_DATABASE_CHARSET 設定を使ってください。 MySQL を使って いるなら、 TEST_DATABASE_COLLATION でテストデータベースで使うコ レーション(collation) を指定できます。これらの設定については、 settings ファイルのドキュメント を参照してください。

その他のテスト条件

設定ファイル上の DEBUG の値にかかわらず、 Django は全てのテスト を DEBUG=False で動かします。これは、テストコードに実運用環境と 同じ内容を出力させるためです。

テストプログラムの出力を理解する

テストを実行すると、テストランナ自体が大量に出力するメッセージに出くわすで しょう。コマンドラインの verbosity オプションを使えば、メッセージの詳細 レベルを制御できます:

Creating test database...
Creating table myapp_animal
Creating table myapp_mineral
Loading 'initial_data' fixtures...
No fixtures found.

前の節でも述べたように、このメッセージは、テストランナがテストデータベース を作成したことを示しています。

テストデータベースが生成されると、 Django はテストを実行します。全てのテス トにパスすると、最後には以下のようなメッセージが表示されます:

----------------------------------------------------------------------
Ran 22 tests in 0.221s

OK

一方、失敗したテストがあると、失敗したテストに関する詳しい情報が表示されま す:

======================================================================
FAIL: Doctest: ellington.core.throttle.models
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/dev/django/test/doctest.py", line 2153, in runTest
    raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for myapp.models
  File "/dev/myapp/models.py", line 0, in models

----------------------------------------------------------------------
File "/dev/myapp/models.py", line 14, in myapp.models
Failed example:
    throttle.check("actor A", "action one", limit=2, hours=1)
Expected:
    True
Got:
    False

----------------------------------------------------------------------
Ran 2 tests in 0.048s

FAILED (failures=1)

エラー出力の詳細はこのドキュメントの範囲を超えるので解説はしませんが、ほと んど直感的に理解できる内容のはずです。詳しくは、 Python の unittest ラ イブラリのドキュメントを参照してください。

スクリプトのリターンコードは失敗したテストや出力のおかしかったテストの総数で す。全てのテストにパスしていれば、リターンコードは 0 です。この仕様は、テス トランナをシェルスクリプト上で動かしたり、テストが成功したかどうかをテスト ランナのレベルで調べたい場合に便利です。

テスト用のツール

Django は、テストを書くときに便利なツールをいくつか提供しています。

テストクライアント

テストクライアント (test client) は、簡単なダミーブラウザとして動作する Python のクラスです。テストクライアントを使うと、ビューをテストしたり、 プログラムを使ってDjango で作られたアプリケーションとやりとりできます。

テストクライアントを使ってできることをいくつか挙げましょう:

  • ある URL に対する GET や POST をシミュレートでき、低水準の HTTP (レスポ ンスヘッダや状態コード) 情報から、ページの内容まで、リクエストに対するレ スポンスの全てを調べられます。
  • 特定の URL に対して正しいビューが呼び出されるかどうかを調べられます。
  • 特定のリクエストに対して、特定のテンプレートを使ったレンダリングが行わ れ、その際に特定の値が入ったコンテキストが使われているかどうかを調べら れます。

テストクライアントは TwillSelenium やその他のブラウザ自動化フレームワー クを置き換えようとするものではありません。 Django のテストクライアントはもっ と別の部分に焦点を当てているのです。すなわち:

  • 正しいビューが呼び出され、ビューが正しいコンテキストデータを生成してい るかどうかは、 Django のテストクライアントを使って調べてください。
  • Twill や Selenium は、 レンダリング済みの HTML や、 JavaScript の機能 のような Web ページの ビヘイビア のテストに使ってください。

網羅的なテストスイートでは、両方のタイプのテストを組み合わせて使うはずです。

テストの概要と簡単な例

テストクライアントを使うには、 django.test.client.Client をインスタンス 化して、 Web ページを取得します:

>>> from django.test.client import Client
>>> c = Client()
>>> response = c.post('/login/', {'username': 'john', 'password': 'smith'})
>>> response.status_code
200
>>> response = c.get('/customer/details/')
>>> response.content
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...'

上の例でわかるように、 Client は Python 対話インタプリタのセッション中 でもインスタンス化できます。

テストクライアントの動作には重要な点がいくつかあります:

  • テストクライアントを実行するために Web サーバを起動する必要は ありません 。実際、 Web サーバがまったく動いていなくても、テストは 何の問題もなく実行できるのです。というのも、テストクライアントは HTTP 通信のオーバヘッドを回避して、 Django フレームワークに直接アクセスし ているからです。このからくりによって、ユニットテストを高速に実行でき ます。

  • ページを取得するときには、ドメインを含まない パス部分だけ を指定す るよう気をつけてください。例えば、以下の呼び出し:

    >>> c.get('/login/')
    

    は正しいですが、次の呼び出し:

    >>> c.get('http://www.example.com/login/')
    

    は正しくありません。

    Django のプロジェクトから生成されていない Web ページは、テストクライ アントで取得できません。Django 以外の Web ページを取得したければ、 urlliburllib2 のような Python 標準ライブラリを使ってください。

  • テストクライアントは URL の解決に ROOT_URLCONF に指定され た URLconf を使います。

  • 上の例は Python の対話インタプリタ中でも動作しますが、一部のテンプレー ト関連の機能などは テストの実行中だけ でしか使えません。

    というのも、 Django のテストランナは、あるビューでどのテンプレートが ロードされるかを決定するためにちょっとした黒魔術的なコードを使ってい るからです。この黒魔術 (実際には、メモリ上のテンプレートシステムに対 するパッチ) は、テスト実行時にしか適用されません。

リクエスト生成

リクエストの生成には、 django.test.client.Client クラスを使います。 Client は引数なしで生成します。:

class Client

Client のインスタンスからは、以下のメソッドを呼び出せます:

get(path, data={}, follow=False, **extra)

path に対する GET リクエストを行い、 Response オブジェクト を返します。 Response オブジェクトについては後で説明します。

引数 data は辞書オブジェクトで、キー/値のペアが GET データのペ イロードの生成に使われます。例えば:

>>> c = Client()
>>> c.get('/customers/details/', {'name':'fred', 'age':7})

は、以下のような GET リクエストの送信と同じです:

/customers/details/?name=fred&age=7

The extra keyword arguments parameter can be used to specify headers to be sent in the request. For example:

>>> c = Client()
>>> c.get('/customers/details/', {'name': 'fred', 'age': 7},
...       HTTP_X_REQUESTED_WITH='XMLHttpRequest')

...will send the HTTP header HTTP_X_REQUESTED_WITH to the details view, which is a good way to test code paths that use the django.http.HttpRequest.is_ajax() method.

If you already have the GET arguments in URL-encoded form, you can use that encoding instead of using the data argument. For example, the previous GET request could also be posed as:

>>> c = Client()
>>> c.get('/customers/details/?name=fred&age=7')

If you provide URL both an encoded GET data and a data argument, the data argument will take precedence.

If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes.

If you had an url /redirect_me/ that redirected to /next/, that redirected to /final/, this is what you’d see:

>>> response = c.get('/redirect_me/', follow=True)
>>> response.redirect_chain
[(u'http://testserver/next/', 302), (u'http://testserver/final/', 302)]
post(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra)

path に対する POST リクエストを行い、 Response オブジェクト を返します。

引数 data は辞書オブジェクトで、キー/値のペアが POST データの ペイロード生成に使われます。例えば:

>>> c = Client()
>>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'})

は、以下のパス:

/login/

への POST リクエストで、以下の POST データ:

name=fred&passwd=secret

を伴います。

content_type を指定した場合 (例えば XML ペイロードの場合には text/xml)、引数 data の中身は POST リクエストそのままで送信 され、 Content-Type ヘッダに content_type の値を使います。

content_type を指定しなければ、 data の中身は multipart/form-data で送信されます。この場合、 data の中の キー/値のペアは、マルチパートメッセージにエンコードされ、 POST デー タのペイロード生成に使われます。

あるキーに対して複数の値を提出 (submit) する場合 (例えば、 <select multiple> の選択結果を指定する場合など) は、キーに対す る値をリストやタプルにしてください。例えば、choices という名前 のフィールドから 3 つの行を選択して提出したければ:

{'choices': ('a', 'b', 'd')}

のようにします。

ファイルの送信には特別な扱いが必要です。ファイルの POST を行う場合、 以下のように、ファイル名フィールドの名前をキーに、アップロードした いファイルのファイルハンドルを値に設定します:

>>> c = Client()
>>> f = open('wishlist.doc')
>>> c.post('/customers/wishes/', {'name':'fred', 'attachment':f})
>>> f.close()

(attachment という名前には特に意味はありません。ファイルを処理 するコードで使いたい名前を指定してください)

送信するファイルのハンドルは、 post() 後に手動で閉じねばならな いので注意してください。

The extra argument acts the same as for Client.get().

If the URL you request with a POST contains encoded parameters, these parameters will be made available in the request.GET data. For example, if you were to make the request:

>>> c.post('/login/?vistor=true', {'name': 'fred', 'passwd': 'secret'})

... the view handling this request could interrogate request.POST to retrieve the username and password, and could interrogate request.GET to determine if the user was a visitor.

If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes.

head(path, data={}, follow=False, **extra)

Makes a HEAD request on the provided path and returns a Response object. Useful for testing RESTful interfaces. Acts just like Client.get() except it does not return a message body.

If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes.

options(path, data={}, follow=False, **extra)

Makes an OPTIONS request on the provided path and returns a Response object. Useful for testing RESTful interfaces.

If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes.

The extra argument acts the same as for Client.get().

put(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra)

Makes an PUT request on the provided path and returns a Response object. Useful for testing RESTful interfaces. Acts just like Client.post() except with the PUT request method.

If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes.

delete(path, follow=False, **extra)

Makes an DELETE request on the provided path and returns a Response object. Useful for testing RESTful interfaces.

If you set follow to True the client will follow any redirects and a redirect_chain attribute will be set in the response object containing tuples of the intermediate urls and status codes.

The extra argument acts the same as for Client.get().

login(**credentials)

Django の 認証システム を使っていて、ログイン 済みのユーザを扱う必要がある場合、テストクライアントの login() メソッドを使えば、サイトへログインするユーザをシミュレートできます。

このメソッドを呼び出すと、テストクライアントはログインに必要なクッ キーとセッションデータを持つようになり、テスト対象のビューのうち、 ログインの必要なテストをパスできるようになります。

credentials 引数の形式は、使っている 認証バックエンド によって変わりま す (認証バックエンドは AUTHENTICATION_BACKENDS で設定し ます)。 Django が提供している標準の認証バックエンド (ModelBackend) を使う場合、 credentials にはユーザのユーザ 名とパスワードをキーワー引数で指定します:

>>> c = Client()
>>> c.login(username='fred', password='secret')

# これでログイン保護されたビューに入れるようになりました。

認証バックエンドを変えた場合、このメソッドは違った認証情報を要求す るかもしれません。その場合、 login() は、認証バックエンドの authenticate() メソッドが必要とする認証情報をそのまま要求します。

login() は、指定した認証情報が承認され、ログインに成功した場合に True を返します。

このメソッドを使うには、事前にユーザを登録しておかねばなりません。上 で説明したように、テストランナはテストデータベースを使ってテストを実 行するので、デフォルトではユーザが登録されていません。そのため、運用 環境で使えるユーザはテスト環境では使えないのです。テストスイートの一 環として、手動で (Django のモデル API を使って) ユーザを作成するか、 フィクスチャでユーザを登録してください。 Remember that if you want your test user to have a password, you can’t set the user’s password by setting the password attribute directly – you must use the set_password() function to store a correctly hashed password. Alternatively, you can use the create_user() helper method to create a new user with a correctly hashed password.

logout()

Django の 認証システム を使っている場合、 logout() メソッドで、サイトからユーザをログアウトさせる効果をシ ミュレートできます。

このメソッドを呼び出すと、テストクライアントはクッキーとセッション データを全て消去して、デフォルトの状態に戻します。それ以降のリクエ ストは、ビューからは AnonymousUser から送信されたリクエストとみ なされます。

レスポンスのテスト

get() および post() メソッドは、いずれも Response オブジェクト を返します。 Response オブジェクトは Django のビューが返す HttpResponse オブジェクトと同じ ではありません 。このオブジェクトは 検証用のテストコード作成に便利なデータをいくつか備えています。

Response オブジェクトには以下のようなプロパティがあります:

class Response
client

レスポンス要求の生成に使われたテストクライアントです。

content

レスポンスの本体部分 (body) です。ビューがレンダリングによって生成 した最終的なページコンテンツか、エラーメッセージです。

context

レスポンスのページコンテンツのレンダに使われた Context オブジェ クトです。

複数のテンプレートを使ってレンダリングを行った場合、 contextContext オブジェクトをレンダリングで使った順に並べたリストです。

Regardless of the number of templates used during rendering, you can retrieve context values using the [] operator. For example, the context variable name could be retrieved using:

>>> response = client.get('/foo/')
>>> response.context['name']
'Arthur'
request

レスポンスを得るために使用したリクエストデータです。

status_code

レスポンスの HTTP 状態コードです。全ての HTTP 状態コードのリストは RFC2616 を参照してください。

template

最終的なページコンテンツのレンダリングに使われた Template のイ ンスタンスです。テンプレートをファイルからロードした場合、テンプレー トのファイル名を template.name で調べられます ('admin/index.html' のような形式の文字列です)。

複数のテンプレートをレンダリングしている場合 (例えば テンプレートの継承 を使っている場合)、 template はレンダリング順に並んだ Template オブジェクトの リストです。

また、レスポンスオブジェクトを辞書のように扱っても、HTTPヘッダに設定された 値にアクセスできます。例えば、レスポンスのコンテンツタイプは response['Content-Type'] でアクセスできます。

例外

テストクライアントのアクセス先のビューが例外を送出するような場合、テストケー ス内で例外にアクセスできます。例外のテストを行うには、通常の try...catch ブロックか、 unittest.TestCase.assertRaises() を使いま す。

ただし、 Http404PermissionDenied, SystemExit といった例外は テストケースからアクセスできません。 Django はこれらの例外を内部的に捕捉し て、対応する適切な HTTP 応答コードに変換してしまうからです。これらの例外に 対しては、 response.status_code のチェックで対応してください。

セッションの永続性

テストクライアントの動作はステートフルです。あるレスポンスにクッキーが入っ ていると、クッキーはテストクライアント中に保存され、それ以降の get()post() リクエストで使われます。

テストクライアントは、クッキーの有効期限ポリシを守りません。クッキーを期限 切れにしたければ、該当クッキーを client.cookies から手動で削除するか、 新たな Client インスタンスを生成してください (全てのクッキーを除去しま す)。

テストクライアントには、永続セッション情報 (persistent state information) を保存するためのプロパティが二つあります。これらのプロパティは、必要に応じ てテスト条件の一部として検査できます。

Client.cookies

Python の SimpleCookie 型のオブジェクトで、全てのクライアントクッキー の現在値が入っています。詳しくは Cookie モジュールのドキュメント を 参照してください。

Client.session

セッション情報の入った辞書ライクなオブジェクトです。詳しくは セッションのドキュメント を参照してくださ い。

ユニットテストの例

テストクライアントを使った簡単なユニットテストを以下に示します:

import unittest
from django.test.client import Client

class SimpleTest(unittest.TestCase):
    def setUp(self):
        # unittest を使う場合、毎回 Client を生成する必要があります。
        self.client = Client()

    def test_details(self):
        # GET リクエストを発行します。
        response = self.client.get('/customer/details/')

        # レスポンスが 200 OK であるか調べます。
        self.failUnlessEqual(response.status_code, 200)

        # レンダリングされるコンテキストの customers の長さが 5 である
        # か確かます。
        self.failUnlessEqual(len(response.context['customers']), 5)
TestCaseクラス

Normal Python unit test classes extend a base class of unittest.TestCase. Django provides an extension of this base class:

class TestCase

このクラスは、Web サイトのテスト時に便利な機能をいくつか追加しています。

通常のユニットテストを unittest.TestCase から Django 独自の TestCase に移行するのは簡単で、単にベースクラスを unittest.TestCase から django.test.TestCase に変更するだけです。 django.test.TestCase は、標準の Python ユニットテスト機能はそのままに、さらに便利な機能を提供し ています。

class TransactionTestCase

Django TestCase classes make use of database transaction facilities, if available, to speed up the process of resetting the database to a known state at the beginning of each test. A consequence of this, however, is that the effects of transaction commit and rollback cannot be tested by a Django TestCase class. If your test requires testing of such transactional behavior, you should use a Django TransactionTestCase.

TransactionTestCase and TestCase are identical except for the manner in which the database is reset to a known state and the ability for test code to test the effects of commit and rollback. A TransactionTestCase resets the database before the test runs by truncating all tables and reloading initial data. A TransactionTestCase may call commit and rollback and observe the effects of these calls on the database.

A TestCase, on the other hand, does not truncate tables and reload initial data at the beginning of a test. Instead, it encloses the test code in a database transaction that is rolled back at the end of the test. It also prevents the code under test from issuing any commit or rollback operations on the database, to ensure that the rollback at the end of the test restores the database to its initial state. In order to guarantee that all TestCase code starts with a clean database, the Django test runner runs all TestCase tests first, before any other tests (e.g. doctests) that may alter the database without restoring it to its original state.

When running on a database that does not support rollback (e.g. MySQL with the MyISAM storage engine), TestCase falls back to initializing the database by truncating tables and reloading initial data.

Note

The TestCase use of rollback to un-do the effects of the test code may reveal previously-undetected errors in test code. For example, test code that assumes primary keys values will be assigned starting at one may find that assumption no longer holds true when rollbacks instead of table truncation are being used to reset the database. Similarly, the reordering of tests so that all TestCase classes run first may reveal unexpected dependencies on test case ordering. In such cases a quick fix is to switch the TestCase to a TransactionTestCase. A better long-term fix, that allows the test to take advantage of the speed benefit of TestCase, is to fix the underlying test problem.

デフォルトのテストクライアント
TestCase.client

django.test.TestCase クラスのインスタンス内に入っているテストケースは全 て、デフォルトの テストクライアント にアクセスできます。このテストクライ アントは self.client で参照できます。テストクライアントはテストごとに再 生成されるので、テスト間でクッキーのような状態情報が継承される心配はありま せん。

例えば、以下のコード:

import unittest
from django.test.client import Client

class SimpleTest(unittest.TestCase):
    def test_details(self):
        client = Client()
        response = client.get('/customer/details/')
        self.failUnlessEqual(response.status_code, 200)

    def test_index(self):
        client = Client()
        response = client.get('/customer/index/')
        self.failUnlessEqual(response.status_code, 200)

では、各テストで Client をインスタンス化していますが、実際は次のコード のように、 self.client を参照するだけでよいのです:

from django.test import TestCase

class SimpleTest(TestCase):
    def test_details(self):
        response = self.client.get('/customer/details/')
        self.failUnlessEqual(response.status_code, 200)

    def test_index(self):
        response = self.client.get('/customer/index/')
        self.failUnlessEqual(response.status_code, 200)
フィクスチャの読み込み
TestCase.fixtures

データベースがバックにあるウェブサイトのテストで、データベース上に何もデー タが入っていなければあまり意味はありません。データベースにテストデータを入 れやすくするために、 Django の独自 TestCase クラスは フィクスチャ (fixture) の読み込み機能を提供しています。

フィクスチャとは、一群のデータを Django がデータベースに取り込める形式にし たものです。例えば、ユーザアカウントを持つようなサイトを作っている場合、テ スト中は仮のユーザアカウントの入ったフィクスチャを作り、データベースに入れ ておくと便利です。

最も素直なフィクスチャの作成方法は、 manage.py dumpdata コマンドを使う というものです。 dumpdata を使うにはデータベースに既に何らかのデータが 入っていなければなりません。詳しくは dumpdata のドキュメント を参照してください。

Note

manage.py syncdb を実行したことがあるなら、あなたの知らないうちにフィ クスチャは使われています。最初に syncdb を実行したときに、 Django は initial_data という名前のフィクスチャをインストールします。この メカニズムを使えば、 (カテゴリのデフォルトセットのような) 新たなデータ セットをデータベースに組み込めます。

initial_data 以外の名前のフィクスチャは、 django-admin.py loaddata で手動で組み込めます。

単体テストでフィクスチャを使う場合、フィクスチャを作成して Django のプロジェ クトディレクトリ下に置き、 dhango.test.TestCase のサブクラスの fixtures クラス属性を指定します:

from django.test import TestCase
from myapp.models import Animal

class AnimalTestCase(TestCase):
    fixtures = ['mammals.json', 'birds']

    def setUp(self):
        # 従来通りのテスト定義

    def testFluffyAnimals(self):
        # フィクスチャを使うテスト

ユニットテストは、以下のように動作します:

  • テストケースの開始時で、かつ setUp() の実行前に、 Django はデータベー スを一掃して、データベースを syncdb 直後の状態に戻します。
  • 次に、テストケースクラスに指定した全てのフィクスチャをインストールしま す。上の例では、 mammals という名前の JSON フィクスチャと、 birds という名前のフィクスチャがインストールされます。フィクスチャ の定義とインストールに関する詳細は loaddata のドキュメント を参照してください。

このフラッシュ/ロードの作業はテストケースの実行毎に繰り返されるので、テス トの結果が他のテストや以前に実行したテストの影響を受けたり、テストの順番に 左右されることはありません。

URLconf の設定
TestCase.urls

アプリケーションでビューを定義している場合、テストクライアントを使ってビュー を検査するテストを組み込みたいことがあるでしょう。しかし、エンドユーザはア プリケーションのビューを自分の好きな URL でデプロイできるので、テストを行う 際には、ビューが特定の URL でアクセスできると期待してはなりません。

テスト用の URL 空間を指定するために、 django.test.TestCase はテストスイー ト実行中に使われる URLconf をカスタマイズできる仕組みを提供しています。 TestCase インスタンスに urls 属性を指定しておくと、 TestCase はその値をテスト実行中だけ ROOT_URLCONF に使います。

使い方を示しましょう:

from django.test import TestCase

class TestMyViews(TestCase):
    urls = 'myapp.test_urls'

    def testIndexPageView(self):
        #  ``Client`` を使ってビューをテストする

このテストケースは、ケースの実行中だけ、 myapp.test_urls を URLconf と して使います。

メール送信箱の内容抹消

Django 独自の TestCase クラスを使うと、テストランナは各テストケースの開 始時にメールの送信箱に入っている内容を消去します。

テスト中のメールサービスの詳細は メールサービス を参照してください。

アサーション

通常の Python unittest.TestCase クラスが備えている assertTrueassertEquals のようなアサーションメソッドと同様、 Django 独自の TestCase クラスでも Web アプリケーションをテストする上で便利な様々な 独自のアサーションメソッドを提供しています。

TestCase.assertContains(response, text, count=None, status_code=200)

status_code に指定した状態コードで Response インスタンスが生成 され、レスポンスのコンテンツ内に text が入っているかどうか調べるア サーションです。 count を指定すると、 text は正確に count 回出現せねばなりません。

TestCase.assertNotContains(response, text, status_code=200)

status_code に指定した状態コードで Response インスタンスが生成 され、レスポンスのコンテンツ内に text が入っていないことを確認する アサーションです。

TestCase.assertFormError(response, form, field, errors)

form に指定したフォーム上のフィールド field で、 errors に 指定したエラーリストと同じエラーが送出されるかどうか調べるアサーション です。

form はテンプレートコンテキスト上の Form インスタンスの名前です。

field はフォーム内のフィールドの名前です。 field の値が None であれば、非フィールドエラー (特定のフィールドに関連付けられて いない、 form.non_field_errors() でアクセスできるエラー) がチェック されます。

errors はエラー文字列か、エラー文字列のリストです。フォームの検証結 果として返されるのと同じ形式です。

assertTemplateUsed(response, template_name)

template_name に指定したテンプレートがレスポンスのレンダリングに使 われていることを確認するアサーションです。

template_name'admin/index.html' のような文字列です。

assertTemplateNotUsed(response, template_name)

template_name に指定したテンプレートがレスポンスのレンダリングに使 われて いない ことを確認するアサーションです。

assertRedirects(response, expected_url, status_code=302, target_status_code=200)

レスポンスが status_code に指定したリダイレクト状態コードを持ち、か つ expected_url へのリダイレクトを指示しており、さらにリダイレクト 先の内容を HTTP 状態コード target_status_code で取得できるかどうか 調べるアサーションです。

If your request used the follow argument, the expected_url and target_status_code will be the url and status code for the final point of the redirect chain.

メールサービス

ビューが Django のメールサービス を使っている場合、 ビューをテストするたびにメールが送信されてほしくはないでしょう。 Django の テストランナは、テスト中に Django から送信されたすべてのメールをダミーの送 信箱に振り分けます。これによって、送信したメールの数から、各メールのメッセー ジに至るまで、メール送信機能のすべてを (実際にメールを送らずに) テストでき ます。

Django は、テストフレームワークを初期化する際、通常の SMTPConnection クラスをダミーの SMTPConnection 実装に切替えます (Django の外部のメール送信機構、例えば Django を動かしてい るホストで動いているメールサーバには一切影響を及ぼしません)。

django.core.mail.outbox

テストの実行中、 Django から送信されたメールは djnago.core.mail.outbox に保存されます。 djnago.core.mail.outbox はその時点で送信された全ての EmailMessage インスタンスからなるリストで、テ スト時以外には存在しません。このダミー送信箱は、テストのセットアップ時に、 ダミーの SMTPConnection と組で初期化されます。テ ストが終了すると、通常の SMTPConnection が復帰し、 ダミー送信箱は削除されます。

The outbox attribute is a special attribute that is created only when the tests are run. It doesn’t normally exist as part of the django.core.mail module and you can’t import it directly. The code below shows how to access this attribute correctly.

django.core.mail.outbox を調べて、メール送信数やメールの内容をチェック するコード例を以下に示します:

from django.core import mail
from django.test import TestCase

class EmailTest(TestCase):
    def test_send_email(self):
        # Send message.
        mail.send_mail('Subject here', 'Here is the message.',
            'from@example.com', ['to@example.com'],
            fail_silently=False)

        # Test that one message has been sent.
        self.assertEqual(len(mail.outbox), 1)

        # Verify that the subject of the first message is correct.
        self.assertEqual(mail.outbox[0].subject, 'Subject here')

前節で 述べたように、テスト用の送信箱の内容は TestCase 内の各テストケースの開始時点で抹消されます。手動で送信箱の内容を空 にしたければ、空のリストを mail.outbox に代入してください:

from django.core import mail

# Empty the test outbox
mail.outbox = []

他のテストフレームワークを使う

doctestunittest だけが Python のテストフレームワークではありま せん。Django は他のテストフレームワークを明にサポートしているわけではありま せんが、他のテストフレームワークで作成したテストを Django の通常のテストと 同じように呼び出すためのメカニズムは提供しています。

./manage.py test を実行すると、 Django は TEST_RUNNER 設定を 探して、実行すべきテストランナを決定します。デフォルトでは、 TEST_RUNNERdjango.test.simple.run_tests です。このメソッ ドは Django のデフォルトのテスト動作を実装しており、以下のように動作します:

  1. テスト前の全体的な準備を行います。
  2. テストデータベースを生成します。
  3. syncdb を実行して、モデルと初期データをデータベースにインストールし ます。
  4. インストールされている全てのアプリケーションの models.pytests.py から、単体テストと doctest を探します。
  5. 見つかった単体テストと doctest を実行します。
  6. テストデータベースを破壊します。
  7. テスト後の全体的な後始末を行います。

テストランナメソッドを自作して、そのメソッド名を TEST_RUNNER に 指定しておき、 ./manage.py test を実行すると、 Django はそのテストラン ナメソッドを実行します。これによって、 Python コードから任意のテストフレー ムワークを実行できます。

テストランナを定義する

慣習的に、テストランナは run_tests と名付けます。テストランナは以下のよ うに Django テストランナと同じ引数をとらねばなりません:

run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[])

test_labels には、実行したいテストを表す文字列 (ラベル) のリストを 指定します。ラベルは以下の 3 つの形式で指定できます:

  • app.TestCase.test_method - テストケース中の個別のテストメソッ ドを実行します。
  • app.TestCase - テストケース中の全てのテストメソッドを実行しま す。
  • app - アプリケーション中の全てのテストを探して実行します。

test_labelsNone の場合、テストランナは INSTALLED_APPS に登録されている全てのアプリケーションからテ ストを探して実行します。

verbosity には、コンソールに出力される通知情報やデバッグ情報の量を 指定します。 0 にすると何も出力しません。 1 は通常の出力、 2 は多めの出力です。

interactiveTrue にすると、テストスイートの実行時に、テスト スイートからユーザに質問できるようになります。例えば、テストデータベー スを削除してよいか尋ねるといった使い方です。 interactiveFalse にする場合、テストスイートは手動操作なしで実行できねばなりま せん。

extra_tests には、このテストランナに追加で実行させたい TestCase インスタンスを指定します。 extra_tests を指定すると、 module_list から発見したテストに加えて、指定したテストを実行します。

このメソッドは失敗したテストの数を返さねばなりません。

テスト用のユーティリティ

django.test.utils モジュールには、テストランナの自作に役立つユーティリ ティメソッドが定義されています。

setup_test_environment()

テンプレートレンダリングシステム構成のインストールなど、テスト前の全 体的な準備を行い、ダミーの SMTPConnecton をセットアップします。

teardown_test_environment()

テンプレートレンダリングシステムに組み込まれた黒魔術的なフックの除去な ど、テスト後の全体的な後始末を行い、メールサービスを通常の状態に復帰し ます。

データベースバックエンドの生成モジュール (connection.creation) にも、テ スト時に便利なユーティリティがあります。

create_test_db(verbosity=1, autoclobber=False)

新たなテストデータベースを生成し、 syncdb を実行します。

verbosityrun_tests() の同名の引数と同じ意味です。

autoclobber には、テストデータベースと同名のデータベースが見つかっ た際の挙動を指定します:

  • autoclobberFalse なら、既存のデータベースを破壊しても よいかユーザに尋ねます。ユーザが「いいえ」を選択すると、その時点 で sys.exit を呼び出して終了します。
  • autoclobberTrue なら、既存のデータベースを破壊すると きにユーザに了解を求めません。

生成されたテストデータベースの名前を返します。

create_test_db() には settings.DATABASE_NAME を変更してテストデー タベースの名前にするという副作用があります。

create_test_db() 生成されたテストデータベースの名前を返すように なりました。
destroy_test_db(old_database_name, verbosity=1)

このメソッドを呼び出した時点で DATABASE_NAME に設定されてい るデータベースを破壊し、 DATABASE_NAME の値を old_database_name に指定したデータベース名に戻します。

verbosityrun_tests() の同名の引数と同じ意味です。

Django でのユーザ認証

revision-up-to:17812 (1.4)

Django にはユーザ認証システムがついてきます。 Django のユーザ認証システムは、 ユーザアカウント、グループ、パーミッションとクッキーベースのユーザセッショ ンを扱えます。このドキュメントでは、ユーザ認証の仕組みについて説明します。

概要

認証システムは以下の要素から成り立っています:

  • ユーザ (Users)
  • パーミッション: あるユーザが特定のタスクを実行してよいかどうかを決め る、バイナリ (yes/no) のフラグです。
  • グループ (Groups): 複数のユーザに対してラベル付したり、認証を設定した りするための一般的な方法です。
  • メッセージ (Messages): 指定のユーザ(達) に対するメッセージをキューす るための簡単な方法です。

インストール

認証のサポートは Django アプリケーションとして django.contrib.auth にバ ンドルされています。インストールするには、以下のようにします:

  1. INSTALLED_APPS 設定に 'django.contrib.auth' と、 'django.contrib.contenttypes' を加えます。 (django.contrib.auth モジュールのモデル Permissiondjango.contrib.contenttypes に依存します)
  2. manage.py syncdb を実行します。

django-admin.py startproject が生成するデフォルトの settings.py ファイルの INSTALLED_APPS には、簡便のため 'django.contrib.auth' が最初から入っています。この場合は、単に manage.py syncdb するだけでかまいません。 このコマンドはその都度必要なものだけをインストールするので、 何度実行してもかまいません。

syncdb コマンドは必要なデータベーステーブルを作成し、インストー ル済みのアプリケーションで必要な全てのパーミッションオブジェクトを作成しま す。また、最初に実行したときには、ユーザにスーパユーザアカウントを作成する よう促します。

これだけで、認証サポートを使えるようになります。

ユーザ (User)

class models.User
API リファレンス
フィールド
class models.User

User オブジェクトには以下のフィー ルドがあります:

username

必須です。30 文字以下の文字列で、英数字 (アルファベット、数字、アン ダースコア) だけを使えます。

ユーザネームには今では @, +, . and - 等の文字列を 含めることが出来ます。
first_name

オプションです。30 文字以下です。オプションです。30 文字以下です。

last_name

オプションです。 30 文字以下です。

email

オプションです。 Email アドレスです。

password

必須です。パスワードのメタデータであるハッシュ値です (Django では生 のパスワードを保存しません)。生のパスワードは任意の長さでよく、どん な文字が入っていても構いません。詳しくは以下の「パスワード」の節を 参照して下さい。

is_staff

Bool 値です。この値が真なら、ユーザは admin サイトにアクセスできま す。

is_active

Bool 値です。この値が真なら、このアカウントを使ってログインできます。 アカウントを削除する代わりに、この値を False に設定してください。 もしアプリケーションが外部キーをユーザに対して持っていたとしても、 この方法なら破綻しないのでおすすめです。

ユーザがログインできるかどうかをコントロールする必要性がない場合でも 認証バックエンドが is_active フラッグをチェックする必要がない時 であっても、もしログインできるかどうかを is_activeFalse にしたくない場合でも、ログインビューの中ではあなた次第です。 しかしながら、 login() によって使わ れる AuthenticationForm ビューは does このチェックを実行します。has_perm() のよう な権限を確かめるメソッドのように、そして Django アドミンでの認証と 同じように。これらのような関数/メソッドはアクティブでないユーザに 対して、 False を返します.

is_superuser

Bool 値です。この値が真なら、ユーザは明示的な指定がなくても全てのパー ミッションを得ます。

last_login

ユーザが最後にログインした時刻を表す datetime オブジェクトです。デ フォルトではログイン時現在の日付/時刻になります。

date_joined

アカウントの作成された時刻を表す datetime オブジェクトです。デフォ ルトではアカウント作成時現在の日付/時刻になります。

メソッド
class models.User

User オブジェクトには groupsuser_permissions という二つの多対多のフィールドがあります。この 関係性のために、 User オブジェクト は他の Django モデル と同じようにして、関連づ けされたオブジェクトにアクセスできます:

myuser.groups = [group_list]
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions = [permission_list]
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

自動的に生成されるこれらの API に加え、 User オブジェクトには以下のカス タムメソッドがあります:

is_anonymous()

常に False を返します。 User オブジェクトを AnonymousUser オブジェクトと 区別する手段の一つです。 通常は、 is_authenticated() メソッ ドを使うようにしてください。

is_authenticated()

常に True を返します。ユーザを認証済みかどうかを調べる一つの方 法です。このメソッドの戻り値は、ユーザが正しいパーミッションを持っ ているか、あるいはアクティブなユーザであるかどうかに関係なく、ユー ザが正しいユーザ名とパスワードを入力したことだけを示します。

get_full_name()

first_namelast_name をスペースでつな げた文字列を返します。

set_password(raw_password)

渡された文字列をハッシュ化し、ユーザのパスワードに設定します。 User オブジェクトの保存は行い ません。

check_password(raw_password)

渡された文字列がこのユーザの正しい文字列ならば True を返します。 (このメソッドは比較時にパスワードのハッシュ処理を行います)

set_unusable_password()

ユーザにパスワード未設定のマークをつけます。パスワード未設定の状態 は、パスワードが空の文字列である状態と区別されます。パスワード未設 定状態のユーザに対して check_password() を呼び出 すと、決して True を返しません。このメソッドは User オブジェクトを直接保存し ません。

この機能は、 LDAP ディレクトリのような外部の認証ソースを使ってアプ リケーションの認証を行いたい場合に必要です。

has_usable_password()

ユーザに対して set_unusable_password() を 呼び出し、パスワードが未設定状態であれば False を返します。

get_group_permissions(obj=None)

ユーザが自分の属するグループから得ているパーミッションを表す文字列 からなるリストを返します。

リリースノートを参照してください

もし obj が引数に渡されていれば、その種類のオブジェクトへ対する、 属するグループから得ているパーミッションしか返しません。

get_all_permissions(obj=None)

ユーザ自身のもつパーミッションと、ユーザの属するグループのパーミッ ションの両方からなるリストを返します。

リリースノートを参照してください

もし、 obj が引数に渡されていれば、その特有のオブジェクトに 対するユーザのパーミッションを返します。

has_perm(perm, obj=None)

ユーザが特定のパーミッションを持っている場合に True を返します。 パーミッション名 perm は "<application name>.<lowercased model name>" のような形式で表し ます。ユーザがアクティブでない場合、このメソッドは常に False を 返します。

リリースノートを参照してください

もし obj が引数に渡されていれば、このメソッドはモデルに対する パーミッションをチェックせず、引数のオブジェクトに対するものを チェックしようとします。

has_perms(perm_list, obj=None)

ユーザが perm_list 内のパーミッションのいずれかを持っている場合に True を返します。各々のパーミッション名は "<app label>.<permission codename>" のような形式で表します。 ユーザがアクティブでない場合、このメソッドは常に False を 返します。

リリースノートを参照してください

もし obj が引数で渡されていれば、このメソッドはモデルに対する 権限ではなく、引数のオブジェクトに対するものを調べます。

has_module_perms(package_name)

ユーザが指定した名前のパッケージ (アプリケーション) の何らかのパー ミッションを持っていれば True を返します。ユーザがアクティブで ない場合、このメソッドは常に False を返します。

email_user(subject, message, from_email=None)

ユーザにメールを送信します。 from_emailNone の場合、 Django は DEFAULT_FROM_EMAIL 設定を使います。

get_profile()

ユーザのサイト固有のプロファイル (site-specific profile) を返します。 プロファイルを使えないサイトでは django.contrib.auth.models.SiteProfileNotAvailable を送出し ます。もしくはユーザがプロファイルを持っていなければ django.core.exceptions.ObjectDoesNotExtis を送出します。 サイト固有のユーザプロファイルを定義するには、後述の 追加のユーザ情報の保存 を参照して下さい。

マネジャ関数
class models.UserManager

User モデルには、以下のヘルパ関数 を備えたマネジャがあります。

create_user(username, email=None, password=None)
email パラメータはオプションになりました。username パラメ ータは、空のものと有効でない値が出た時の ValueError を上げるものをチェックするのに使われています。

ユーザを生成して保存し、生成された User を返します。 username, email は、自動的に小文字に変更され、 password は指定した値にな り、 is_activeTrue に設定されます。

パスワードを指定しなかった場合、 set_unusable_password() を 呼び出します。

使い方は ユーザの作成 を参照してください。

make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')

指定した長さのランダムなパスワードを生成して返します。パスワードに 使える文字は文字列で指定します。 allowed_chars のデフォルト値は、 ユーザが見間違いやすい以下の文字を除いてあります:

  • i, l, I, and 1 (lowercase letter i, lowercase letter L, uppercase letter i, and the number one)
  • o, O, and 0 (uppercase letter o, lowercase letter o, and zero)
基本的な使い方
ユーザの作成

ユーザを作成する一番基本的な方法は、オブジェクトマネージャの create_user() ヘルパー関数を 使う方法です:

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
>>>
# この操作で、User オブジェクト user を保存できるようになります。
# 他のフィールドを変更したければ、属性を変更します。
>>> user.is_staff = True
>>> user.save()

Django のアドミンサイトを使用するユーザを作ることも出来ます。アドミンサイトの URL を /admin/ にひも付けると思います、 “Add user” ページは /admin/auth/user/add/ にあります。また、アドミンのメインページ(インデ ックスページ)の “Auth” セクションの “Users” へのリンクでも確認できます。 “Add user” 管理ページは、通常の管理ページ(アドミン)とはユーザネームと パスワードを、残りのフィールドを変更する前に埋めなくてはならない点で異なって います。

また、 note: もし、自身のユーザアカウントを Django のアドミンサイトを使える ようにしたいのならば、パーミッションを2つ与える必要があり、それぞれ ユーザを加える権限 ユーザを変更する権限です。(すなわち、 “Add user” と “Change user” の権限です。)もし、あなたのアカウントが 「ユーザを加える権限」は持っていても、「ユーザを変更する権限」を持っていない 場合、ユーザを加えることはできません。なぜか? それは、ユーザを加える権限を 有しているということは、スーパユーザを作る権限を有しているということで、 スーパーユーザは同様に、他のユーザを変えることができます。だから、 Django はそれに加えてユーザ変更の権限も、セキュリティ対策として 必要としているのです。

パスワードの変更
manage.py changepassword コマンドが追加されました。

manage.py changepassword *username* はコマンドラインからユーザのパスワードを変更する手続きを提供していま す。パスワードを変更するには、二度指定したユーザの変更後のパスワード を入力しなくてはいけません。二つがマッチすると、ただちにパスワードが 変更されます。ユーザを渡さないと、コマンドは最新のユーザのパスワード を変更しようとします。

パスワードの変更には set_password() を使います:

.. code-block:: python
>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username__exact='john')
>>> u.set_password('new password')
>>> u.save()

特別な意図のない限り、 password 属性を直接設定しないでください。これについては次節で説明します。

Django はどのようにパスワードを保持するか
Django 1.4 では新しくフレキシブルなパスワードのストレージシステムと PBKDF2 をデフォルトで使用しています。以前のバージョンの Django では SHA1 が使われており、他のアルゴリズムを使用することは出来ませんでした。

User オブジェクトの password フィールドは、以下の形式:

algorithm$hash

すなわちストレージアルゴリズム(storage algorithm)と、ハッシュソルト (salt)、 そしてハッシュ値(hash) はドル記号 ("$") で分割した文字列形式をとります。 アルゴリズムはいくつかのハッシュ化または Django で使えるパスワードの ストレージ方式のうちの一つです。下を見てください。ハッシュ値はハッシュ関数の 結果であります。

通常では、 Django は PBKDF2 アルゴリズムをSHA256ハッシュ関数で暗号化します。 パスワードのストレッチ機構は NIST によって勧告されています。これはほとんどの ユーザにとっては満足できるものでしょう。高い安全性で、パスワードを破るには 莫大な計算量を必要とします。

しかしながら必要に応じて、他のアルゴリズムを選択することもあるでしょう、また 必要なセキュリティの度合いに応じてカスタムアルゴリズムを使用する必要もあるこ とでしょう。繰り返すと、ほとんどのユーザはそれを必要とはしていません。もし、 必要性が確かではないなら、それは必要なことではないでしょう。もし、あなたが そうしたいのならば読み進めてください。

Django では PASSWORD_HASHERS の設定でアルゴリズムを選択することが できます。これは Django で使用するハッシュ化のアルゴリズムクラス群のリストです、 リストの最初の項目(すなわち settings.PASSWORD_HASHERS[0] )はパスワードを 保存するために使われます。そして、他の項目は有効となったハッシュで実在する パスワードをチェックするために使われます。つまり、もし違うアルゴリズムを使用 したくなったときに、 PASSWORD_HASHERS を修正する必要があり、 リストの先頭に好きなアルゴリズムを組み込んでください。

通常 PASSWORD_HASHERS

PASSWORD_HASHERS = (
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
    'django.contrib.auth.hashers.SHA1PasswordHasher',
    'django.contrib.auth.hashers.MD5PasswordHasher',
    'django.contrib.auth.hashers.CryptPasswordHasher',
)

これは、 Django は PBKDF2 を全てのパスワードの保存時に使おうとする ということです。でも、保存されたパスワードをチェックする際には、 PBKDF2SHA1, bcrypt, SHA1, その他を用います。次以降のセクションでは 高度なユーザのために、設定を変更する一般的な二つの方法を紹介します。

bcrypt を Django で使うには

Bcrypt は一般的なパスワードの保存アルゴリズムは長期間パスワードを 保持しておくためにデザインされたアルゴリズムです。 Django では デフォルトで使われていません。サードパーティのライブラリを必要とする からです。しかし、 bcrypt をサポートするにはちょびっとの労力で 使えるように Django は配慮してくれています。

Bcrypt をデフォルトのアルゴリズムで使うには、以下に従ってください。

  1. py-bcrypt ライブラリをインストールしてください( sudo pip install py-bcrypt を実行するか、ライブラリを ダウンロードして、 python setup.py install を使って インストールしてください。)

  2. PASSWORD_HASHERS を設定してください。リスト内で BCryptPasswordHasher を先頭へ。セッティングファイルは こうなります:

    PASSWORD_HASHERS = (
         'django.contrib.auth.hashers.BCryptPasswordHasher',
         'django.contrib.auth.hashers.PBKDF2PasswordHasher',
         'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
         'django.contrib.auth.hashers.SHA1PasswordHasher',
         'django.contrib.auth.hashers.MD5PasswordHasher',
         'django.contrib.auth.hashers.CryptPasswordHasher',
     )
    

    (リストの中の他の項目は、そのままにしておいてください、または Django がパスワードをアップグレードできないようにしてください。 下部を見てください)

今、Django は Bcrypt をデフォルトの パスワード保存アルゴリズムとして使おうとします。

bcrypt を使う他の方法

Django 内で bcrypt を用いる方法はいくつかあります。 Django の bcrypt サポート同士では直接的に互換性がありません。 アップグレードするために、フォームの bcrypt$(生の bcrypt アウトプット)内で、データベースのハッシュを修正する必要が あります。例えば: `bcrypt$$2a$12$NT0I31Sa7ihGEWpka9ASYrEFkhuTNeBQ2xfZskIiiJeyFXhRgS.Sy

作業面の向上

PDKDF2 と、 bcrypt アルゴリズムは、沢山のイテレーションとハッシュの循環を 用います。これはシステムへの攻撃の手を遅めます。ハッシュ化された パスワードによって攻撃に立ち向かいます。しかし、コンピュータのマシンパワー の向上とともに、必要なイテレーションの数も増加しました。それ相当なものを 選んでいます( Django のリリースの度に数を増やしてます)が、その強度を 増したい時もあれば減らしたい時もあるでしょう、セキュリティ環境に応じて、 または実行環境に応じて。そうするために、サブクラスを作り適切なアルゴリズム と iterations パラメータの上書きをするでしょう。たとえば、イテレーション の回数を PBKDF2 で増加させるには:

  1. サブクラスを django.contrib.auth.hashers.PBKDF2PasswordHasher という 名前で作ります。:

    from django.contrib.auth.hashers import PBKDF2PasswordHasher
    
    class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher):
        """
        PBKDF2PasswordHasher のサブクラスで百回以上イテレーションします
        """
        iterations = PBKDF2PasswordHasher.iterations * 100
    

    プロジェクトのどこかでこれを保存してください。例えば、 myproject/hashers.py のようなファイルを置くのがよいでしょう。

2. PASSWORD_HASHERS の中の最初の項目として新しいハッシュを加え ます:

PASSWORD_HASHERS = (
    'myproject.hashers.MyPBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2PasswordHasher',
    'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
    'django.contrib.auth.hashers.BCryptPasswordHasher',
    'django.contrib.auth.hashers.SHA1PasswordHasher',
    'django.contrib.auth.hashers.MD5PasswordHasher',
    'django.contrib.auth.hashers.CryptPasswordHasher',
)

これだけで – Django は PBKDF2 を使ってパスワードを保存する時に、もっと 沢山のイテレーションを用いれるようになりました。

パスワードのアップグレード

ログインする時に、パスワードがアルゴリズムよりも好ましいもので保存されて いれば、 Django は自動的にアルゴリズムをそちらにアップグレードします。 この意味は、古い Django でもユーザがログインするたびにセキュアなものに なるということです、そしてまた新しく(そしてより良い)パスワードの 保持アルゴリズムが作られるたびにそちらへ切り替えられるということです。

しかしながら、 Django がアップグレードできるパスワードはアルゴリズムとして PASSWORD_HASHERS のなかで宣言されているものだけです。新しい システムにアップグレードする時には、 以前使っていたものを削除しない こと を気をつけてください。もし削除してしまうと、消去してしまったアルゴリズムを いつまでもアップグレードできないでいることになります。

匿名ユーザ (Anonymous users)
class models.AnonymousUser

django.contrib.auth.models.AnonymousUserdjango.contrib.auth.models.User と同じインタフェースを実装した クラスですが、以下の点で User と異 なります:

おそらく、実践上意識して AnonymousUser オブジェクトを使う必要はないはずです。とはいえ、匿名ユーザは次節で述べるよ うな形で Web リクエストで使われています。

スーパユーザの作成

INSTALLED_APPS'django.contrib.auth' を追加した直後に manage.py syncdb を実行すると、スーパユーザの作成を促す プロンプトを表示します。後でスーパユーザを作成したい場合には、以下のように コマンドラインユーティリティを使います:

manage.py createsuperuser --username=joe --email=joe@example.com

ユーティリティはパスワードの入力を促します。入力すると、ユーザは即座に作成 されます。 --username--email オプションを省 略すると、ユーティリティはそれらの値を入力するよう促します。

古い Django も使っている場合、以前からあるコマンドラインのスーパユーザ作成 方法も使えます:

python /path/to/django/contrib/auth/create_superuser.py

/path/to/ は自分のシステムの Django コードベースへのパスに応じて読 み変えて下さい。 manage.py は自動的に正しいパスと環境変数を決定するので、 manage.py を使うよう推奨します。

追加のユーザ情報の保存

ユーザに追加の情報をひもづけて保存したい場合のために、 Django ではサイトご とにユーザに関連付けられた「ユーザプロファイル」を取り出すためのメソッドを 提供しています。

ユーザプロファイルを利用するには、まず、ユーザにひもづけて保存したい情報を 入れるためのフィールドや持たせたいメソッド、そして User モデルへの user という名前で OneToOneField を持ったモデルを定義します。 OneToOneField には User に対してユーザごとにモデルが一つだけ生成 されるようにします。例をあげると:

from django.contrib.auth.models import User

class UserProfile(models.Model):
    # このフィールドが必要です.
    user = models.OneToOneField(User)

    # 他のフィールドはこちらにあります
    accepted_eula = models.BooleanField()
    facorite_animal = models.CharField(max_length=20, default="Dragons.")

このモデルをあるサイトのユーザプロファイルモデルにするには、 AUTH_PROFILE_MODULE に以下の内容をドット区切りの文字列で指定しま す:

  1. ユーザプロファイルモデルを定義している (小文字に変換した) アプリケーショ ン名 (別の言い方をするなら、 manage.py startapp で アプリケーションを作成するときに指定する名前を全て小文字にしたもの)。
  2. (小文字に変換した) モデルクラス名

例えば、プロファイルモデルが UserProfile という名前のクラスで、 accounts というアプリケーションで定義されているなら、設定値は以下のよう になるでしょう:

AUTH_PROFILE_MODULE = 'accounts.UserProfile'

ユーザプロファイルモデルが定義されていて、この規則通りになっていた場合、 User のオブジェクトは、 get_profile() というメソッドを 持つでしょう。 – これは User ユーザ プロファイルモデルに関連づけられたインスタンスを返します。

get_profile() のメソッドは、 プロファイルを作る訳ではありません。もし存在しないものがあれば、 自身でユーザモデルの django.db.models.signals.post_save のハンドル のシグナルを登録する必要と、ハンドラーの中で、 createdTrue ならばユーザプロファイルと関連させて作るようにします:

# models.py の中で

from django.contrib.auth.models import User
from django.db.models.signals import post_save

# 上のユーザプロファイルの定義
# ...

def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

post_save.connect(create_user_profile, sender=User)

See also

シグナル シグナルについての詳しい情報です。

Web リクエストに対する認証

ここまでのドキュメントは、認証関連のオブジェクトを操作するための低水準の API について扱ってきました。より高水準の API では、 Django はこれらの認証フ レームワークを リクエストオブジェクト シ ステム内にフックできます。

まず、 SessionMiddleware およ び AuthenticationMiddlewareMIDDLEWARE_CLASSES 設定に追加して、これらのミドルウェアをインス トールします。詳しくは セッションのドキュメント を参照してください。

ミドルウェアをインストールしたら、ビューから request.user にアクセスできるように なります。 request.user は現在ログイ ンしているユーザの User オブジェクトを 表します。ユーザがログインしていなければ、 request.userAnonymousUser のインスタンスになります (前節を参照してください)。ログインユーザと匿名ユーザは、 is_authenticated() で以下のように 区別できます:

if request.user.is_authenticated():
    # Do something for authenticated users.
else:
    # Do something for anonymous users.
ユーザをログインさせる

Django では、 django.contrib.auth の中で、 authenticate()login() という二つの関数を提供しています。

authenticate()

あるユーザ名とパスワードに対する認証を行うには、 authenticate() を使ってください。この関数 は二つのキーワード引数、 usernamepassword をとり、ユーザ名 に対してパスワードが有効であった場合に User オブジェクトを返します。パス ワードが無効だった場合には、 authenticate()None を返します。例 えば:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
    if user.is_active:
        print "You provided a correct username and password!"
    else:
        print "Your account has been disabled!"
else:
    print "Your username and password were incorrect."
login()

ユーザをログインさせるには、ビューの中で login() を使ってください。この関数は HttpRequest オブジェクトと User オブジェクトを引数にとります。 login() は Django のセッションフレームワー クを使って、ユーザの ID をセッションに保存します。従って、上でも述べた ように、セッションミドルウェアをインストールしておかねばなりません。

ユーザがログインする時に、匿名ユーザだった時のデータセットを残しておく 方法にも触れておきます。

以下の例は authenticate()login() の使い方を示しています:

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(username=username, password=password)
    if user is not None:
        if user.is_active:
            login(request, user)
            # Redirect to a success page.
        else:
            # Return a 'disabled account' error message
    else:
        # Return an 'invalid login' error message.

authenticate() は最初に呼び出してください

ユーザを手動でログインさせる場合、 login() を呼び出す前に 必ず authenticate() を呼び出してください。 authenticate() は、 User オブジェクトに、そのユーザが 認証バックエンドによって正しく認証されたことを示す属性を付加します。 (詳しくは 認証バックエンドのドキュメント を参照してください) この情報が後でログインの処理で必要だからです。

ユーザのパスワードを手動で管理する
django.contrib.auth.hashers モジュールは関数セットを ハッシュ化したパスワードの作成と有効化のために提供しています。 独立してそれらを使うことが出来ます。
check_password()
リリースノートを参照してください

ユーザ認証を手動で行うために平文パスワードとデータベース上のハッシュ化 パスワードを比較したい場合には、 django.contrib.auth.hashers.check_password() という便宜関数を使えます。この関数は、調べたい平文パスワードと、比較対 象のデータベースに格納されているユーザの password フィールド全体の 二つの引数をとり、二つが一致すれば True を、そうでなければ False を返します。

make_password()
リリースノートを参照してください

アプリケーションの中で使うフォーマット通りにハッシュ化したパスワードを作り るには、二つの引数をとります: ハッシュ化するアルゴリズムとプレーンテキスト のパスワードです。今サポートされているアルゴリズムは : 'sha1', 'md5' で、もし crypt のライブラリがインストールされ ていれば、それも使えます。もし、二つ目の引数が None だと、使えない パスワードがかえってきます(一つは、 django.contrib.auth.hashers.check_password() によって受け付けられ ません)

is_password_usable()
リリースノートを参照してください

与えられた文字列がハッシュ化されたパスワードであれば、それをチェックしま す。 django.contrib.auth.hashers.check_password() に反しないかが 確かめられます。

ユーザをログアウトさせる
logout()

django.contrib.auth.login() でログインしたユーザをログアウトさ せるには、ビューの中で django.contrib.auth.logout() を使ってください。この関数は、 HttpRequest オブジェクトを引数に取り、戻り値を持 ちません。例を以下に示します:

from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    # Redirect to a success page.

ユーザがログインしていなくても logout() は エラーを送出しないことに注意してください。

logout() を呼び出すと、現在のリクエストに 結び付いたセッションデータを全て抹消します。その時に記憶されていたデー タは全て除去されます。これは、他のユーザが同じブラウザを使ってログイン し、直前にブラウザを使っていたユーザのセッションデータを読み出したりで きないようにするためです。ユーザのログアウト後に何らかのセッションデー タを記憶させたければ、 django.contrib.auth.logout()後で 行ってください。

ログインとログアウトのサイン
リリースノートを参照してください

auth 認証のフレームワークは二つ signals を使います。それは、ユーザがログインまたはログアウトした時のお知らせ のためです。

django.contrib.auth.signals.user_logged_in

ユーザがログインに成功した時に送信します。

このシグナルが引数で送られます:

sender
上にある通り: このクラスはユーザがログインした時のものです
request
最新のものは HttpRequest のインスタンスです。
user
ログインしたユーザのインスタンスです。
django.contrib.auth.signals.user_logged_out

ユーザがログアウトする時に送信するものは

sender
上にあるとおり: ログアウトしたユーザのクラスまたは ユーザが認証されていなければ None を返します。
request
最新のものは HttpRequest instance.
user
ログアウトしたユーザのインスタンスか、もし認証されていな ければ None を返します。
ログインユーザだけがアクセスできるように制限をかける
生真面目な方法

ページへのアクセスを制限する単純で生真面目な方法は、 request.user.is_authenticated() をチェックして、ログインページにリダイレクトするというものです:

from django.http import HttpResponseRedirect

def my_view(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/?next=%s' % request.path)
    # ...

あるいは、エラーメッセージを出しても構いません:

def my_view(request):
    if not request.user.is_authenticated():
        return render_to_response('myapp/login_error.html')
    # ...
login_required デコレータ
decorators.login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None])

手間を省くために、 login_required() デコレータを使え ます:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...

login_required() に従うと:

  • もし、ユーザがログインしていなければ、クエリ文字列の現在の完全 パスを通って、 settings.LOGIN_URL へとリダイレクトします。例えば: /accounts/login/?next=/polls/3/
  • もし、ユーザがログインしていれば、通常のビューを実行します。 ビューコードは、ユーザがログインしているかという仮定には縛られません。

通常、ユーザがリダイレクトされる認証が成功した場合のパスは クエリ文字列のパラメータの中に "next" という名前で保持されています。 もし、このパラメータに別の名前をあてがいたい場合には、 login_required() はオプションの redirect_field_name パラメタをとります。例えば:

from django.contrib.auth.decorators import login_required

@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
    ...

もし、 redirect_field_name に値を設定した場合、ログインテンプレート もそれに応じて変更する必要があります、テンプレートのコンテキスト(context) 変数が保持するリダイレクトパスは redirect_field_name で設定した値を、 "next" (通常)のかわりにキーとして扱うからです。

リリースノートを参照してください

login_required() もまた、オプション として login_url パラメータを取ります。例えば:

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def my_view(request):
    ...

login_url パラメータを設定しない場合には settings.LOGIN_URL に適切な Django のビュー関数 を対応づけておかねばなりません。例えば URLconf に以下のような行を設定します:

(r'^accounts/login/$', 'django.contrib.auth.views.login'),
views.login(request[, template_name, redirect_field_name, authentication_form])

URL name: login

the URL documentation に URL パターンについて 詳細にのっているので見てください。

django.contrib.auth.views.login は以下のような処理を行います:

  • GET で呼び出されると、同じ URL に対して POST を行うためのログ インフォームを表示します。これについては後でもう少し説明します。
  • POST で呼び出されると、ユーザのログイン処理を試みます。ログイ ンに成功すると、ビューは next に示された URL にリダイレクトし ます。 next を指定しない場合、 settings.LOGIN_REDIRECT_URL (デフォルト値は /accounts/profile/) にリダイレクトします。ロ グインに失敗すると、ログインフォームを再度表示します。

開発者は registration/login.html という名前のテンプレート上でログイ ンフォームを提供せねばなりません。 Django はこのテンプレートに、以下の 3 つのテンプレートコンテキスト変数を渡します:

  • form: ログインフォームを表現する Form オブジェクトです。 Form オブジェクトの詳細 は forms のドキュメント を参照してく ださい。
  • next: ログイン成功後にリダイレクトされる先の URL です。 URL にはクエリ文字列を含めてかまいません。
  • site: 現在の Site, SITE_ID のセッティングに従っています。もし、サイト フレームワークがインストールされていなければ、これは、 RequestSite のインスタンスが セットされます。これはサイトの名前とドメインを現在の HttpRequest から取ってきます。
  • site_name: site.name のための別名(alias)です。もし、 サイトフレームワークがインストールされていなければ、 request.META['SERVER_NAME'] の値がセットされます。サイトについてもっと知りたければ “sites” フレームワーク を見てください。

registration/login.html テンプレートを呼び出したくないのなら、 URLconf を通じて外部パラメタ template_name をビューに渡してください。 例えば、 myapp/login.html を使いたければ、URLconf の行は以下の ようになります:

(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}),

GET フィールドの名前を指定できます。 GET フィールドは、 redirect_field_name からビューへの、 ログイン後のリダイレクト先を含むURLを設定してください。 通常では、このフィールドは next です。

編集の雛型にできるような registration/login.html テンプレートの 例を以下に示します。このテンプレートは、 content ブロックの定義された base.html があるという前提で書かれています:

{% extends "base.html" %}
{% load url from future %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

<form method="post" action="{% url 'django.contrib.auth.views.login'%}">
{% csrf_token %}
<table>
<tr>
    <td>{{ form.username.label_tag }}</td>
    <td>{{ form.username }}</td>
</tr>
<tr>
    <td>{{ form.password.label_tag }}</td>
    <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>

{% endblock %}
リリースノートを参照してください

もし、他の認証を使っているならば( 他の認証データソースを使う を見て ください)カスタムされた認証フォームを通って、 authentication_form パラメータを経てログインビューへと行きます。このフォームは request キーワード引数を自身の __init__ メソッドの中で受け取らなくては いけません。そして、 get_user メソッドは認証されたユーザーオブジェクト を返します。(このメソッドは、成功したフォームバリデーションの 後に一度だけ呼ばれます。)

リリースノートを参照してください

login() のビューと その他の組み込みビュー は今、 全て TemplateResponse のインスタンス を返します。これは、レスポンスデータをレンダリング前に容易に改変できる ようにします。もっと情報が欲しければ TemplateResponse documentation を見て ください。

その他の組み込みビュー

login() ビューに加えて、認証システムはその他の役に立つビューを django.contrib.auth.views: に持っています。:

logout(request[, next_page, template_name, redirect_field_name])

ユーザをログアウトさせます。

URL name: logout

URL のドキュメント を見てください。もっと 詳しく URL パターンを使う上での情報が載っています。

オプション引数:

  • next_page: ログアウト後にリダイレクトされる URL です。
  • template_name: ログアウトページのテンプレートの完全な名前です。 この引数を省略すると、デフォルト値の registration/logged_out.html を使います。
  • redirect_field_name: GET フィールドの名前で、ログアウト後の リダイレクト先 URL を含みます。 GET パラメータが渡されると next_page が上書きされます。

テンプレートコンテキスト:

  • title: “Logged out” の文字列を翻訳した値になります。
  • site: 現在の Site で、 SITE_ID のセッティングに従っています。もし、サイト フレームワークをインストールしていなければ、これは RequestSite のインスタンス がセットされ、サイトの名前てドメインを現在の HttpRequest から取ってきます。
  • site_name: site.name のための別名(alias)です。もし、 サイトフレームワークがインストールされていなければ、 request.META['SERVER_NAME'] の値がセットされます。サイトについてもっと知りたければ “sites” フレームワーク を見てください。
logout_then_login(request[, login_url])

ユーザをログアウトさせてから、ログインページにリダイレクトします。

オプション引数:

  • login_url: ログインページへのリダイレクト先です。この引数を省 略すると、デフォルト値の settings.LOGIN_URL を使います。
password_change(request[, template_name, post_change_redirect])

ユーザがパスワードを変更できるようにします。

オプション引数:

  • template_name: パスワード変更ページのテンプレートの完全な名前 です。この引数を省略すると、デフォルト値の registration/password_change_form.html を使います。

  • post_change_redirect: パスワードの変更に成功した場合の URLリダイレクト先です。

    リリースノートを参照してください
  • password_change_form: “パスワードの変更” フォームのカスタマイズ は、 user のキーワード引数を受け取らなくてはいけません。 フォームは実際にウーザのパスワードが変更される責任があります。 通常では、 PasswordChangeForm になります。

テンプレートコンテキスト:

  • form: パスワード変更のためのフォームです。
password_change_done(request[, template_name])

ユーザがパスワードを変更した後のページを表示するためのビューです。

URL name: password_change_done

オプション引数:

  • template_name: パスワード変更完了ページのテンプレートの完全な 名前です。この引数を省略すると、デフォルト値の registration/password_change_done.html を使います。
password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect, from_email])

ユーザがパスワードをリセットできるように、一回しか使用できないリンクを 作成します。また、新たなパスワードをメールで送信します。

from_email 引数が加えられました。
使えないパスワードでフラグ付けされたユーザ( set_unusable_password() を見てください)は、パスワードのリセットをリクエストできません。 外部の認証ソース、例えばLDAPのようなものを使う際の悪用を防ぐためです。

URL name: password_reset

オプション引数:

  • template_name: パスワードリセットページのテンプレートの完全な 名前です。この引数を省略すると、デフォルト値の registration/password_reset_form.html を使います。

  • email_template_name: 新しいパスワードを e-mail で送信する際に 使うテンプレートの完全な名前です。この引数を省略すると、デフォル ト値の registration/password_reset_email.html を使います。

  • subject_template_name: 新しいパスワードのemailを生成するのに使う テンプレートのフルネームです。デフォルトでは registration/password_reset_email.html が設定されています。

    リリースノートを参照してください
  • password_reset_form: パスワードのセットに使うフォームです。 デフォルトでは PasswordResetForm が設定されています。

  • token_generator: パスワードのチェックに使うクラスのインスタンスで す。通常は default_token_generator に設定されています、これは django.contrib.auth.tokens.PasswordResetTokenGenerator のインスタ ンスです。

  • post_reset_redirect: パスワードの変更が成功した後にリダイレクト する URL です。

  • from_email: 有効な email アドレスです。通常 Django が使うのは DEFAULT_FROM_EMAIL です。

テンプレートコンテキスト:

  • form: パスワードリセットのためのフォームです。 (上にある password_reset_form` を見てください)

Email テンプレートコンテキスト:

  • email : user.email の別名です。
  • user: 現在の User で、 email フォームフィールドに従っています。アクティブユーザのみ が、パスワードをリセットすることができます。( User.is_active is True )
  • site_name: sit.name のエイリアス(別名)です。もし、 インストール済みのサイトフレームワークがない場合は、 request.META['SERVER_NAME'] の値をセットします。これについては “sites” フレームワーク を ご覧ください。
  • domain: site.domain のエイリアス(別名)です。もし、 サイトフレームワークがインストールされていない場合、これは request.get_host() の値をセットします。
  • protocol: http or https
  • uid: ユーザのIDは36進数でエンコードされます。
  • token: トークンはパスワードが有効なものかをチェックします。

registration/password_reset_email.html ( email ボディテンプレー ト)にサンプルがあります:

{% load url from future %}
誰かがパスワードの変更を求めたら {{ email }} のように
email から送られたリンクへと飛ぶことになります。下のリンクに従ってください。:
{{ protocol }}://{{ site_name }}{% url 'auth_password_reset_confirm' uidb36=uid token=token %}

同じテンプレートコンテキストが、サブジェクトテンプレートに使われる 時、サブジェクトは一行のプレーンテキストでなくてはなりません。

views.password_reset_done(request[, template_name])

ユーザがパスワードをリセットした後のページを表示するためのビューです。 このビューは password_reset() ビューが post_reset_redirect の URL セットを所持していない時にデフォルトで呼ばれます。

オプション引数:

  • template_name: パスワードリセット完了ページのテンプレートの完 全な名前です。この引数を省略すると、デフォルト値の registration/password_reset_done.html を使います。
password_reset_confirm(request[, uidb36, token, template_name, token_generator, set_password_form, post_reset_redirect])

Presents a form for entering a new password.

オプション 引数:

  • uidb36: 36進数でエンコードされたユーザのIDです。デフォルトでは None です。
  • token: パスワードが有効かをチェックするためのトークンです。 デフォルトでは None です。
  • template_name: 確定したパスワードのビューを表示するテンプレート のフルネームです。
  • token_generator: パスワードをチェックするためのクラスのインスタ ンスです。これは default_token_generator がデフォルトです。 そして、 django.contrib.auth.tokens.PasswordResetTokenGenerator のインスタンスでもあります。
  • set_password_form: パスワードをセットするためのフォームとして 使用されます。 SetPasswordForm がデフォルトです。
  • post_reset_redirect: パスワードのリセットが終了した後に リダイレクトされる先です。デフォルトでは None です。

テンプレートコンテキスト:

  • form: 新しいユーザのパスワードをセットするための フォームです(上にある set_password_form を見てください)
  • validlink: Boolean 型です。 True でリンクが有効か( uidb36 とトークンの組み合わせ)またはまだ使われていないかです。
password_reset_complete(request[, template_name])

ユーザにパスワードの変更が成功したということを伝えるためのビューです。

URL name: password_reset_complete

オプション引数:

  • template_name: ビューを表示するためのテンプレートのフルネームで す。registration/password_reset_complete.html がデフォルトの 値になります。
ヘルパー関数
redirect_to_login(next[, login_url, redirect_field_name])

ログインページへリダイレクトします、ログインに成功したら、トップ画面で はなく、違う URL へと戻ります。

必要な 引数:

  • next: ログインに成功した後のリダイレクト先の URL です。

オプション 引数:

  • login_url: リダイレクトするログインページの URL です。 デフォルトでは settings.LOGIN_URL となります。
  • redirect_field_name: GET フィールドに含まれているログアウト後 にリダイレクトする先の URL です。 GET パラメータが渡されていれば next を上書きします。
組み込みフォーム

組み込みビューを使いたくないけれども、フォームクラスを書かずに済ませたい場 合のために、認証システムは組み込みのフォームを django.contrib.auth.forms でいくつか提供しています:

class AdminPasswordChangeForm

Admin インタフェースでユーザのパスワード変更に使われているフォームです。

class AuthenticationForm

ユーザをログインさせるためのフォームです。

class PasswordChangeForm

ユーザにパスワードを変更させるためのフォームです。

class PasswordResetForm

パスワードをリセットし、新たなパスワードを送信するためのフォームです。

class SetPasswordForm

古いパスワードを入力することなく、パスワードを変更させるための フォームです。

class UserChangeForm

ユーザ情報とパーミッションを変更するためのアドミンインターフェースです

class UserCreationForm

新たなユーザを作成するためのフォームです。

テストにパスしたログインユーザだけがアクセスできるように制限をかける

特定のパーミッションやその他のテストの結果に応じたアクセスの制限には、前節 で説明したの本質的に同じことをします。

一番簡単な方法は、ビュー内で直接 request.user に対するテストを実行す るというものです。例えば、以下のビューではユーザがログイン済みで、かつ polls.can_vote というパーミッションを持っているかチェックします:

def my_view(request):
    if not request.user.has_perm('polls.can_vote'):
        return HttpResponse("You can't vote in this poll.")
    # ...
user_passes_test(func[, login_url=None])

user_passes_test デコレータを使えば、手間を省けます:

from django.contrib.auth.decorators import user_passes_test

@user_passes_test(lamda u: u.has_perm('polls.can_vote'))
def my_view(request):
    ...

ここでは、簡単な例としてパーミッションのテストに user_passes_test() を使っています が、単にあるユーザがあるパーミッションを有しているかをテストしたいだけ なら、後で解説する django.contrib.auth.decorators.permission_required() デコレータ を使えます。

user_passes_test() には必須の引数 が一つあります。この引数は、 User を引数に取り、ユーザにページのビューを許可する場合には True を返す 呼び出し可能オブジェクトでなければなりません。 user_passes_test()User が匿名かどうかを自動的に調べ ないので注意してください。

user_passes_test() はオプション の引数として login_url をとります。この引数を使うとログインページへ の URL を指定できます (デフォルトでは settings.LOGIN_URL になります)。

例えば:

from django.contrib.auth.decorators import user_passes_test

@user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/')
def my_view(request):
    ...
permission_required デコレータ
decorators.permission_required([login_url=None, raise_exception=False)

あるユーザが特定のパーミッションを有しているかのチェックは、比較的よく ある操作なので、 Django はショートカットとして permission_required() という デコレータを用意しています。このデコレータを使うと、上の例は以下のよう に書き直せます:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote')
def my_view(request):
    ...

As for the User.has_perm() method, permission names take the form "<app label>.<permission codename>" (すなわち polls.choice は は polls アプリケーションのモデルへのパーミッションです.)

permission_required() もまた、 login_url を引数に取れます。例えば:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url='/loginpage/')
def my_view(request):
    ...

login_required デコレータと同様、 login_url のデフォルト値は settings.LOGIN_URL です。

リリースノートを参照してください

raise_exception パラメータが追加されました。もし、パラメータが 与えられると、でコレータは PermissionDenied を送出します。 the 403 (HTTP Forbidden) view を、ログインページへのリダイレクトの代わりに出します。

アクセスを汎用ビューに制限する

アクセスを 汎用ビュー に制限するには、 View.dispatch という クラスのメソッドをデコレートする必要があります。 クラスのデコレート の詳細を確認してください。

汎用ビューをベースにした関数

class-based generic view にアクセスを制限 するにはビューを囲む薄いラッパコードを書き、URLconf を変更して、 ジェネリックビュー自体ではなくラッパコードを指すようにします。例えば:

from django.views.generic.date_based import object_detail

@login_required
def limited_object_detail(*args, **kwargs):
    return object_detail(*args, **kwargs)

パーミッション (Permission)

Django には単純なパーミッション機構がついてきます。このパーミッション機構は 特定のユーザやユーザのグループに対してパーミッションを結びつける手段を提供 します。

パーミッション機構は Django の admin サイトでも使われていますが、自作のコー ド内でも自由に使えます。

  • “add” フォームをビューし、オブジェクトを追加するためのアクセスを、そ の型のオブジェクトの “add” パーミッションを持つユーザに制限しています。
  • 変更リストをビューし、”change” フォームをビューしてオブジェクトを変更 するためのアクセスを、その型のオブジェクトの “change” パーミッション を持つユーザに制限しています。
  • あるオブジェクトを削除するためのアクセスを、その型のオブジェクトの “delete” パーミッションを持つユーザに制限しています。

パーミッションはオブジェクトインスタンスごとではなく、オブジェクトの型ごと にグローバルに設定されます。例えば、「Mary はニュース記事を変更できる」のよ うには書けますが、現状では、「Mary はニュース記事を変更できる。ただし彼女が 書いた分だけ」とか、「Mary はある状態にある記事か、ある日時に出版されたか、 ある ID の記事だけを変更できる」のようには書けません。後者の機能については は、現在 Django の開発者達が議論中です。

デフォルトのパーミッション

INSTALLED_APPS 設定に django.contrib.auth を追加している場合、 インストールされている全てのアプリケーションのモデルについて、追加 (add)、 変更 (change)、および削除 (delete) というデフォルトのパーミッションが作成さ れます。

これらのパーミッションは、 manage.py syncdb を実行した ときに生成されます。厳密には、 django.contrib.authINSTALLED_APPS 設定に追加した直後に syncdb を実行する と、その時インストールされていた全てのアプリケーションと、新たに追加したア プリケーションのデフォルトパーミッションが作成されます。以後、 manage.py syncdb を実行するたびに、新たに追加されたモデ ルのデフォルトパーミッションが生成されます。

もし、アプリケーションを app_label foo という名前にしていてモデルの名前を Bar だと仮定します、 標準のパーミッションをテストするにはこのようにします:

  • add: user.has_perm('foo.add_bar')
  • change: user.has_perm('foo.change_bar')
  • delete: user.has_perm('foo.delete_bar')
カスタムのパーミッション

カスタムのパーミッションを生成するには、 permissions という モデルのメタ属性 を使います。

この例では、 Task モデルに三つのカスタムパーミッションを作っています、 すなわち Task インスタンスによってユーザが出来るアクションが決まります。 アプリケーション内でのコードは:

class Task(models.Model):
    ...
    class Meta:
        permissions = (
            ("view_task", "Can see available tasks"),
            ("change_task_status", "Can change the status of tasks"),
            ("close_task", "Can remove a task by setting its status as closed"),
        )

この定義の役割は特別なパーミッションを追加することだけです。 manage.py syncdb を実行すると、コードは パーミッションをチェックする役割を負います。それが実行されるのは、 ユーザがアプリケーションによって機能へとアクセスしようとする時 (タスクを見て、タスクのステータスを変え、タスクを閉じるような動作) です。上の例に続ければ、ユーザがタスクを見る時にそれと共にチェックし ます:

user.has_perm('app.view_task')
API リファレンス
class models.Permission
フィールド

Permission オブジェクトには以下のフィー ルドがあります:

Permission.name

必須です。50 文字以下です。例: 'Can vote'

Permission.content_type

必須です。インストール済みの Django モデルのレコードが入った django_content_type データベーステーブルへの参照です。

Permission.codename

必須です。 100 文字以下です。例: 'can_vote'

メソッド

Permission オブジェクトは、他の Django モデル と同じく、標準的なデータアクセスメソッ ドを備えています。

プログラム的にパーミッションを作る

Meta クラス内でカスタムパーミッションが定義される一方、 直接的にパーミッションを作ることもまたできます。例えば、 myappBlogPost モデルに対して、 can_publish パーミッションを作ろうとすると:

from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get(app_label='myapp', model='BlogPost')
permission = Permission.objects.create(codename='can_publish',
                                       name='Can Publish Posts',
                                       content_type=content_type)

パーミッションは自身のクラスの user_permissions アトリビュートか、 Grouppermissions アトリビュートから User へと割り当てることができます。

認証データのテンプレート上での扱い

RequestContext を使っている場合、ログイン ユーザとそのパーミッションに テンプレートコンテキスト (template context) を使っ てアクセスできます。

技術的な話題

デフォルトの設定では、テンプレートコンテキストに RequestContext を使うようになっていて、 かつ TEMPLATE_CONTEXT_PROCESSORS の設定に "django.contrib.auth.context_processors.auth" が入っています。この場合にのみ、 上記の変数をテンプレートコンテキストの中で使えるようになります。詳しくは RequestContext のドキュメント を参照してください。

ユーザ

現在のログインユーザは、 User インスタ ンスであっても AnonymousUser インスタ ンスであっても、テンプレート変数 {{ user }} に入ります:

{% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
    <p>Welcome, new user. Please log in.</p>
{% endif %}

このテンプレートコンテキスト変数は、 RequestContext が使われていないと 使うことが出来ません。

パーミッション

現在のログインユーザのパーミッションはテンプレート変数 {{ perms }} に入っ ています。この変数はパーミッションオブジェクトをテンプレートで扱いやすくす るためのプロキシ (proxy) である、 django.contrib.auth.context_processors.PermWrapper のインスタンスです。

バージョン1.3の変更で、 django.contrib.auth.context_processors の中に PermWrapper が置かれました。

{{ perms }} オブジェクトに対して 1 段の属性参照を行うと、実際には User.has_module_perms へのプロキシになっています。例えば下記の例は、ログインユーザが foo とい うアプリケーションへのパーミッションを持っている場合に True を表示しま す:

{{ perms.foo }}

2 段階属性を探索すると、 User.has_perm へのプロキ シに到達します。以下の例では、ログインユーザが foo.can_vote へのパーミッ ションを持つ場合に True を表示します:

{{ perms.foo.can_vote }}

こうして、テンプレート内で {% if %} 文を使ってチェックを行えます:

{% if perms.foo %}
    <p>You have permission to do something in the foo app.</p>
    {% if perms.foo.can_vote %}
        <p>You can vote!</p>
    {% endif %}
    {% if perms.foo.can_drive %}
        <p>You can drive!</p>
    {% endif %}
{% else %}
    <p>You don't have permission to do anything in the foo app.</p>
{% endif %}

グループ (Group)

グループは、パーミッションを適用するユーザのカテゴリを作ったり、一連のユー ザに何らかのラベルを適用するための汎用的な手段です。一人のユーザは複数のグ ループに所属できます。

グループに所属したユーザは、そのグループに許可されているパーミッションを自 動的に得ます。例えば、 Site editors というグループに can_edit_home_page というパーミッションをがあれば、そのグループに属する ユーザはみな, can_edit_home_page のパーミッションを持ちます。

パーミッションだけではなく、グループはユーザをカテゴリに分けてラベルを付け たり、機能を拡張したりできます。例えば、 '特別なユーザ' のグループを作 成して、そのグループのユーザ向けに、例えばサイト内のメンバー限定エリアへの アクセスを提供したり、メンバーだけに email メッセージを送るといった、特別 な処理を行うコードを書けます。

メッセージ (Message)

API リファレンス
class models.Group
フィールド

Group オブジェクトはそれに続くフィールドを 持っています:

Group.name

必須です。 80文字以下です。どんな文字でも使えます。例えば: 'Awesome Users' このように。

Group.permissions

Many-to-many フィールド Permissions:

group.permissions = [permission_list]
group.permissions.add(permission, permission, ...)
group.permissions.remove(permission, permission, ...)
group.permissions.clear()

他の認証データソースを使う

ほとんどのケースでは、 Django についてくる認証メカニズムで十分のはずですが、 場合によっては別の認証データソース (authentication source) をフックしたい、 すなわち、Django 外のユーザ名やパスワードデータや認証メソッドを使いたいよう なケースもあることでしょう。

例えば、会社が LDAP 構成を使って社員のユーザ名やパスワードを管理していると しましょう。ネットワーク管理者にとっても、またユーザ自身にとっても、 LDAP とDjango ベースのアプリケーションの双方で別々のアカウントを維持するのはいさ さか骨の折れる作業です。

こうした状況を扱うために、 Django の認証システムは別の認証ソースをプラグイ ンできるようになっています。 Django がデフォルトで使っているデータベースの スキームをオーバライドしたり、デフォルトのシステムを他のシステムと並列して 動作させたりできます。

authentication backend reference を見てください。 もっと詳しい情報が載っています。

他の認証バックエンドを指定する

舞台裏では、 Django は認証に使う「認証バックエンド」のリストを維持していま す。前述の 「ユーザをログインさせる」 で説明したように django.contrib.auth.authenticate() を呼び出すと、Django は全ての認 証バックエンドにわたって認証テストを試みます。最初の認証メソッドに失敗する と次の認証バックエンド、という具合にして、認証に成功しない限り、全てのバッ クエンドを試すまで続けます。

認証に使うバックエンドのリストは AUTHENTICATION_BACKENDS 設定に 指定します。この値は Python モジュールパス名からなるタプルで、認証方法を実 装したクラスの名前を指定します。認証クラスは Python パス上のどこにあっても かまいません。

デフォルトでは、 AUTHENTICATION_BACKENDS の値は:

('django.contrib.auth.backends.ModelBackend',)

に設定されています。このクラスは、 Django のユーザデータベースをチェックす る認証スキームです。

AUTHENTICATION_BACKENDS の順番には意味があり、同じユーザ名とパス ワードが複数のバックエンドで有効な値であったとしても、 Django は最初にユー ザ名とパスワードがマッチした時点で認証処理を停止します。

Note

一度ユーザが認証されると、 Django はユーザのセッション内でどのバック エンドによってユーザが認証されたかを保持します。そして、同じバックエンド を「認証されたユーザ」であることが必要とされる時にアクセスします。 この効率性が意味するのは、認証ソースが一回のセッションを基礎として キャッシュされるということです。だから、もし AUTHENTICATION_BACKENDS を変更すると、セッションデータをクリア しなければ、異なる方法で再認証することができません。これのシンプルな方法 は、 Session.objects.all().delete() を実行することです。

認証バックエンドを作成する

認証バックエンドの実体は、 get_user(user_id)authenticate(**credentials) という二つのメソッドを実装したクラスです。

get_user メソッドはユーザ名、データベース ID などを表す引数 user_id をとり、対応する User オブジェクトを返します。

authenticate メソッドは証明情報、すなわちユーザ名とパスワードなどをキー ワード引数の形で受け取ります。ほとんどの場合、以下のような形式をとります:

class MyBackend(object):
    def authenticate(self, username=None, password=None):
        # Check the username/password and return a User.

以下のようにトークンに対する認証を行うようにも書けます:

class MyBackend(object):
    def authenticate(self, token=None):
        # Check the token and return a User.

どちらの方法でも、 authenticate は受け取った証明情報をチェックし、証明 情報が有効な場合、対応する User オブジェクトを返さねばなりません。証明 情報が無効なら、 None を返します。

Django の admin システムは、冒頭で説明した Django の User オブジェクト と強くカップリングしています。従って、今のところ自作の認証バックエンドを扱 うには、 (LDAP ディレクトリや外部の SQL データベースなどのような) 別のバッ クエンド上のユーザに対して Django の User オブジェクトを生成するのがベ ストです。あらかじめスクリプトを書いておいてもよいですし、ユーザが最初にロ グインした際に、 authenticate メソッドでその処理を行うようにしてもよい でしょう。

以下に示すバックエンドの例では、 settings.py ファイルに定義されたユーザ 名とパスワードに対して認証を行い、ユーザが最初に認証を行ったときに User オブジェクトを生成します:

from django.conf import settings
from django.contrib.auth.models import User, check_password

class SettingsBackend(object):
    """
    セッティングにそぐわない認証の ADMIN_LOGIN and ADMIN_PASSWORD

    ログインネームとパスワードのハッシュを使ってみます。例えば:

    ADMIN_LOGIN = 'admin'
    ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'
    """

    supports_inactive_user = False

    def authenticate(self, username=None, password=None):
        login_valid = (settings.ADMIN_LOGIN == username)
        pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
        if login_valid and pwd_valid:
            try:
                user = User.objects.get(username=username)
            except User.DoesNotExist:
                # Create a new user. Note that we can set password
                # to anything, because it won't be checked; the password
                # from settings.py will.
                user = User(username=username, password='get from settings.py')
                user.is_staff = True
                user.is_superuser = True
                user.save()
            return user
        return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None
カスタムのバックエンドでパーミッションを扱う

カスタムの認証バックエンドから、独自のパーミッションを提供できます。

認証バックエンドがパーミッション照会のための関数 (get_group_permissions(), get_all_permissions(), has_perm(), および has_module_perms()) をサポートして いる場合、ユーザモデルはパーミッションの照会をバックエンドに移譲します。

あるユーザに付与されるパーミッションの集合は、全てのバックエンドの返しうる パーミッションのスーパーセットです。すなわち、 Django はいずれかのバックエ ンドのパーミッションを、どのユーザにも付与できます。

前述の単純なバックエンドで、万能の管理ユーザを作る方法は、以下のようにとても 簡単です:

class SettingsBackend(object):

    # ...

    def has_perm(self, user_obj, perm, obj=None):
        if user_obj.username == settings.ADMIN_LOGIN:
            return True
        else:
            return False

この書き方だと、上の例でアクセスを認可されたユーザにはあらゆるパーミッショ ンが許されます。バックエンドの認証関数はユーザオブジェクトを引数にとります。 また、ユーザオブジェクトの代わりに、 User のコンストラクタと同じ引数も指定 できます。

認可の API は、 django/contrib/auth/backends.py で実装されています。この バックエンドはデフォルトのバックエンドであり、ほとんどの場合 auth_permission にパーミッションを問い合わせます。

匿名ユーザへの権限
リリースノートを参照してください

匿名ユーザは認証されていません。すなわち、有効な認証の情報が提供されていませ ん。しかしながら、権限が与えられてないから何もしなくてよいという意味ではありま せん。最も基本的な部分で、ほとんどの Web サイトはサイトの大部分を匿名ユーザ に対して見せています。そして、許可された匿名ユーザはコメントなどを投稿する ことができます。

Django のパーミッションフレームワークは、匿名ユーザに対してのパーミッションを 保持する場所を設けてはいません。ですが、匿名ユーザに対しての権限を指定するため の認証バックエンドのカスタムは基礎部分で許可されています。これは特に、 再利用できるアプリの作者に取って役に立つものです。認証バックエンドに権限につい ての全ての問題を任せてしまうことが出来ます。セッティングを必要とするというより 、例が匿名ユーザのコントロールです。

アクティブでないユーザの権限
リリースノートを参照してください

アクティブでないユーザは、認証されていても is_activeFalse に セットされているユーザです。しかし、これは何も認証されていないという意味で はありません。例えば、そのようなユーザは自身のアカウントをアクティブにする ことができます。

パーミッションシステム内での匿名ユーザに対してのサポートは、アクティブでな いユーザがしない、「何かをする権限を得ること」を許可しています。

これをバックエンドで有効にするには、クラスの supports_inactive_user アトリビュートを True にしなければいけません。

supports_inactive_user 属性が存在しないことは、 PendingDeprecationWarning を送出します。もし、 Django 1.3 または、 1.4 ではこの警告は、 DeprecationWarning にアップデートされています。 これは大きくうるさげに表示されます。加えて、 supports_inactive_userFalse になっていると、 Django 1.5 ではアクティブでないユーザが 認証手続きでパスされることをサポートするでしょう。

オブジェクトへのパーミッションのハンドリング

Django のパーミッションフレームワークは、オブジェクトへのパーミッションを 基礎に持っています、でも、コアにその実装を持っていません。その意味は、 オブジェクトへのパーミッションは常に False が返るか、または空っぽの リスト(チェックがどう働いたかに依存します)が返ります。

Django のキャッシュフレームワーク

revision-up-to:17812 (1.4)

動的な Web サイトの根本的なトレードオフ要因とは、まさに動的であるということ そのものです。ユーザがページをリクエストするたびに、サーバはデータベースへ のクエリからテンプレートのレンダリングやビジネスロジックといった全ての計算 を実行して、サイト訪問者が見るページを生成します。これは、処理のオーバヘッ ドという観点から考えると、ファイルシステムからファイルを読み出すタイプの標 準的なサーバ設計よりもはるかに高くつきます。

ほとんどの Web アプリケーションでは、このオーバヘッドはたいしたものではあり ません。ほとんどの Web アプリケーションは washingtonpost.com や slashdot.org とは違って、小規模から中規模のサイトであり、トラフィックもそこ そこにすぎません。しかし、中規模以上のサイトや高いトラフィックをさばかねば ならないサイトでは、可能なかぎりオーバヘッドを削るのは基本です。

そこでキャッシュが登場します。

コンテンツのキャッシュとは、コストのかかる計算で、かつ一度計算したら再度計 算する必要のないものの結果を保存することです。以下の疑似コードは、動的に生 成されるWeb ページで、キャッシュがどのように動作するかを説明しています:

ある URL に対し、キャッシュに該当するページがないか探す
キャッシュ内にページがある場合:
    キャッシュされたページを返す
それ以外:
    ページを生成する
    生成されたページを (次のリクエスト用に) キャッシュに保存
    生成されたページを返す。

Django には堅牢なキャッシュシステムが付属しており、動的なページを保存して、 リクエストの度に最計算しなくてもよいようになっています。利便性のため、 Django には様々な粒度でのキャッシュを提供しており。特定のビューだけをキャッ シュしたり、生成に時間を要する部分だけをキャッシュしたり、サイト全体をキャッ シュしたりできます。

Django は Squid のような「上流の」キャッシュ や、ブラウザベースのキャッシュともうまく協調できます。こうした類のキャッシュ は直接制御できませんが、サイトのどの部分をどのようにキャッシュすべきかを (HTTP ヘッダを介して) ヒントとして与えられます。

キャッシュを立ち上げる

キャッシュシステムを使うには、少し設定が必要です。例えば、キャッシュデータ をどこに置くか、データベース上か、ファイルシステム上か、それともメモリ上か を指定せねばなりません。これはキャッシュのパフォーマンスに影響する重要な決 定です; そう、あるキャッシュ方式が別の方式より高速な場合もあるのです。

キャッシュの選択は設定ファイルの CACHES 設定で行います。 CACHES に設定できる値を以下に示します。

キャッシュの設定は Django 1.3 で変わりました。 Django 1.2 以前では CACHE_BACKEND という文字列でキャッシュの設定を行っていました。 この設定は CACHES という辞書に置き換えられました。
Memcached

Django で利用できるキャッシュの中でも断然高速で、もっとも高効率である Memcached は、完全なメモリベースのキャッシュフレームワークです。 Memcached はもともと LiveJournal.com の高負荷を低減するために開発され、その後 Danga Interactive でオープンソース化されました。 Memcached は Slashdot や Wikipedia で使われており、データベースアクセスを低減して、サイトのパフォー マンスを劇的に向上させます。

Memcached はデーモンとして動作し、指定された量の RAM の割り当てを受けます。 Memcached の役割は、キャッシュ内に任意のデータを追加し、取り出したり削除したりするた めのインタフェース、それも 超稲妻迅い インタフェースを提供することにあり ます。全てのデータは直接メモリ上に保存されるので、データベースやファイルシ ステムの使用によるオーバヘッドがなくなります。

Memcached 本体のインストールの他に、 memcached の Python バインディングをイ ンストールする必要があります。 いくつかの Python バインディングがあります。 一般的なのは python-memcachedpylibmc です。

Django 1.0 と 1.1 では cmemcache バインディングも利用できましたが、 cmemcache がメンテナンスされていないため、 1.2 で 推奨されないライブラリ になりました。 cmemcache のサポートは Django 1.4 で無くなります。
pylibmc のサポートを追加しました。

Django と Memcached を組み合わせて使うには

  • BACKENDdjango.core.cache.backends.memcached.MemcachedCachedjango.core.cache.backends.memcached.PyLibMCCache を 設定します(選んだ Memcached バインディングによります)。
  • LOCATIONip:port を設定します。 ip は Memcached デーモンが動作している IP アドレスを、 port は、Memcached が動作しているポート番号を設定します。 あるいは、 unix:path を設定します。 path は Unix ソケットファイルのパスを設定します。

次の例は、 Memcached が localhost (127.0.0.1) の 11211 番ポートで動作していて、 python-memcached バインディングを利用している場合のものです。:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '127.0.0.1:11211',
    }
}

次の例は、 Memcached が /tmp/memcached.sock の Unix ソケットを通じて利用可能で、 python-memcached バインディングを利用している場合のものです。:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': 'unix:/tmp/memcached.sock',
    }
}

memcached の素晴らしい点の一つは、複数のサーバ間でキャッシュを共有できると いうことです。この機能を利用するには、全てのサーバアドレスをセミコロンで区 切るか、リストで LOCATION に設定します。

以下の例では、 IP アドレスが 172.19.26.240 と 172.19.26.242 で、いずれもポー ト番号 11211 で動作している memcached インスタンスでキャッシュを共有してい ます:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]
    }
}

以下の例では、 IP アドレスが 172.19.26.240 (ポート番号 11211) 、 172.19.26.242 (ポート番号 11212) 、 172.19.26.244 (ポート番号 11213) で 動作している Memcached インスタンスでキャッシュを共有しています。:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
            '172.19.26.244:11213',
        ]
    }
}

メモリベースのキャッシュには一つだけ短所があります: キャッシュデータはメモ リ上に保存されるので、サーバクラッシュ時に失われることがあります。いうまで もなく、メモリは永続的なデータ保存場所ではありません。ですから、データの保 存場所を確保するのにメモリベースのキャッシュに依存してはなりません。実際に は、 Django のキャッシュバックエンドは どれも、永続的な記憶装置にはなりえません – キャッシュバックエンドは記憶 装置ではなく、あくまでもキャッシュ用です – ただ、メモリベースのキャッシュ は特に一時性が高いため、ここで注意しておきます。

データベースを使ったキャッシュ

データベーステーブルをキャッシュバックエンドに使うには、まず以下のコマンド を実行してデータベース上にキャッシュテーブルを作成します:

python manage.py createcachetable [cache_table_name]

[cache_table_name] は作成したいデータベーステーブルの名前です。 (この名 前は、現在データベースで既に使われていない有効なテーブル名なら何でも構いま せん。) このコマンドはデータベース中に Django のデータベースキャッシュシス テム向けの適切な形式のテーブルを生成します。

キャッシュ用のテーブルを作成したら、 BACKEND 設定を "django.core.cache.backends.db.DatabaseCache" にし、 LOCATION 設定を tablename にします。 tablename はキャッシュ用テーブルの名前です。 以下の例では、キャッシュテーブル名を my_cache_table にしています:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION': 'my_cache_table',
    }
}

データベースを使ったキャッシュは、設定ファイルで指定しているのと同じデータベースを利用します。 キャッシュ用のテーブルを別のデータベースにすることはできません。

データベースのキャッシュがうまく働くのは、高速でインデクス構築のよくできた データベースサーバを使っている場合です。

データベースを使ったキャッシュと、マルチデータベース

データベースを使ったキャッシュをマルチデータベースで使っている場合には、 データベースキャッシュテーブルのルーティングを設定しなければなりません。 ルーティングのためのキャッシュテーブルは CacheEntry という名前のモデルとして、 アプリケーション名は django_cache という名前として扱われます。 このモデルはモデルキャッシュには現れませんが、ルーティングのために使えます。

例えば、このルーターはすべてのキャッシュの読み取り操作を cache_slave へ、 すべての書き込み操作を cache_master へルーティングします。 キャッシュテーブルは cache_master にだけ同期します。:

class CacheRouter(object):
    """すべてのデータベースキャッシュ操作をコントロールするルーター"""

    def db_for_read(self, model, **hints):
        "すべてのキャッシュ読み込み操作をスレーブへ"
        if model._meta.app_label in ('django_cache',):
            return 'cache_slave'
        return None

    def db_for_write(self, model, **hints):
        "すべてのキャッシュ読み込み操作をマスターへ"
        if model._meta.app_label in ('django_cache',):
            return 'cache_master'
        return None

    def allow_syncdb(self, db, model):
        "キャッシュモデルはマスターにだけ同期"
        if model._meta.app_label in ('django_cache',):
            return db == 'cache_master'
        return None

データベースキャッシュモデルへルーティングの指示をしなかった場合には、キャッシュバックエンド は default データベースを利用します。

もちろん、データベースを使ったキャッシュを使わない場合には、データベースキャッシュモデルへの ルーティング指示について心配する必要はありません。

ファイルシステムを使ったキャッシュ

ファイルシステム上にキャッシュしたい内容を置くには、 BACKEND"django.core.cache.backends.filebased.FileBasedCache" と指定します。 キャッシュデータを /var/tmp/django_cache に置きたいなら、以下の ように設定します:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
    }
}

Windowsの場合には、ドライブレターを次の例のようにパスの先頭に置きます。:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': 'c:/foo/bar',
    }
}

ディレクトリパスは常に絶対パス指定。すなわち、ファイルシステムのルートから 始まるパス名を指定せねばなりません。パスの末尾にスラッシュを追加するかどう かは問題にはなりません。

この設定の指し示すパスが実在し、 Web サーバを動かしているシステムユーザから 読み書き可能であるようにしてください。上の例でいうなら、サーバを apache というユーザで動かしている場合、 /var/tmp/django_cache ディレクトリ が実在して、 apache によって読み書き可能かどうかをチェックしてください。

各キャッシュは別々のファイルに、 Python の pickle モジュールを使って シリアライズされた (“pickleされた”) オブジェクト として保存されます。 各ファイル名はファイルシステムで利用できる安全な文字にエスケープされたキャッシュキーです。

ローカルメモリ上のキャッシュ

メモリを使ったキャッシュの恩恵を受けたい一方で、 memcached を動かせない状況 にある場合には、ローカルメモリを使ったキャッシュバックエンドを検討してみて ください。このキャッシュはマルチプロセスセーフかつスレッドセーフです。使う には、 BACKEND"django.core.cache.backends.locmem.LocMemCache" と指定します。 以下のようにして使います:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
        'LOCATION': 'unique-snowflake'
    }
}

キャッシュの LOCATION は個別のメモリストアを識別するために 使われます。ローカルメモリ上のキャッシュを一つだけ使う場合には、 LOCATION は省略できます。ローカルメモリ上のキャッシュを複数 使う場合にはキャッシュを分けておくために少なくとも一つには名前を割り当てておく必要があります。

各サーバプロセスは、個別にキャッシュインスタンスを保持するので、プロセス間 でキャッシュは共有されません。このことから、明らかに、ローカルメモリキャッ シュのメモリ効率は非常に悪いといえます。おそらく実運用環境向きとではないで しょう。

ダミーキャッシュ (開発用)

最後に、 Django には「ダミーの」キャッシュが付いてきます。このキャッシュは 実際にはなにもしません – 単に何もしないキャッシュインタフェースを実装して いるだけです。

ダミーキャッシュが便利になるのは、そこかしこで様々なキャッシュを使っている ような実運用サイトを構築していて、開発/テスト環境ではキャッシュを行いたく ないような場合です。開発環境ではダミーキャッシュによってキャッシュしなくな りますが、実運用環境はそのままにしておけます。ダミーキャッシュを有効にする には、次のように BACKEND を設定します:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
    }
}
カスタムのキャッシュバックエンドを使う

Django には、すぐに使えるキャッシュバックエンドがいくつもありますが、カスタ マイズしたバックエンドや自作のバックエンドを使いたい場合もあるでしょう。 外部のキャッシュバックエンドを Django と組み合わせたいなら、以下のように、 Python の import パスを CACHE_BACKENDBACKEND で指定します:

CACHES = {
    'default': {
        'BACKEND': 'path.to.backend',
    }
}

自作のバックエンドを作成しているなら、リファレンス実装として標準のキャッシュ バックエンドを使うとよいでしょう。キャッシュバックエンドは Django のソース 中の django/core/cache/backends/ ディレクトリ下にあります。

注意: 運用ホスト上でサポートされていないなど、本当に特別な理由がないかぎり、 Django 組み込みのキャッシュバックエンドを使った方がよいでしょう。組み込みの バックエンドは良くテストされており、とても簡単に扱えます。

Cache の引数

エンジンと名前のほかに、キャッシュの振る舞いをコントロールするためにキャッシュバックエンドは どれも引数をとれます。引数は CACHES のキーで指定します。 使える引数は以下の通りです:

  • TIMEOUT: デフォルトのタイムアウトで、単位は秒です。 デフォルト値は5 分 (300 秒) に設定されています。

  • OPTIONS: キャッシュバックエンドへ渡したい オプションです。 使えるオプションは、バックエンドごとに様々です。

    locmemfilesystemdatabase といったキャッシュバックエンドは それぞれ独自の淘汰方法を持っていて、次のオプションに従います。

    • MAX_ENTRIES: いくつまでキャッシュエントリを保持するかの設定です。 この設定を超えると古いものから削除されます。 デフォルト値は 300 です。

    • CULL_FREQUENCY: キャッシュエントリ数が MAX_ENTRIES に 達したときにどのくらいのキャッシュエントリを削除するかを分数で指定します。 実際の割合は 1/CULL_FREQUENCY です。 つまり、CULL_FREQUENCY2 に設定すると、 MAX_ENTRIES に達した場合に半分のキャッシュを削除します。

      CULL_FREQUENCY0 を指定すると、キャッシュエントリ数が MAX_ENTRIES に到達した時に全てのキャッシュエントリを廃棄します。 の設定は、キャッシュミスの増加と引き換えに、淘汰処理を 劇的に 高速化します。

    サードパーティのライブラリを使ったキャッシュバックエンドはライブラリの オプションを背後のライブラリにじかにオプションを渡します。 結果として、有効なオプションのリストは使うライブラリに依存します。

  • KEY_PREFIX: Djangoサーバが使うキャッシュキーに 自動的に付与される文字列です(デフォルトでは前につきます)。 頭につけられる文字列です。

    詳細は キャッシュのドキュメント を参照してください。

  • VERSION: Djangoサーバが生成するキャッシュキーに使われる デフォルトのバージョン番号です。

    詳細は キャッシュのドキュメント を参照してください。

  • KEY_FUNCTION ドットで区切られた関数のパスを設定します。関数でキーの頭につけられる文字とバージョンを 最終的にどのように構成するかを定義します。

    詳細は キャッシュのドキュメント を参照してください。

ファイルシステムを使ったキャッシュを、デフォルトの タイムアウトが 60 秒で、 最大のキャッシュエントリ保持数が 1000 の設定です。:

CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': '/var/tmp/django_cache',
        'TIMEOUT': 60,
        'OPTIONS': {
            'MAX_ENTRIES': 1000
        }
    }
}

不正な引数や引数値は暗黙のうちに無視されます。

サイト単位のキャッシュ

キャッシュを立ち上げたら、サイト全体をキャッシュするのが最も簡単な使い方で す。設定は設定ファイルの MIDDLEWARE_CLASSES'django.middleware.cache.UpdateCacheMiddleware''django.middleware.cache.FetchFromCacheMiddleware' を追加するだけです。 例えば以下のようにします:

MIDDLEWARE_CLASSES = (
    'django.middleware.cache.UpdateCacheMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.cache.FetchFromCacheMiddleware',
)

Note

ミドルウェアの順番は、これで間違っていません。 “Update” ミドルウェ アがリストの先頭で、 “Fetch” ミドルウェアが末尾です。詳しいからくりは ちょっとややこしいのですが、後述の MIDDLEWARE_CLASSES の順番 で説明 しています。

次に、以下の必須の設定を Django 設定ファイルに追加します:

  • CACHE_MIDDLEWARE_ALIAS – キャッシュを保存するストレージの エイリアスを指定します。
  • CACHE_MIDDLEWARE_SECONDS – 各ページのキャッシュ時間を秒単位で 指定します。
  • CACHE_MIDDLEWARE_KEY_PREFIX – 同じ Django の下にある複数のサ イト間でキャッシュを共有する場合、この値をサイトの名前にするか、 Django インスタンスごとに固有の文字列にして、キャッシュのキー衝突を防ぎます。キー 衝突を気にする必要がない場合は空文字列を設定します。

キャッシュミドルウェアはリスエストとレスポンスのヘッダで許可された場合、 GET と HEAD リクエストへのレスポンスをキャッシュします。 同じ URL で別のパラメータがついたリクエストは、ユニークなものとして認識し、 別々にキャッシュされます。 オプションとして CACHE_MIDDLEWARE_ANONYMOUS_ONLYTrue に設定すると、アノニマスリクエスト(ログインしていないユーザのリクエスト)のみ がキャッシュされます。ユーザに特異なページのキャッシュを無効にする簡単で効果的な 設定です( Django の管理画面を含みます)。 CACHE_MIDDLEWARE_ANONYMOUS_ONLY の設定を使う場合には、 AuthenticationMiddleware を有効にするのを忘れないでください。 キャッシュミドルウェアは HEAD リクエストに対しての返答のレスポンスヘッダと GET リクエストへのレスポンスヘッダが同じであることを期待しています。 上記の場合 GET レスポンスのキャッシュを HEAD リクエストへ返します。

加えて、キャッシュミドルウェアは自動的に以下のヘッダを HttpResponse に追加します:

  • 「新鮮な」(キャッシュされていない) ページをリクエストされた場合には、 Last-Modified ヘッダを現在の date/time に設定します。
  • Expires ヘッダを現在時刻と CACHE_MIDDLEWARE_SECONDS を加算した 値に設定します。
  • CACHE_MIDDLEWARE_SECONDS に基づき、 Cache-Control ヘッダにページ の最長寿命を設定します。

ミドルウェアの詳細は ミドルウェア を参照してください。

ビューの中でキャッシュの有効期限を設定した場合 (Cache-Control ヘッダの max-age セクションを設定した場合)、ページは CACHE_MIDDLEWARE_SECONDS の設定値ではなくビューで設定した有効期限の下で キャッシュされます。 django.views.decorators.cache モジュールのデコレー タを使えば、ビューの有効期限を設定 (cache_control デコレータ) したり、 ビューのキャッシュを抑制 (never_cache デコレータ) できます。これらのデ コレータについては Vary ヘッダ以外のヘッダを使ったキャッシュ制御 を参照してください。

リリースノートを参照してください

USE_I18NTrue に設定した場合、アクティブな language 名付きのキャッシュキーが生成されます。 – 言語設定の検出メカニズム も参照してください。 マルチリンガルなサイトも自分でキーを生成すること無く容易にキャッシュできます。

リリースノートを参照してください

アクティブな languageUSE_L10NTrue に設定されたときもキャッシュキーに含まれます。 また USE_TZTrue に設定された場合には 現在のタイムゾーン も含まれます。

ビュー単位のキャッシュ

django.views.decorators.cache.cache_page()

キャッシュフレームワークをもう少し低い粒度で使うには、個々のビューの出力を キャッシュします。 django.views.decorators.cache には関数デコレータ cache_page があり、自動的にビューからの応答をキャッシュします。 使い方は簡単です:

from django.views.decorators.cache import cache_page

@cache_page(60 * 15)
def my_view(request):
    ...

cache_page は単一の引数をとります。これはキャッシュのタイムアウトを秒で 表したものです。上の例では、 my_view() の出力結果は 15 分間キャッシュ されます。(上の例では、可読性のために、 60 * 15 と書いています。 60 * 15900 、すなわち 60 秒を 15 回です)

サイト単位のキャッシュのように、ビュー単位のキャッシュは URL 単位です。 複数の URL が同じビューに対してある場合には各URLごとに別々にキャッシュされます。 my_view を例にしましょう。 URLConf が以下のような場合には:

urlpatterns = ('',
    (r'^foo/(\d{1,2})/$', my_view),
)

/foo/1//foo/23/ へのリクエストは期待通り別々にキャッシュされます。 いったん固有の URL (たとえば /foo/23/ )へのリクエストがあると、同じ URL への リクエストに対してはキャッシュが使われます。

cache_page はオプションのキーワード引数をとれます。 cache 引数はビューの結果をキャッシュする際に特定のキャッシュを指定できます( CACHES の設定のもの)。 デフォルトでは default キャッシュが使われますが、望みのキャッシュを指定できます:

@cache_page(60 * 15, cache="special_cache")
def my_view(request):
    ...

ビュー単位でキャッシュのプリフィックスの設定を上書きすることもできます。 cache_pagekey_prefix というキーワード引数をとれます。 key_prefix はミドルウェアに対する CACHE_MIDDLEWARE_KEY_PREFIX と同様に機能します。次のように使います:

@cache_page(60 * 15, key_prefix="site1")
def my_view(request):
    ...

二つの設定は組み合わせて使用できます。 cache key_prefix を 指定すると、設定されているキャッシュエイリアスのキャッシュのプリフィックスを 上書きしたものを取得できます。

URLconf でビュー単位のキャッシュを指定する

ここまでのセクションに登場した例は my_view 関数自身を cache_page で 置き換えていたので、ビューがキャッシュされるようにハードコードされていました。 この方法はビューとキャッシュシステムを密結合してしまうため、いくつかの理由において 理想的ではありません。 実際は、ビュー関数をほかのキャッシュしないサイトで再利用したくなるかもしれませんし、 キャッシュを使わないかもしれない人々にビュー関数を配布したいかもしれません。 このような問題を解決するには、ビュー関数自身ではなく、 URLconf でビュー単位の キャッシュを設定します。

URLconf への設定は簡単にできます: URLconf でビュー関数を cache_page で ラップするだけです。もともとの URLconf がこうなっているとします:

urlpatterns = ('',
    (r'^foo/(\d{1,2})/$', my_view),
)

cache_pagemy_view をラップするとこうなります。:

from django.views.decorators.cache import cache_page

urlpatterns = ('',
    (r'^foo/(\d{1,2})/$', cache_page(60 * 15)(my_view)),
)

テンプレートの部分的キャッシュ

ページのキャッシュをもっと細かく制御したいなら、 cache テンプレートタグ を使って、テンプレートの一部分だけをキャッシュできます。 cache タグをテ ンプレート内で使えるようにするには、テンプレートの冒頭に {% load cache %} を挿入しておきます。

{% cache %} テンプレートタグは、タグで囲まれたブロックの内容を、指定さ れた時間だけキャッシュします。 cahce タグは、必須の引数として、キャッシュ の有効期限 (秒単位) とキャッシュされた部分に付ける名前をとります。例えば、 以下のように使います:

{% load cache %}
{% cache 500 sidebar %}
    .. sidebar ..
{% endcache %}

キャッシュ部分内で使われる変数に応じて、複数のキャッシュコピーを保存したい 場合もあるでしょう。例えば、上の例で挙げたサイドバー部分を、ユーザ毎に個別 にキャッシュしたい場合には、 {% cache %} テンプレートタグに追加の引数を 指定して、キャッシュをユーザ毎に一意に識別できるようにします:

{% load cache %}
{% cache 500 sidebar request.user.username %}
    .. sidebar for logged in user ..
{% endcache %}

キャッシュ変数は、複数指定しても全く問題ありません。必要なだけの引数を {% cache %} に指定してください。

USE_I18NTrue にセットされている場合、 サイト単位のミドルウェアキャッシュは アクティブな言語を優先しますcache テンプレート内で同じ結果を取得するために、テンプレートタグは 翻訳用の変数 を使えます。

{% load i18n %}
{% load cache %}

{% get_current_language as LANGUAGE_CODE %}

{% cache 600 welcome LANGUAGE_CODE %}
    {% trans "Welcome to example.com" %}
{% endcache %}

キャッシュのタイムアウトはテンプレート変数でも指定できます。ただし、テンプ レート変数は整数値でなければなりません。例えば、テンプレート変数 my_timeout600 にセットしていれば、以下の二つの例は同じ効果をも たらします:

{% cache 600 sidebar %} ... {% endcache %}
{% cache my_timeout sidebar %} ... {% endcache %}

この機能を使えば、テンプレートで何度もタイムアウトを編集しなくても、一箇所 で変数を宣言しておいて再利用できるので便利です。

低水準のキャッシュ API

ページ全体のキャッシュがあまり有効でなく、ともするとやりすぎでかえって不便 な場合があります。

恐らく実際には、いくつかのコストの高い、結果の更新頻度が違うクエリーを含んでいるでしょう。 こういう場合には、サイト単位や、ビュー単位のキャッシュが提供するページ全体のキャッシュは 理想的ではありません。(いくつかのデータは頻繁に更新されるので)全部の結果はキャッシュしたく なくて、それでも変更が少ない結果はキャッシュしたいでしょうから。

こういう場合のために、 Django は低レベルなキャッシュ API を公開しています。 この API は好きな粒度でオブジェクトをキャッシュに格納するのに使えます。 安全に pickle できる Python オブジェクトであれば、文字列でも辞書でも、モデルオブジェクトの リストでも、なんでもキャッシュできます(たいていの Python オブジェクトは pickle できます。 pickle に関して、より詳しくは Python のドキュメントを参照してください)。

キャッシュを表現するモジュールである django.core.cacheCACHES'default' エントリ設定に基づいて生成された cache オブジェクトを公開しています:

>>> from django.core.cache import cache

基本となるインタフェースは set(key, value, timeout)get(key) です:

>>> cache.set('my_key', 'hello, world!', 30)
>>> cache.get('my_key')
'hello, world!'

timeout 引数はオプションで、デフォルト値は CACHESdefault バックエンド設定の timeout 引数の値になります (これについては上記を参照してください)。 キャッシュに保存する秒数です。

オブジェクトがキャッシュの中になければ、 cache.get()None を返し ます:

# Wait 30 seconds for 'my_key' to expire...

>>> cache.get('my_key')
None

リテラルで None をキャッシュにしまうことは賛成できません。 なぜなら None が保持されていたのか、キャッシュに見つからなくて None が 返されたかの区別ができないでしょうから。

cache.get() には default 引数を指定できます。 default には、オ ブジェクトがキャッシュの中にないときに返す値を指定します:

>>> cache.get('my_key', 'has_expired')
'has_expired'

キーに使う値がまだキャッシュ辞書上に存在しない場合にのみ、 add() メソッ ドを使ってください。 add() メソッドは、 set() と同じ引数をとります が、指定したキーがすでに存在する場合には、キャッシュを更新しません:

>>> cache.set('add_key', 'Initial value')
>>> cache.add('add_key', 'New value')
>>> cache.get('add_key')
'Initial value'

add() によってキャッシュにデータが保存されたどうかを知りたければ、戻り 値をチェックしてください。戻り値が True なら、保存されています。そうで ないときは False を返します。

キャッシュを一度しかアクセスしない get_many() インタフェースもあります。 get_many() は指定した全てのキーのうち、キャッシュ内に実在する (そして期 限切れでない) ものの入った辞書を返します:

>>> cache.set('a', 1)
>>> cache.set('b', 2)
>>> cache.set('c', 3)
>>> cache.get_many(['a', 'b', 'c'])
{'a': 1, 'b': 2, 'c': 3}
リリースノートを参照してください

cache.set() のように、 set_many() はオプションで timeout 引数をとります。

キーは delete() で明示的に削除できます。特定のオブジェクトのキャッシュをクリアする 簡単な方法です。

>>> cache.delete('a')
リリースノートを参照してください

一度にたくさんのキーをクリアしたい場合には、 delete_meny() にクリアしたいキーの リストを渡します。

>>> cache.delete_many(['a', 'b', 'c'])
リリースノートを参照してください

最後に、すべてのキーをキャッシュから削除したい場合には、 cache.clear() を 使います。注意が必要なのは、 clear() はキャッシュから すべてを 削除することです。 あなたのアプリケーションがセットしたキーにとどまりません。

>>> cache.clear()

既に登録済みのキーを増減したい場合には、それぞれ incr()decr() メソッド を使います。デフォルトではキャッシュの値は 1 ずつ増減されます。増減の値は引数で与えられます。 もし、存在しないキーに対して増減しようとした場合には ValueError を送出します:

>>> cache.set('num', 1)
>>> cache.incr('num')
2
>>> cache.incr('num', 10)
12
>>> cache.decr('num')
11
>>> cache.decr('num', 5)
6

Note

incr()/decr() メソッドはアトミックが保証されません。 アトミックな増減をサポートしているバックエンド( memcached バックエンドとか)は 増減の操作はアトミックになります。 一方、増減の操作をネイティブに提供していないバックエンドは取得と更新という2ステップで 実装されるでしょう。

キャッシュキーのプリフィックス
リリースノートを参照してください

複数のサーバ間でキャッシュインスタンスを共有している場合や本番環境と 開発環境で共有している場合には、あるサーバのキャッシュデータを他の サーバに使われてしまうことがあります。 キャッシュデータのフォーマットがサーバ間でつがう場合には突き止めるのが 非常に難しい問題を引き起こしがちです。

この問題を避けるために、すべてのキャッシュキーにプリフィックスをつけられます。 個別のキャッシュキーを保存するときや取得するときに キャッシュの KEY_PREFIX に設定された 値を Django が自動でプリフィックスをつけます。

各 Django インスタンスの KEY_PREFIX を確実に別のものに設定しておくことで、キャッシュが衝突することを避けられます。

キャッシュバージョン
リリースノートを参照してください

キャッシュの値を利用するコードを変更した場合、既存のキャッシュを きれいにする必要があるかもしれません。 一番簡単な方法は前キャッシュをフラッシュすることですが、まだ使える 有効なキャッシュをロスしてしまいます。

Django は個別のキャッシュをターゲットによりより手段を用意しています。 Django のキャッシュフレームワークは VERSION で設定できるシステムワイドなバージョン識別子を持っています。 この設定の値はユーザが指定したキーとキャッシュプリフィックスと自動的に 組み合わされて最終的なキャッシュキーが生成されます。

デフォルトでは、すべてのキーリクエストは自動的にサイトのデフォルト キャッシュキーバージョンが含まれます。 しかし、基本的なキャッシュ関数は、 set と get でキャッシュキーバージョンを 指定できる世に version 引数をとれます。:

# Set version 2 of a cache key
>>> cache.set('my_key', 'hello world!', version=2)
# Get the default version (assuming version=1)
>>> cache.get('my_key')
None
# Get version 2 of the same key
>>> cache.get('my_key', version=2)
'hello world!'

特定キーのバージョンは incr_version()decr_version() メソッドを 使うことで増減できます。 他のキーには影響を与えずに、特定キーを新しいバージョンに押し出せます。前の例に続けると:

# Increment the version of 'my_key'
>>> cache.incr_version('my_key')
# The default version still isn't available
>>> cache.get('my_key')
None
# Version 2 isn't available, either
>>> cache.get('my_key', version=2)
None
# But version 3 *is* available
>>> cache.get('my_key', version=3)
'hello world!'
キャッシュキーの変換
リリースノートを参照してください

ここまでの2つのセクションで解説した通り、ユーザの与えたキャッシュキーは そのままでは利用されません。キャッシュプリフィックスとキャッシュキー バージョンと組み合わせて、最終的なキャッシュキーが与えられます。 デフォルトでは3つの部分がコロンで区切られた文字列が与えられます。

def make_key(key, key_prefix, version):
return ‘:’.join([key_prefix, str(version), smart_str(key)])

別の方法で組み合わせたり、(キーの部分を八種ダイジェストしたりと)他の 処理をキーに加えたい場合には、カスタムキー関数を定義できます。

キャッシュの設定で KEY_FUNCTION に 上で紹介した make_key() と引数を あわせた関数へのパスをドットで区切られたパスで指定します。 設定がされていれば、デフォルトのキー組み合わせ関数の代わりに利用されます。

キャッシュキーに関する注意
リリースノートを参照してください

Memcached は一番一般的に本番環境のキャッシュバックエンドで使われていますが、 250文字以上のキャッシュキーや、空白・制御文字を含めたキーは許されません(使用 すると例外が発生します)。 キャッシュのコードをポータブルにするために、また好ましくないサプライズを最小限 にするために、他のビルトインキャッシュバックエンドは、 memcached で利用すると エラーになるキーが使われた場合には、ウォーニングを出します ( django.core.cache.backends.base.CacheKeyWarning )。

いろいろなキーを受け付けるキャッシュバックエンド(カスタムバックエンドや memcached 以外のビルトインバックエンド)を使っていて、ウォーニングなしでいろいろなキーを利用したい 場合には、 CacheKeyWarning をおとなしくさせられます。 INSTALLED_APPS に設定しているうちの一つの management モジュール に、次のコードを追加します。:

import warnings

from django.core.cache import CacheKeyWarning

warnings.simplefilter("ignore", CacheKeyWarning)

ビルトインバックエンドでキーのバリデーションロジックを交換したい場合には、 バックエンドを継承して validate_key メソッドを上書きして、 カスタムのキャッシュバックエンドを使う に従うだけです。 実際に locmem バックエンドで行う場合には、このコードをモジュールに 追加します。:

from django.core.cache.backends.locmem import LocMemCache

class CustomLocMemCache(LocMemCache):
    def validate_key(self, key):
        """Custom validation, raising exceptions or warnings as needed."""
        # ...

...ドットで区切られたこのクラスの Python のパスを CACHES 設定の BACKEND 部分に設定します。

上流キャッシュ

ここまでは、 自分の データに対するキャッシュについて説明してきました。し かし、 Web 開発にはもう一つのタイプのキャッシュが関係してきます。それ は 「上流 (upstream)」のキャッシュ機構で行われているキャッシュです。上流の キャッシュは、ユーザのリクエストが Web サイトに到達する前ですらページのキャッ シュを行います。

上流キャッシュの例をいくつか示します:

  • ISP がある程度のページをキャッシュしていることもありますので、 http://example.com/ へリクエストしたページを ISP は example.com へ アクセスせずに返してくることがあります。 example.com のメンテナは、このキャッシュについて知りません。 ISP は example.com とブラウザの間にいて、すべてのキャッシュハンドリングを 透過的に行います。
  • ページをキャッシュしてパフォーマンスを向上させるために、 Django Web サイトを Squid Web プロキシ (http://www.squid-cache.org/) の背後に置 けます。この場合、リクエストはまず Squid でさばかれ、必要な時にのみア プリケーションに渡されるようになります。
  • Web ブラウザもページをキャッシュします。 Web ページが適切なヘッダを送 信すると、ブラウザは以後の同じページへのリクエストにはローカルの (キャッ シュされた) コピーを使うようになります。

上流のキャッシュは効率を高める良い方法ではありますが、危険もはらんでいます: 多くの Web ページのコンテンツは認証に応じて異なる内容になります。また、その 他の変数も入ります。キャッシュシステムが純粋に URL だけに基づいてページを 盲目的に保存してしまうと、同じページを後から見た訪問者に対して正しくない情 報や機密の情報を晒してしまいます。

例えば、 Web ベースの email システムを操作しているとしましょう。”inbox” ページのコンテンツはいうまでもなくログインしているユーザ固有のものです。 ある ISP が盲目的にサイトをキャッシュしてしまうと、その ISP を経由して最初 にログインしたユーザは自分の inbox ページをキャッシュしてしまい、以降に そのサイトを訪れたユーザが閲覧できるようになってしまいます。これはよろしく ありません。

幸運にも、 HTTP にはこうした問題に対する解決策があります。すなわち、キャッ シュ機構に指定の変数に基づいてコンテンツのキャッシュを行うよう指示したり、 キャッシュメカニズムが特定のページをキャッシュしないように指示したりする 一連の HTTP ヘッダがあるのです。

Vary ヘッダを使う

Vary ヘッダは、キャッシュ機構がキャッシュキーを生成するときに、どのリク エストヘッダを考慮すべきかを定義しています。例えば、 Web ページのコンテンツ が言語設定に依存している場合、ページは「言語によって変化 (vary)」します。

Django 1.3 でクエリを含むフルリクエストパスがキャッシュキーの 生成に使われるようになりました。 Django 1.2 ではパス部分のみでした。

デフォルトでは、 Django のキャッシュシステムはキャッシュキーをリクエストの パス部分とクエリ、例えば /stories/2005/?order_by=author" を使って生成します。 この場合、クッキーや言語設定のようなユーザエージェント間の違いにかかわらず、 同じ URL を指すリクエストは全て同じバージョンのキャッシュを使います。 しかし、クッキーや言語、ユーザエージェントといったリクエストヘッダ上の違い に基づいて、違った内容を出力する場合、 Vary ヘッダを使って、ページ出力 が何に依存しているかをキャッシュメカニズムに教える必要があります。

Django で Vary ヘッダを設定するには、以下のような便宜用のビュー関数デコ レータ、 vary_on_headers を使います:

from django.views.decorators.vary import vary_on_headers

@vary_on_headers('User-Agent')
def my_view(request):
    ...

上の場合では、 (Django 自体のキャッシュミドルウェアのような) キャッシュメカ ニズムは個々のユーザエージェント固有の別のバージョンをキャッシュします。

Vary ヘッダを (response['Vary'] = 'user-agent' のような操作で) 手動 で変更せずに、 vary_on_headers デコレータを使う利点は、デコレータが (す でに存在するかもしれない) Vary ヘッダをスクラッチから作るのではなく、き ちんと追加処理を行う点にあります。

vary_on_headers() には複数のヘッダを渡せます:

@vary_on_headers('User-Agent', 'Cookie')
def my_view(request):
    # ...

これは上流キャッシュに 両方 の変化を伝えます。つまり、ユーザエージェントとクッキー の組み合わせでキャッシュを取得します。例えば、ユーザエージェントが Mozilla で クッキーの値が foo=bar は、ユーザエージェントが Mozilla で、 クッキーの値が foo=ham のリクエストと別のものとして考慮されます。

クッキーによるコンテンツの変更はよくあることなので、 vary_on_cookie デコレータも用意されています。従って、以下の二つのビューは同じ振舞いをします:

@vary_on_cookie
def my_view(request):
    ...

@vary_on_headers('Cookie')
def my_view(request):
    ...

vary_on_headers に渡すヘッダは大小文字を区別しないので注意してください。 "User-Agent""user-agent" と同じです。

ヘルパ関数 django.utils.cache.patch_vary_headers() も直接使えます:

from django.utils.cache import patch_vary_headers
def my_view(request):
    # ...
    response = render_to_response('template_name', context)
    patch_vary_headers(response, ['Cookie'])
    return response

patch_vary_headers は第一引数に HttpResponse インスタンスをとり、ヘッ ダ名のリストまたはタプルを第二引数にとります。

Vary ヘッダの詳細は 公式の Vary の仕様 を参照してください。

Vary ヘッダ以外のヘッダを使ったキャッシュ制御

キャッシュの利用で起きるもう一つの問題は、データのプライバシーと、カスケー ド接続したキャッシュのどこにデータを保存すべきかという疑問です。

通常、ユーザの目に触れるのは二種類のキャッシュ、すなわち自分のブラウザのキャッ シュ (プライベートのキャッシュ) と、ページプロバイダ側のキャッシュ (公開の キャッシュ) です。公開のキャッシュは複数のユーザによって利用されており、別 のユーザがその内容を制御することもあります。これは、注意の必要なデータを扱 う際には問題になります: 例えば、銀行のアカウント番号を公開キャッシュに保存 して欲しくはないでしょう。つまり、 Web アプリケーションにはどのデータがプラ イベートで、どのデータが公開なのかを区別する方法が必要なのです。

この問題の解決策は、ページキャッシュが「プライベート」であると示すことです。 Django では、 cache_control ビューデコレータを使ってこれを実現します。 例えば:

from django.views.decorators.cache import cache_control
@cache_control(private=True)
def my_view(request):
    # ...

このデコレータは、適切な HTTP ヘッダが送信されるように背後で気を配ります。

「プライベート」と「パブリック」キャッシュ制御は排他的であることを覚えておいてください。 デコレータは「プライベート」がセットされるべきである場合には「パブリック」ディレクティブ を取り除きます(逆も同じです)。プライベートとパブリックなエントリの両方を持つブログサイトで 二つのディレクティブを使う例です。パブリックなエントリは共有キャッシュとしてキャッシュされます。 コードに登場する patch_cache_controll はキャッシュ制御ヘッダをマニュアルで修正 します(内部的には cache_control デコレータを呼び出します)。:

from django.views.decorators.cache import patch_cache_control
from django.views.decorators.vary import vary_on_cookie

@vary_on_cookie
def list_blog_entries_view(request):
    if request.user.is_anonymous():
        response = render_only_public_entries()
        patch_cache_control(response, public=True)
    else:
        response = render_private_and_public_entries(request.user)
        patch_cache_control(response, private=True)

    return response

他にもキャッシュパラメタを操作する方法がいくつかあります。例えば、 HTTP を 使うアプリケーションは以下のような操作を行えます:

  • ページの最大キャッシュ回数を定義できます。
  • キャッシュされているコンテンツの新たなバージョンがないか常に調べ、変 更がないときに限ってキャッシュを送信するように設定できます (キャッシュ によっては、サーバ上のページが変更されていても、単にキャッシュコピー の有効期限が切れていないという理由でキャッシュされた内容を配信するこ とがあります)。

Django では、ビュー関数デコレータの cache_control を使って、キャッシュ パラメタを設定します。以下の例では、 cache_control を使って、アクセス ごとにコンテンツの再検証を行い、キャッシュされたバージョンの最大保存期限を 3600 秒に設定しています:

from django.views.decorators.cache import cache_control

@cache_control(must_revalidate=True, max_age=3600)
def my_view(request):
    # ...

有効な Cache-Control HTTP ディレクティブは全て cache_control() に 使えます。利用できるディレクティブを示します:

  • public=True
  • private=True
  • no_cache=True
  • no_transform=True
  • must_revalidate=True
  • proxy_revalidate=True
  • max_age=num_seconds
  • s_maxage=num_seconds

Cache-Control HTTP ディレクティブの説明は Cache-Control の仕様 を参照し てください。

(キャッシュミドルウェアは常にキャッシュヘッダの最長寿命 (max-age) を CACHE_MIDDLEWARE_SETTINGS の設定値に設定するので注意してください。カス タムの max_agecache_control デコレータで使うと、デコレータの設 定が優先され、ヘッダの値は正しくマージされます。)

ヘッダを使ってキャッシュを抑制したい場合には、 django.views.decorators.cache.never_cache を使ってください。このデコレー タは、応答コンテンツがブラウザやその他のキャッシュ機構によってキャッシュさ れないようにヘッダを追加します:

from django.views.decorators.cache import never_cache

@never_cache
def myview(request):
    # ...

その他の最適化

Django には、アプリケーションのパフォーマンスを最適化する上で役立つミドルウェ アが他にもいくつかあります:

  • django.middleware.http.ConditionalGetMiddleware を使うと、条件付 き GET をサポートできるようになり、 ETag および Last-Modified ヘッダを使えるようになります。
  • django.middleware.gzip.GZipMiddleware は gzip 圧縮を扱えるブラウ ザ (最近のほとんどのブラウザが対応しています) に対して、コンテンツを gzip で圧縮します。

MIDDLEWARE_CLASSES の順番

キャッシュ関連のミドルウェアを使う場合、 MIDDLEWARE_CLASSES 設定中の 正しい場所に配置することが重要です。というのも、キャッシュミドルウェアは キャッシュストレージ上のコンテンツとの差異を検出するために、どのヘッダが変 更されたかを調べる必要があるからです。ミドルウェアは通常、必要に応じて Vary レスポンスヘッダに情報を付加します。

UpdateCacheMiddleware はレスポンスフェイズに動作します。レスポンスフェ イズのミドルウェアは逆順に処理されるので、リストの先頭のミドルウェアは 最後 に呼び出されます。従って、 UpdateCacheMiddleware は、 Vary ヘッダに何らかの情報を付加するミドルウェアよりも 手前 に追加せねばなりま せん。以下のミドルウェアが、 Vary ヘッダを操作します:

  • SessionMiddlewareCookie を追加します。
  • GZipMiddlewareAccept-Encoding を追加します。
  • LocaleMiddlewareAccept-Language を追加します。

一方、 FetchFromCacheMiddleware はリクエストフェイズに動作します。リク エストフェイズでは、ミドルウェアは先頭から末尾に向けて処理されるので、 リストの先頭にあるミドルウェアが 最初 に呼び出されます。 FetchFromCacheMiddleware もまた、 Vary ヘッダを操作するミドルウェア よりも後に呼び出さねばならないので、 FetchFromCacheMiddleware後ろ に置かねばなりません。

ビューの条件付き処理

revision-up-to:17812 (1.4)

HTTP クライアントは様々なヘッダを送信することで、すでに閲覧されたリソースについ てサーバに伝えられます。 Web ページが (HTTP の GET リクエストを使って) 取得 されるとき、クライアントが既に取得しているデータを送信しないために使われます。 同じハンドラはすべての HTTP メソッド (POSTPUTDELETE など) に使われます。

Django がビューから返す、各ページ (レスポンス) は HTTP ヘッダを 2 つ提供します。 ETag ヘッダと Last-Modified です。これらのヘッダは HTTP レスポンスの オプションです。ビュー関数によって設定するか、 ETag ヘッダを設定する CommonMiddleware ミドルウェアを使ってでき ます。

クライアントが同じリソースを次にリクエストしたとき送られるヘッダは例えば、 If-modified-since や、 If-none-match などになるでしょう。 If-modified-since はリソースが送られたときの最終変更日時を保持し、 If-none-match はリソースが送られたときの ETag を保持しています。ページの 現在のバージョンがクライアントに送信された ETag に一致するか、リソースが変更 されていない場合は、 304 ステータスコードが返されます。クライアントにリソースの 変更が無いことを伝えるため、フルレスポンスの代わりに返されます。

より細かいコントロールが必要なら、ビューごとに条件付き処理関数を使ってください。

condition デコレータ

リソースへの ETag の値、最終変更日時を素早く算出する関数を、ビューをすべて コーディングする必要 なしに 作れます。ときおり (実際には頻繁に) 役立ちます。 Django ではそれらの関数を使用することで、ビューの処理のための “早期救済 (early bailout)” オプションを提供できます。クライアントに、コンテンツの内容が 最後のリクエスト以来修正されていないと伝えます。

これら 2 つの関数は、パラメータとして django.views.decorators.http.condition デコレータに渡されます。HTTP リクエストのヘッダがコンテンツ上のものとマッチする とき、このデコレータは 2 つの関数を使って解決します。 (両者を素早く、容易に 計算できない場合、どちらか 1 つを提供する必要があります) 。マッチしない場合は、 リソースの新しいコピーができ、通常のビューが呼ばれます。

condition デコレータは以下のようになります:

condition(etag_func=None, last_modified_func=None)

ETag と最終変更日時を計算する 2 つの関数は、 request オブジェクトとその他の 同じ引数を、同じ順序で、ラップされるビュー関数と同様に受け取ります。 last_modified_func に渡される関数が返すべき値は、リソースが変更された時間を 特定する標準の datetime 値です。リソースが存在しないなら None です。 etag デコレータに渡される関数が返すべき値は、リソースへの Etag を表す 文字列です。リソースが存在しないなら None です。

例で、この機能の有用な使い方を説明します。以下のような 2 つのモデルがあると仮定 します。これは単純なブログシステムを表現しています:

import datetime
from django.db import models

class Blog(models.Model):
    ...

class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    published = models.DateTimeField(default=datetime.datetime.now)
    ...

最新のブログ記事を表示するフロントページが、新しいブログ記事を追加したときのみ 変更されるとすると、このときの最終変更日時は非常に素早く計算できます。 その ブログに関連付けられた全エントリのうち、最新の published 日時が必要です。 以下のようになります:

def latest_entry(request, blog_id):
    return Entry.objects.filter(blog=blog_id).latest("published").published

この関数を使って、フロントページビューが変更されていないことを知らせられます:

from django.views.decorators.http import condition

@condition(last_modified_func=latest_entry)
def front_page(request, blog_id):
    ...

1 つの値を計算するだけのショートカット

一般的なルールとして、 ETag と最終変更日時の 両方を 計算する関数を提供できる なら、そうするべきです。任意の HTTP クライアントがどのヘッダを送るかは分からない ので、両方を扱えるよう用意すべきです。しかし、 1 つの値だけを計算するのは簡単 なので、 Django は ETag か最終変更日時の 1 つだけを計算するデコレータを提供して います。

django.views.decorators.http.etagdjango.views.decorators.http.last_modified デコレータには同じ種類の関数を 渡します。 condition デコレータと同じです。こんな感じです:

etag(etag_func)
last_modified(last_modified_func)

両デコレータのうちの、 last-modified 関数を使用して前述の例を書けます:

@last_modified(latest_entry)
def front_page(request, blog_id):
    ...

...あるいは:

def front_page(request, blog_id):
    ...
front_page = last_modified(latest_entry)(front_page)
両条件を検査するのに condition を使う

両方の前提条件を検査するとき、 etaglast_modified デコレータを 繋いで使うば良いと思えるかもしれません。しかしこれは不正な動作を起こします。

# ダメコード。マネしないでね!
@etag(etag_func)
@last_modified(last_modified_func)
def my_view(request):
    # ...

# ダメコード終了

1 つめのデコレータは 2 つめについては何も知りません。 2 つめのデコレータが違う 方法で答えを出したとしても、 1 つめのデコレータはレスポンスが修正されないと 答えます。 condition デコレータは正しい動作をさせるために同時に両コール バック関数を使います。

このデコレータを他の HTTP メソッドに使う

condition デコレータは GETHEAD リクエスト以外にも使えます (この 場合 HEAD リクエストは GET と同じです) 。 POSTPUTDELETE リクエストのチェックを提供するために使えます。この場合、 “not modified” レスポンスは返されません。変更しようとしたリソースが、その間に すでに変わっていたことをクライアントに伝えます。

例えば、次のクライアントとサーバのやりとりを考えてみましょう:

  1. クライアントが /foo/ をリクエストします。
  2. サーバがコンテンツと ETag "abcd1234" を返します。
  3. クライアントが /foo/ の更新に HTTP PUT リクエストを送信します。更新 しようとしているバージョンを特定する If-Match: "abcd1234" ヘッダも送信 します。
  4. サーバはリソースが変更されたかどうかチェックします。 GET リクエストのとき と同じ方法 (同じ関数) で ETag を計算します。リソースが変更 されていた ときは、”前提条件失敗 (precondition failed)” を意味する 412 ステータスコード が返されます。
  5. 412 レスポンスを受信した後に、クライアントは /foo/GET リクエスト を送信します。コンテンツの変更前に、すでに変更されていたバージョンを取得 します。

この例が示す重要なことは、すべての状況において ETag および最終変更日時を計算する ために、同じ関数を使用できるということです。実際には同じ関数を 使うべき です。 そうすることで、いつでも同じ値が返されます。

ミドルウェアによる条件処理との比較

Django は、簡単で分かりやすい条件付き GET 処理を django.middleware.http.ConditionalGetMiddlewareCommonMiddleware によって提供しています。 確かに使いやすく、多くの状況に適していますが、それらミドルウェア機能性の一部には 高度な使用法に制限があります:

  • プロジェクトの全てのビューに適応されます。
  • レスポンスそのものの生成の助けになりません。重い処理になることがあります。
  • HTTP GET リクエストにのみ使えます。

問題にあわせて適したものを選ぶべきです。 ETag と変更日時を素早く計算でき、ある ビューがコンテンツの生成に時間がかかる場合、先述した condition デコレータの 使用を考慮すべきです。すべてがすでに高速化されているなら、ミドルウェアの使用が 相応しいでしょう。ビューが変更されていなければクライアントに送信されるネット ワークのトラフィック量は、さらに小さくなります。

暗号による署名

revision-up-to:17812 (1.4)
リリースノートを参照してください

Web アプリケーションセキュリティの黄金律は、信頼できないソースからのデータを決 して信頼しないということです。しかし時には信頼できない媒体にデータを通すことが 便利かもしれません。暗号により署名された値を使えば、どんな改ざんも検出されると いう知識のもとで、信頼できない経路を安全に通過できます。

Django は値を署名するための低レベル API と、署名つきクッキーを設定したり読み込 むための高レベル API を提供しています。署名つきクッキーは Web アプリケーション で最もよく使われる署名の一つです。

また、次のような場合に署名が使えることにお気づきでしょうか:

  • パスワードを紛失したユーザに送るために「アカウント復旧」用 URL を生成する。
  • フォームの hidden フィールドに格納されたデータが改ざんされていないことを確認 する。
  • 保護されたリソース (例えば料金を支払ってダウンロードできるファイル) に一時的 にアクセスするためのワンタイム URL を生成する。

SECRET_KEY の保護

startproject を使って新しく Django プロジェクトを作成すると、 settings.py ファイルが自動的に生成され SECRET_KEY にはランダム 値がセットされます。この値はデータを安全に署名するためのキーなので、このキーを 秘密に保つことが不可欠です。そうしなければ攻撃者がキーを使って自分の署名された 値を生成できてしまうでしょう。

低レベル API を使う

class Signer

Django の署名メソッドは django.core.signing モジュールにあります。値を署名 するには、最初に Signer インスタンスを生成します:

>>> from django.core.signing import Signer
>>> signer = Signer()
>>> value = signer.sign('My string')
>>> value
'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'

署名は、文字列の最後でコロンの後に付け足されます。 unsign メソッドを使うと 元の値を取得できます:

>>> original = signer.unsign(value)
>>> original
u'My string'

署名または値が何らかの方法で変更されると、 django.core.signing.BadSignature 例外が送出されます:

>>> value += 'm'
>>> try:
...    original = signer.unsign(value)
... except signing.BadSignature:
...    print "Tampering detected!"

デフォルトでは Signer クラスは SECRET_KEY 設定を署名の生成に使 います。 Signer コンストラクタに別の秘密鍵を渡して使うこともできます。

>>> signer = Signer('my-other-secret')
>>> value = signer.sign('My string')
>>> value
'My string:EkfQJafvGyiofrdGnuthdxImIJw'
ソルト (salt) 引数を使う

同じ文字列に対して毎回同じ署名ハッシュを取得したくないなら、オプションの salt 引数を Signer クラスに使うことができます。ソルトを使うと 署名ハッ シュ関数はソルトと SECRET_KEY の両方を使ってハッシュを生成します:

>>> signer = Signer()
>>> signer.sign('My string')
'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'
>>> signer = Signer(salt='extra')
>>> signer.sign('My string')
'My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw'
>>> signer.unsign('My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw')
u'My string'

このようにソルトを使うと、署名が別々の名前空間に置かれます。同じプレーンテキス トの検証でも、特定のソルト値を使ったある名前空間から得られた署名を、別のソルト を設定した名前空間で使うことはできません。この結果により、コードのある場所で生 成された署名つき文字列を、違うソルトを使って生成 (検証) している別の場所への入 力として攻撃者が使うことを防げます。

SECRET_KEY と違って、ソルト引数は秘密にする必要がありません。

タイムスタンプつきの値を検証する
class TimestampSigner

TimestampSignerSigner のサブクラスで、署名つきタイムスタンプ を値に付け加えます。これによって署名された値が特定の期間に作られたことを確認で きます:

>>> from django.core.signing import TimestampSigner
>>> signer = TimestampSigner()
>>> value = signer.sign('hello')
>>> value
'hello:1NMg5H:oPVuCqlJWmChm1rA2lyTUtelC-c'
>>> signer.unsign(value)
u'hello'
>>> signer.unsign(value, max_age=10)
...
SignatureExpired: Signature age 15.5289158821 > 10 seconds
>>> signer.unsign(value, max_age=20)
u'hello'
複雑なデータ構造を保護する

リストやタプルや辞書を保護したいのであれば、 signing モジュールの dumpsloads 関数を使ってください。これらの関数は Python の pickle モジュールを 真似た動きをします。ただし舞台裏では JSON シリアライズを使います。 JSON は SECRET_KEY が盗まれた時でさえ、攻撃者が pickle フォーマットを利用し て任意のコマンドを実行できないことを保証します:

>>> from django.core import signing
>>> value = signing.dumps({"foo": "bar"})
>>> value
'eyJmb28iOiJiYXIifQ:1NMg1b:zGcDE4-TCkaeGzLeW9UQwZesciI'
>>> signing.loads(value)
{'foo': 'bar'}
dumps(obj, key=None, salt='django.core.signing', compress=False)

sha1 で署名され base64 で圧縮された URL を安全に使える JSON 文字列を返しま す。

loads(string, key=None, salt='django.core.signing', max_age=None)

dumps() の逆です。署名が間違っていると BadSignature を送出します。

メールの送信

revision-up-to:17812 (1.4)

Python の smtplib モジュール を使えば、比較的簡単にメールを送信できます が、 Django ではこのライブラリへの軽量ラッパを二つ用意しています。これらのラッパ ではメールの送信を極めて素早くおこなえ、開発時のテストメールの送信を簡単にでき、 SMTPを使えないプラットフォームにも対応しています。

コードは: django.core.mail にあります。

お手軽な例

二行だけです:

from django.core.mail import send_mail

send_mail('Subject here', 'Here is the message.', 'from@example.com',
    ['to@example.com'], fail_silently=False)

これで、 EMAIL_HOST および EMAIL_PORT 設定で指定した SMTP ホストを介してメールを送信します。 EMAIL_HOST_USER および EMAIL_HOST_PASSWORD を指定していれば、 SMTP サーバの認証に使います。 また、SMTP サーバとの接続に TLS を使うかどうかを EMAIL_USE_TLS で設定できます。

Note

django.core.mail で送信されるメールの文字セットは DEFAULT_CHARSET 設定の値に設定されます。

send_mail()

send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None)

メールを送信する最も簡単な方法は django.core.mail.send_mail() です。

subject, message, from_email および recipient_list は必須の パラメタです。

  • subject: 文字列です。
  • message: 文字列です。
  • from_email: 文字列です。
  • recipient_list: 文字列からなるリストで、各々がメールアドレ スを表します。 recipient_list に入っているユーザは、お互いに他のユー ザをメールの “To:” フィールドで見られます。
  • fail_silently: ブール型の値です。 False なら send_mailsmtplib.SMTPException 例外を出すようになります。 送出されうる例外のリストは smtplib ドキュメントを参照してくださ い。いずれの例外も SMTPException のサブクラスです。
  • auth_user: オプションです。 SMTP サーバでの認証に使うユーザ名です。 この値を指定しなければ、 Django は EMAIL_HOST_USER 設定を使います。
  • auth_password: オプションです。 SMTP サーバでの認証に使うパスワー ドです。この値を指定しなければ、 Django は EMAIL_HOST_PASSWORD 設 定を使います。
  • connection: オプションです。メール送信に使うバックエンドです。 明示しなければデフォルトのバックエンドが使われます。詳細はドキュメントの Email backends を参照してください。

send_mass_mail()

send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None, connection=None)

django.core.mail.send_mass_mail() は一括メール (mass email) の送信 用の関数です。この関数の定義は以下の通りです

datatuple はタプルで、各要素は以下の形式になっています:

(subject, message, from_email, recipient_list)

fail_silently, auth_user および auth_passwordsend_mail() と同じです。

datatuple の各要素ごとに個別のメールメッセージを作成して送信します。 send_mail() と同様、同じ recipient_list に入ってい る受信者は、他の受信者を “To:” フィールドで見られます。

例えば下記のコードでは、2つのメールがそれぞれ複数の宛先に一斉送信されます。 しかし、メールサーバへの接続は1つだけ開かれます。:

message1 = ('Subject here', 'Here is the message', 'from@example.com', ['first@example.com', 'other@example.com'])
message2 = ('Another Subject', 'Here is another message', 'from@example.com', ['second@test.com'])
send_mass_mail((message1, message2), fail_silently=False)
send_mass_mail() と send_mail()

send_mass_mail()send_mail() の大きな違いは send_mail() は実行の度にメールサーバに 接続するのに対し、 send_mass_mail() は全てのメッセージの 送信に一つの接続を使う点です。このため、 send_mass_mail() の方が少しだけ効率的です。

mail_admins()

mail_admins(subject, message, fail_silently=False, connection=None, html_message=None)

django.core.mail.mail_admins()ADMINS に書かれたサイト管理者 へのメール送信を行うためのショートカットです。

mail_admins() はサブジェクトの先頭に EMAIL_SUBJECT_PREFIX の 設定値を付加します。デフォルトは "[Django] " です。

メールの “From:” ヘッダには SERVER_EMAIL の設定値が入ります。

このメソッドは利便性と可読性のために用意されています。

リリースノートを参照してください

html_message が指定されているなら、結果のメールは multipart/alternative メールになります。 text/plain タイプの messagetext/html タイプの html_message から なります。

mail_managers()

mail_managers(subject, message, fail_silently=False, connection=None, html_message=None)

django.core.mail.mail_managers()mail_admins() と同じですが、メールを MANAGERS 設定に書かれたサイトマネジャに送信します。

以下の例は、単一のメールを john@example.comjane@example.com に送信 します。両方の宛先が “To:” に表示されます:

send_mail('Subject', 'Message.', 'from@example.com',
    ['john@example.com', 'jane@example.com'])

以下の例は、単一のメールを john@example.comjane@example.com に送信 しますが、受け取り人はそれぞれ別々のメッセージを受け取ります:

datatuple = (
    ('Subject', 'Message.', 'from@example.com', ['john@example.com']),
    ('Subject', 'Message.', 'from@example.com', ['jane@example.com']),
)
send_mass_mail(datatuple)

ヘッダインジェクションの抑制

ヘッダインジェクション とは、スクリプトが生成したメッセージの “To:” や “From:” に、攻撃者が余分なメールヘッダを挿入するというセキュリティ侵害 です。

上記で解説した Django のメール機能では、ヘッダの値に改行を使えないよう にしてヘッダインジェクションを防御しています。 subject, from_email および recipient_list が (Unix, Windows または Mac 形式の) 改行を含む場 合、メール送信関数 ( send_mail() など) は django.core.mail.BadHeaderError 例外 (ValueError のサブクラス) を送 出します。このため、メールは送信されません。メール送信関数に渡すデー タの検証はユーザに任されています。

message の文字列の先頭にヘッダが入っている場合、ヘッダは単にメッセー ジ本文の先頭部分として出力されます。

以下に示すのは、 subject, message および from_email をリクエス トの POST データから受け取り、メールを admin@example.com に送信し、終了した ら “/contact/thanks/” にリダイレクトする例です:

from django.core.mail import send_mail, BadHeaderError

def send_email(request):
    subject = request.POST.get('subject', '')
    message = request.POST.get('message', '')
    from_email = request.POST.get('from_email', '')
    if subject and message and from_email:
        try:
            send_mail(subject, message, from_email, ['admin@example.com'])
        except BadHeaderError:
            return HttpResponse('Invalid header found.')
        return HttpResponseRedirect('/contact/thanks/')
    else:
        # 実際にはフォームクラスを使って適切な検証エラーを
        # 取得するべきでしょう。
        return HttpResponse('Make sure all fields are entered and valid.')

EmailMessage クラス

Django の send_mail() および send_mass_mail() 関数は、実際には EmailMessage クラスに対して薄いラッパをかぶせたものに すぎません。

send_mail() をはじめとしたラッパ関数から利用できる 機能は、 EmailMessage クラスで提供している全ての 機能をカバーしているわけではありません。BCC への宛先を指定やファイルの添付、 マルチパート形式メールの送信などを行いたい場合には、 EmailMessage インスタンスを直接生成する必要があり ます。

Note

send_mail()`() がこのような、いささかややこしい仕様 なのは、設計上の事情によるものです。 send_mail()`() などの関数はもともと単なる Django 向けの単純なメールインタフェースでしか ありませんでした。その後、指定できるパラメタが少しづつふえてきたのです。 今となっては、メールメッセージを扱うためのよりオブジェクト指向の設計に移行 して、 send_mail()`() は互換性のためだけにおいておく 方が有意義でしょう。

EmailMessage はメールメッセージ自体の生成に関わり ます。 メールバックエンド は、メールの送信に関わり ます。

便宜上、 EmailMessage は単純な send() メソッド を単一のメールを送信するために提供しています。複数のメッセージを送りたいときは、 メールバックエンドAPIは 他の手段を提供しています

EmailMessage オブジェクト
class EmailMessage

EmailMessage クラスは以下のパラメタ (固定引数を使 う場合には以下に示す順番に指定します) で初期化します。パラメタは全て省略可能 で、 send() メソッドを呼び出す前であればいつでも設定しなおせます。

引数 cc が追加されました。
  • subject: メールの題名です。
  • body: メール本文です。平文テキストのメッセージでなければなりません。
  • from_email: 送信者のアドレスです。 fred@example.com 形式でも Fred <fred@example.com> 形式でもかまいません。省略すると、 DEFAULT_FROM_EMAIL の設定値を使います。
  • to: 受信者アドレスのリストまたはタプルです。
  • bcc: メールを送信する際に “Bcc” ヘッダに指定するアドレスのリスト
    またはタプルです。
  • connection: メールバックエンドのインスタンスです。一つの SMTP 接 続を使い回して複数のメッセージを送信したい場合に指定します。この引数を省略する と、 send() を呼び出す瞬間に新しい接続を生成します。
  • attachments: メールに添付するデータのリストです。リストの各要素は、 email.MIMEBase.MIMEBase のインスタンスか、 (filename, content, mimetype) からなるタプルです。
  • headers: メッセージに追加するヘッダの辞書です。ヘッダ名をキーに、 ヘッダ値を値にします。このパラメタを使うのなら、指定したヘッダがメー ルメッセージ中で正しいヘッダとして扱われるように気をつけねばなりませ ん。
  • cc: 受信者アドレスのリストまたはタプルです。メール送信時の “Cc” ヘッダに 使われます。

例を示します:

email = EmailMessage('Hello', 'Body goes here', 'from@example.com',
            ['to1@example.com', 'to2@example.com'], ['bcc@example.com'],
            headers = {'Reply-To': 'another@example.com'})

EmailMessage クラスのインスタンスには以下のようなメソッドがあります:

  • send(fail_silently=False) メソッドはメッセージを送信します。メールが作成さ れたときに接続が指定されれば、その接続が使われます。接続がなければ、デフォルト バックエンドのインスタンスが生成され、使われます。 fail_silentlyTrue にすると、メッセージ送信に失敗した場合に例外を送出します。

  • message()django.core.mail.SafeMIMEText クラス (Python の email.MIMEText.MIMEText クラスのサブクラス) または django.core.mail.SafeMIMEMultipart クラスのインスタンスを生成します。 このオブジェクトには送信するメッセージが入っています。 EmailMessage クラスを拡張する必要がある場合、 おそらくこのメソッドをオーバライドして、所望の内容を MIME オブジェクト内に 配置することになるでしょう。

  • recipients() はメッセージの全ての宛先からなるリストを返します。この 宛先リストは、 tobcc に指定した全ての宛先が入ります。 EmailMessage をサブクラス化する際、このメソッドも オーバライドする必要があるかもしれません。というのも、 SMTP サーバはメッセージ 送信時に全ての宛先を知る必要があり、全ての宛先はこのメソッドを介して返さねば ならないからです。

  • attach() を呼び出すと、新たなファイル添付用パートを生成してメッセー ジに追加します。 attach() の呼び出しかたは 2 通りあります:

    • attach() に引数を一つだけ指定し、 email.MIMEBase.MIMEBase のインスタンスを渡します。このインスタンスの内容は最終的なメッセージ に直接挿入されます。

    • 別の方法として、 attach() に 3 つの引数、 filename, content および mimetype を渡します。 filename は添付する ファイルの名前で、これはメール中で表示される添付ファイルの名前になり ます。 content は添付パート中に入るデータで、 mimetype は添 付内容の MIME タイプです。 mimetype を省略すると、ファイル名を元 に推測を行います。

      例を示します:

      message.attach('design.png', img_data, 'image/png')
      
  • attach_file() を呼び出すと、ファイルシステム上のファイルから添付パー トを生成します。 attach_file() の引数には添付したいファイルのパスを 指定します。オプションとして、添付ファイルの MIME タイプも指定できます。 MIME タイプを省略すると、ファイル名をもとに推測を行います。簡単な使い方 を示すと、以下のようになります:

    message.attach_file('/images/weather_map.png')
    
拡張コンテンツ形式のメールを送信する

メールの内容をいくつかのバージョンに分けて送信すると便利な場合があります。 古典的な例でいえば、テキスト形式と HTML 形式の両方でメールを送信するような 場合です。 複数バージョンのメールを同時に送るには、 EmailMultiAlternatives クラス を使います。このクラスは EmailMessage のサブクラスで、 attach_alternative() メソッドを使ってメールのメッセージ本文に別のバージョ ンの本文を追加できます。 attach_alternative() 以外は、(クラスをインスタ ンス化するときの初期化メソッドも含めて) EmailMessage と全く同じです。

テキストと HTML を組み合わせて送信したければ、以下のように書けます:

from django.core.mail import EmailMultiAlternatives

subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
text_content = 'This is an important message.'
html_content = '<p>This is an <strong>important</strong> message.</p>'
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()

デフォルトでは、 EmailMessagebody パラメタの MIME タイプは "text/plain" です。実践的には、このパラメタは変更せずにおいた 方がよいでしょう。なぜなら、メールを受信した人が使っているメールクライアントソフ トに関係なくメッセージを読めるよう保証できるからです。とはいえ、メールの読み手 が拡張コンテンツ形式 (alternative content type) のメッセージを扱えると分かっ ている場合には、 EmailMessagecontent_subtype 属性を使って、主メッセージのコンテンツタイプを変更できます。メールのメジャー コンテンツタイプは常に "text" ですが、サブタイプは以下のように変更できます:

msg = EmailMessage(subject, html_content, from_email, [to])
msg.content_subtype = "html"  # メインのコンテンツは text/html になります。
msg.send()

メールバックエンド

リリースノートを参照してください

メールを送るのは、実際にはメールバックエンドが扱っています。

メールバックエンドクラスには以下のようなメソッドがあります:

  • open() 永続するメール送信接続をインスタンス化します。
  • close() 現在のメール送信接続を閉じます。
  • send_messages(email_messages) EmailMessage オブジェクトを送信します。接続が開かれていないときは暗黙的に接続が開かれ、 メール送信後に閉じられます。 接続がすでに開かれているときは、メール送信後も 接続は開かれたままになります。
メールバックエンドのインスタンスを得る

django.core.mailget_connection() 関数はメールバックエンドの インスタンスを、あなたが使えるように返します。

get_connection(backend=None, fail_silently=False, *args, **kwargs)

デフォルトで get_connection()EMAIL_BACKEND で指定された メールバックエンドのインスタンスを返します。引数 backend を指定した 場合は、そのバックエンドのインスタンスを返します。

fail_silently 引数は、バックエンドがエラーを扱うかどうかを指定できます。 fail_silently が True のときは、メール送信プロセス中の例外が無視されます。

それ以外の引数は、メールバックエンドのコンストラクタに直接渡されます。

いくつかのメール送信バックエンドが Django には付属しています。SMTPバックエンド (デフォルト)以外のバックエンドは、テストと開発時にのみ有効です。特別なメール送信 が必要な場合は、 自分でメールバックエンドを書いてください

SMTP バックエンド

これはデフォルトのバックエンドです。メールは SMTP サーバを通して送信されます。 サーバのアドレスと認証情報は EMAIL_HOSTEMAIL_PORTEMAIL_HOST_USEREMAIL_HOST_PASSWORDEMAIL_USE_TLS 設定を設定ファイルに書いてください。

SMTP バックエンドは古くから Django のデフォルトです。 明示的に指定したいときは以下のように設定ファイルに書いてください:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

SMTPConnection objects

先のバージョン 1.2 では、 Django は SMTPConnection クラスを提供していました。このクラスは SMTP を直接制御してメールを送信する方法 を提供します。このクラスは、汎用のメールバックエンドAPIが採用さたので廃止され ました。

後方互換性のために SMTPConnection は SMTP バックエンドの別名として django.core.mail で依然使えます。

コンソールバックエンド

実際にメールを送信する代わりに、コンソールバックエンドはただメールを書く だけです。コンソールバックエンドに書かれたメールは標準出力に送られます。 デフォルトでは、コンソールバックエンドは stdout に書きます。 接続を構成するときに stream キーワード引数を与えると、他のストリームなどの オブジェクトも使えます。

コンソールバックエンドを指定するには以下を設定ファイルに記述してください:

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

コンソールバックエンドは製品での使用を意図していません。開発時に使える、利便性の ため提供されるものです。

ファイルバックエンド

ファイルバックエンドはメールをファイルに書き込みます。ファイルバックエンドが 新しいセッションを開く度に、新しいファイルは作られます。ファイルが書き込まれる ディレクトリは、 EMAIL_FILE_PATH 設定か file_path キーワードの どちらかで決められます。これは get_connection() との接続 が作成されるときに決まります。

ファイルバックエンドを指定するには以下を設定ファイルに記述してください:

EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = '/tmp/app-messages' # 適切な値に変えてください。

ファイルバックエンドは製品での使用を意図していません。開発時に使える、利便性の ため提供されるものです。

メモリバックエンド

'locmem' バックエンドはメッセージを django.core.mail モジュールの特殊な 属性に格納します。 outbox 属性は最初のメッセージが送られたときに作られます。 EmailMessage インスタンスのリストがそれぞれのメッセージ として送られます。

メモリバックエンドを指定するには以下を設定ファイルに記述してください:

EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

メモリバックエンドは製品での使用を意図していません。開発やテスト時に使える、 利便性のため提供されるものです。

ダミーバックエンド

名前が示すように、ダミーバックエンドはメッセージに対して何もしません。

ダミーバックエンドを指定するには以下を設定ファイルに記述してください:

EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'

ダミーバックエンドは製品での使用を意図していません。開発時に使える、利便性の ため提供されるものです。

カスタムメールバックエンドを定義する

メールがどのようにして送られるかを変更する必要があるなら、あなた自身のメールバッ クエンドを書いてください。設定ファイルの EMAIL_BACKEND 設定には、 あなたが書いたバックエンドへの Python インポートパスを指定してください。

カスタムメールバックエンドは django.core.mail.backends.base モジュールにあ る BaseEmailBackend のサブクラスであるべきです。カスタムメールバックエンド は send_messages(email_messages) メソッドを実装しなければなりません。この メソッドは EmailMessage インスタンスを受け取り、正常 に送信されたメッセージの数を返します。カスタムメールバックエンドが永続するセッ ションか接続をもてるようにするには、 open() および close() メソッドも実 装する必要があります。リファレンス実装のために smtp.EmailBackend を参考にして ください。

複数のメールを送信する

SMTP 接続の確立と切断(もしくは他のどのネットワーク接続もそうですが)は重い処理 です。多くのメールを送る必要があるなら、 SMTP 接続を再利用するのは納得できます。 メールを送る度に接続を確立して切断するのは良い方法ではないでしょう。

接続を再利用できるようにメールバックエンドに指定する方法は2つあります。

第一に、 send_messages() メソッドを使う方法があります。 send_messages()EmailMessage インスタンス (もしくはサブクラス) の リストを受け取り、1つの接続を使ってそれら全てを送信します。

例えば get_notification_email() 関数を使えば、定期送信するメールを EmailMessage オブジェクトのリストで返してくれるので、 そのまま send_messages を使って送信することができます:

from django.core import mail
connection = mail.get_connection()   # デフォルトのメール接続を使います。
messages = get_notification_email()
connection.send_messages(messages)

この例では、 send_messages() は接続をバックエンドで開き、メッセージのリスト を送信し、さらに接続を切断します。

2つ目の方法はメールバックエンドの open()close() メソッドを手動で使っ て接続をコントロールすることです。 send_sessages() では手動で接続を開いたり 閉じたりコントロールできません。すでに接続が開かれているときは手動で接続を開いた ということなので、閉じるタイミングをコントロールできます:

from django.core import mail
connection = mail.get_connection()

# 手動で接続を開きます。
connection.open()

# メールメッセージを作成します。さっき作った接続で使います。
email1 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com',
                          ['to1@example.com'], connection=connection)
email1.send() # Send the email

# さらに二つ作成します。
email2 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com',
                          ['to2@example.com'])
email3 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com',
                          ['to3@example.com'])

# 二つのメールを一つの呼び出しで送信します。
connection.send_messages([email2, email3])
# send_messages() が接続を閉じなかったので未だに開かれています。
# なので手動で閉じる必要があります。
connection.close()

メール送信のテスト

Django に一切のメール送信をしてほしくないときがあります。例えば、 Web サイトの 開発をしているとき、何千ものメールを送信してほしくないと思います。しかし適切な 条件の下で適切な相手に、正しい内容のメールを送るのを認めたい場合があるかもしれま せん。

プロジェクトのメールの扱いをテストする最も簡単な方法は console を使うこと です。このバックエンドはすべてのメールを標準出力にリダイレクトします。これで メールの内容を検査することができます。

file メールバックエンドも開発時には使えます。このバックエンドはすべての SMTP コネクションのコンテンツをファイルにダンプします。なので暇なときに検査 できます。

他にも “無口な (dumb)” SMTP サーバを使う方法があります。この SMTP サーバはロー カルでメールを受け取って端末に表示しまが、送信はなにもしません。 Python のビル ドインで、1つのコマンドでできます:

python -m smtpd -n -c DebuggingServer localhost:1025

このコマンドはローカルホストのリスニングポート 1025 で SMTP サーバ を開始しま す。このサーバはすべてのメールのヘッダ、ボディーを標準出力に書き出します。そし て必要なのは EMAIL_HOSTEMAIL_PORT をそれらしく設定し ます。以上です。

ローカルでのメールの処理やテストの詳細については、 Python ドキュメントの smtpd を参照してください。

SMTPConnection

class SMTPConnection

Deprecated since version 1.2.

SMTPConnection クラスは汎用のメールバックエンドAPIが採用されたので廃止されま した。

後方互換性のために SMTPConnection は依然使えます。 django.core.mailSMTP バックエンド の 別名として存在します。これから書くコードには get_connection() を使うべきです。

国際化とローカライズ

revision-up-to:17812 (1.4)

翻訳

revision-up-to:17812 (1.4)
概要

Django プロジェクトを翻訳可能にするためには、 Python コードに最小限のフックを入 れなければなりません。このフックは 翻訳文字列 と呼ばれます。翻訳文字列は Django に「もしこのテキストがエンドユーザの言語に翻 訳可能であれば、翻訳すべきだ」ということを教えます。翻訳可能な文字列をマークす ることは開発者の責任です。システムは教えられた文字列だけを翻訳できます。

Django は翻訳文字列を メッセージファイル に抽出するユーティリティを提供 します。このファイルがあるため、翻訳者が対象の言語において翻訳文字列に対応する 文字列を用意することが簡単になります。翻訳者がメッセージファイルの中身を書き終 わったら、それをコンパイルしなければなりません。このプロセスは GNU gettext ツー ルキットに依存しています。

これが済めば Django は、ユーザの言語設定に従い、利用可能な言語へのアプリケーシ ョン翻訳をオンザフライで行えるようになります。

Django の国際化フックはデフォルトで有効になっています。これは、フレームワークの 特定の箇所で小さなオーバーヘッドが存在することを意味します。もし国際化を使わな いなら、 USE_I18N = False を設定ファイルに記述してくださ い。そうすれば Django は国際化機構を読み込まないようにして多少の最適化をします。 'django.core.context_processors.i18n'TEMPLATE_CONTEXT_PROCESSORS から取り除くのも効果があります。

Note

関連する設定として、 Django が書式ローカライズをすべきかを制御する USE_L10N があります。 書式ローカライズ を参照してください。

Python コードでの国際化
標準的な翻訳

翻訳対象文字列を関数 ugettext() で指定します。タイプ数を減らすため、 ugettext()_ という別名で import するのが慣習的なやり方です。

Note

Python の標準ライブラリ gettext は、グローバルの名前空間に _() とい う名前で gettext() をインストールします。 Django ではこの方法に 従って いませんが、それは以下の理由からです:

  1. 国際化文字セット (Unicode) のサポート下では、 gettext() よりも ugettext() の方が便利だからです。また、ファイルによっては ugettext_lazy() をデフォルトの翻訳用メソッドに使った方がよい場合もあ ります。グローバル名前空間に _() がなければ、開発者に 場合に応じて適 切な翻訳用メソッドを選ぶ自由を与えられます。
  2. アンダースコア文字は、 Python の対話シェルや doctest で書かれたテスト中 では「直前の式の値」を表します。そのため、グローバル名前空間に _() をインストールすると、干渉して問題を引き起こします。 ugettext()_() という名前で明示的に import すれば、この問題を回避できます。

下の例では、 "Welcome to my site." というテキストを翻訳文字列としてマークし ます:

from django.utils.translation import ugettext as _

def my_view(request):
    output = _("Welcome to my site.")
    return HttpResponse(output)

もちろん、 ugettext() に別名を付けなくても使えます。従って、下の例は上の例 と全く同じになります:

from django.utils.translation import ugettext

def my_view(request):
    output = ugettext("Welcome to my site.")
    return HttpResponse(output)

翻訳は計算済みの値に対して行われます。従って、下の例も上の 2 例と同じになります

def my_view(request):
    words = ['Welcome', 'to', 'my', 'site.']
    output = _(' '.join(words))
    return HttpResponse(output)

翻訳は変数に対しても使えます。従って、下の例もまた、上の例と同じになります:

def my_view(request):
    sentence = 'Welcome to my site.'
    output = _(sentence)
    return HttpResponse(output)

(上の 2 つの例のように変数や計算済みの値を使う場合、 Django の翻訳文字列検 出ユーティリティ django-admin.py makemessages は これらの文字列を検出できないので注意しておきましょう。詳しくは後の makemessages の節で説明します。)

_()ugettext() に渡す文字列には、 Pyton の標準の名前付き補完構文 によるプレースホルダを使えます。例えば:

def my_view(request, m, d):
    output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d}
    return HttpResponse(output)

このテクニックを使うと、言語ごとの翻訳でプレースホルダを並べ変えできるよう になり、例えば、英語の翻訳文が "Today is Nobember, 26." であるのに対し て、スペイン語では "Hoy es 26 de Noviembre." であるように、プレースホル ダの位置を翻訳文の前後で移動できます。

この理由から、引数が複数ある場合には、固定引数を使った補完 (%s%d) ではなく、名前付きの補完 (%(day)s) を使ってください。固定引数 による補完を使った場合、プレースホルダの順番によってうまく翻訳できない場合 があります。

翻訳者へのコメント
リリースノートを参照してください

翻訳可能文字列について翻訳者にヒントを与えたい場合は、 Translators キ ーワードで始まるコメントを、翻訳可能文字列の直前の行に置きます:

def my_view(request):
    # Translators: This message appears on the home page only
    output = ugettext("Welcome to my site.")

テンプレートでは comment タグで同じことができます:

{% comment %}Translators: This is a text of the base template {% endcomment %}

コメントは .po ファイルの中に入り、ほとんどの翻訳ツールで表示できます。

すぐには翻訳しない文字列をマークする

すぐには翻訳しない文字列のマークには django.utils.translation.ugettext_noop() を使って下さい。マークした文字 列は後で変数として使われるときに翻訳されます。

この関数は、ソース言語の中に定数として文字列を置いておきたい場合に使います。 というのも、定数は、例えばデータベース中の文字列のように、システムやユーザ 間で共通な値である一方で、ユーザにメッセージとして提示する最後の段階で翻訳 せねばならない場合があるからです。

複数形化

複数形のメッセージを指定するには django.utils.translation.ungettext() を使います。

ungettext は 単数形の翻訳文字列、複数形の翻訳文字列、オブジェクトの数 の 3 つの引数を取ります。

この関数は、 複数形 の形式が英語よりも多くて複雑な言語へアプリケーションをローカライズする時に使えます。

例えば:

from django.utils.translation import ungettext

def hello_world(request, count):
    page = ungettext(
        'there is %(count)d object',
        'there are %(count)d objects',
    count) % {
        'count': count,
    }
    return HttpResponse(page)

この例ではオブジェクトの数が count 変数として翻訳文字列に渡されます。

もうちょっと複雑な使用例を見てみましょう:

from django.utils.translation import ungettext

count = Report.objects.count()
if count == 1:
    name = Report._meta.verbose_name
else:
    name = Report._meta.verbose_name_plural

text = ungettext(
        'There is %(count)d %(name)s available.',
        'There are %(count)d %(name)s available.',
        count
) % {
    'count': count,
    'name': name
}

この例では、文の中の別の部分のために、ローカライズ可能で、うまくすれば既に翻訳 済みのリテラルを再利用しています。 (モデル Metaverbose_nameverbose_name_plural オプションに含まれています) そのため全体が要素のカーディナリティ (cardinality) をもとに一貫したものになりま す。

Note

このテクニックを使う場合、全ての推定の変数に単数形を使うようにしてください。 上の例では Python 変数の name が両方の翻訳文字列で使われていたことに注 意してください。次の例はうまく行きません:

from django.utils.translation import ungettext
from myapp.models import Report

count = Report.objects.count()
d = {
    'count': count,
    'name': Report._meta.verbose_name,
    'plural_name': Report._meta.verbose_name_plural
}
text = ungettext(
        'There is %(count)d %(name)s available.',
        'There are %(count)d %(plural_name)s available.',
        count
) % d

django-admin.py compilemessages: を実行すると エラーが出ます:

a format specification for argument 'name', as in 'msgstr[0]', doesn't exist in 'msgid'
コンステキストマーカー
リリースノートを参照してください

英語の "May" が月の名前と動詞を指すように、単語が複数の意味を持つことがあ ります。このような単語を翻訳者が異なる文脈で正しく翻訳できるようにするには、 django.utils.translation.pgettext() 関数、または複数形が必要な場合は django.utils.translation.npgettext() 関数を使えます。いずれも、最初の 変数に文脈文字列 (context string) を取ります。

.po ファイルでは、この文字列は同じ文字列に対する別々のコンテキストマーカ ーとして現れるので、翻訳者はそれぞれに対して別の訳を当てることができます。

例えば:

from django.utils.translation import pgettext

month = pgettext("month name", "May")

もしくは:

from django.utils.translation import pgettext_lazy

class MyThing(models.Model):
    name = models.CharField(help_text=pgettext_lazy(
        'help text for MyThing model', 'This is the help text'))

これらは .po ファイルでは、このように見えます:

.. code-block:: po
msgctxt “month name” msgid “May” msgstr “”
リリースノートを参照してください

trans および blocktrans テンプレートタグはコンテキストマーカー をサポートするようになりました。

翻訳を遅延させる

文字列の翻訳を遅延させる – 値が呼び出された時ではなく、アクセスされた時に翻訳 するには、 django.utils.translation モジュールで遅延バージョンの翻訳関 数を使ってください。 (名前の末尾に lazy がついているのですぐに見分けられま す)

これらの関数は、実際の翻訳結果ではなく、文字列への遅延参照を保存します。翻訳 自体は、文字列がテンプレートのレンダリングなど文字列コンテキストで使われた時 に行われます。

これが重要なのは、モジュールのロード時にコードパスにこれらの関数の呼び出しが配 置されるような時です。

これはモデル、フォーム、モデルフォームを定義する時に容易に起こりえます。 Django はこれらのフィールドをクラスレベル属性として実装しているからです。この 理由により、そのような場合は遅延翻訳を使っているか確認してください。

モデルフィールドとリレーションでの verbose_namehelp_text

例えば次のモデルで name フィールドのヘルプテキストを翻訳するには、以下のよう にします:

from django.utils.translation import ugettext_lazy

class MyThing(models.Model):
    name = models.CharField(help_text=ugettext_lazy('This is the help text'))

verbose_name オプションによって、 ForeignKeyManyTomanyFieldOneToOneField の名前をマークすることができます:

from django.utils.translation import ugettext_lazy as _

class MyThing(models.Model):
    kind = models.ForeignKey(ThingKind, related_name='kinds',
                             verbose_name=_('kind'))

verbose_name でするように、小文字の名前を渡す 必要があります。 Django はそれを必要な時に自動でタイトルケースにします。

モデルの verbose name の値

verbose_nameverbose_name_plural オプションを明示的に指 定することをお勧めします。 モデルのクラス名を見て Django が行う決定は、英語中心でナイーブなフォールバック だからです:

from django.utils.translation import ugettext_lazy

class MyThing(models.Model):
    name = models.CharField(_('name'), help_text=ugettext_lazy('This is the help text'))

    class Meta:
        verbose_name = ugettext_lazy('my thing')
        verbose_name_plural = ugettext_lazy('my things')
モデルメソッドの short_description 属性

モデルメソッドに対して short_description 属性を使って Django と admin サイ トに翻訳を教えることができます:

from django.utils.translation import ugettext_lazy as _

class MyThing(models.Model):
    kind = models.ForeignKey(ThingKind, related_name='kinds',
                             verbose_name=_('kind'))

    def is_mouse(self):
        return self.kind.type == MOUSE_TYPE
    is_mouse.short_description = _('Is it a mouse?')
遅延翻訳オブジェクトの動作

ugettext_lazy() の結果はユニコード文字列 ( unicode 型のオブジェクト) を使う場所ならどこでも使えます。バイト文字列 ( str オブジェクト) が期待さ れる場所で使うとうまく動きません。通常のPythonの動作と密接にむすびいているた め、バイト文字列の中でユニコード文字列を使うこともできません。例えば:

# This is fine: putting a unicode proxy into a unicode string.
u"Hello %s" % ugettext_lazy("people")

# This will not work, since you cannot insert a unicode object
# into a bytestring (nor can you insert our unicode proxy there)
"Hello %s" % ugettext_lazy("people")

"hello<django.utils.functional...>" のように出力されるなら、 そのコードにはバグがあります。ugettext_lazy() の結果をバイト文字列に挿入 しようとしているのでしょう。

長い ugettext_lazy の名前が好きじゃないなら、このように _ (アンダース コア) をエイリアスとして使うことができます:

from django.utils.translation import ugettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(help_text=_('This is the help text'))

ugettext_lazy()ungettext_lazy() をモデルやユーティリティ関数の中 の文字列をマークするのに使うことは、一般的な操作です。コードの中でこれらのオ ブジェクトを使う時は、偶然に文字列に変換されてしまわないか確認するべきです。 できるだけ遅く変換されるべきだからです。これは次に説明するヘルパー関数の使用 を伴います。

文字列の連結: string_concat()

Python標準の文字列連結 (''.join([...])) は遅延翻訳オブジェクトを含むリスト に対してはうまく動きません。代わりに django.utils.translation.string_concat() を使ってください。この関数はそ の内容を連結した遅延オブジェクトを生成し、さらに 結果が文字列の中に入れられた 時にのみそれらを文字列に変換します。例えば:

from django.utils.translation import string_concat
...
name = ugettext_lazy(u'John Lennon')
instrument = ugettext_lazy(u'guitar')
result = string_concat(name, ': ', instrument)

この場合、 result に入る遅延翻訳は result 自体が文字列の中で使われた 時 (通常はテンプレートのレンダリング時) にだけ文字列変換されます。

言語のローカル名
get_language_info()
リリースノートを参照してください

get_language_info() 関数は言語についての詳細な情報を返します:

>>> from django.utils.translation import get_language_info
>>> li = get_language_info('de')
>>> print li['name'], li['name_local'], li['bidi']
German Deutsch False

辞書の name および name_local 属性は、それぞれ、英語での言語名と、その 言語自体での言語名を含みます。 bidi 属性は両方向 (bi-directional) な言語の 時だけ True になります。

言語情報のソースは django.conf.locale モジュールです。この情報へのアクセス はテンプレートコードからも可能です。下記を参照してください。

テンプレート内での翻訳

Django テンプレート 中の翻訳は、二つのテンプレー トタグを使ってPython コードとは少し違った方法で行います。テンプレートで翻訳 用のタグを使えるようにするには、テンプレートの上の方に {% load i18n %} を入れておきます。

テンプレートタグ {%  trans %}

テンプレートタグ {% trans %} は定数の文字列 (シングルクオートまたはダブ ルクオートで囲まれた文字列) や変数を翻訳します:

<title>{% trans "This is the title." %}</title>
<title>{% trans myvar %}</title>

noop オプションを指定すると、値の参照は行われますが、翻訳はしません。 noop は、将来翻訳が必要なコンテンツを「スタブ」するのに便利です:

<title>{% trans "myvar" noop %}</title>

内部的には、インラインの翻訳は ugettext() を呼び出します。

{% trans %} の中では定数文字列とテンプレート変数を同時に扱えません。翻 訳中で変数 (プレースホルダ) を使いたい場合には、{% blocktrans %} を使 います。

リリースノートを参照してください

表示せずに翻訳文字列を検索したい場合、次の文法を使ってください:

{% trans "This is the title" as the_title %}

<title>{{ the_title }}</title>
<meta name="description" content="{{ the_title }}">

実用上は、複数の場所で使われたり、他のテンプレートタグやフィルタで使われる 文字列を得るために使うことができます:

{% trans "starting point" as start %}
{% trans "end point" as end %}
{% trans "La Grande Boucle" as race %}

<h1>
  <a href="/" title="{% blocktrans %}Back to '{{ race }}' homepage{% endblocktrans %}">{{ race }}</a>
</h1>
<p>
{% for stage in tour_stages %}
    {% cycle start end %}: {{ stage }}{% if forloop.counter|divisibleby:2 %}<br />{% else %}, {% endif %}
{% endfor %}
</p>
リリースノートを参照してください

{% trans %}context キーワードを使って コンテキストマーカー もサポートします:

{% trans "May" context "month name" %}
blocktrans テンプレートタグ
キーワード引数フォーマットが新しくなりました。

trans タグと反対に、 blocktrans タグはプレースホルダを使用する ことによってリテラルと変数を含む複雑な文章を扱えます:

{% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %}

オブジェクト属性へのアクセスや、テンプレートフィルタの使用などのテンプレート式 を翻訳するには、翻訳ブロックの中でその表現をローカル変数にバインドする必要があ ります。例:

{% blocktrans with amount=article.price %}
That will cost $ {{ amount }}.
{% endblocktrans %}

{% blocktrans with myvar=value|filter %}
This will have {{ myvar }} inside.
{% endblocktrans %}

一つの blocktrans タグの中で複数の表現を使うことができます:

{% blocktrans with book_t=book|title author_t=author|title %}
This is {{ book_t }} by {{ author_t }}
{% endblocktrans %}

Note

以前のもっと冗長なフォーマットもまだサポートされています: {% blocktrans with book|title as book_t and author|title as author_t %}

リリースノートを参照してください

プロック引数のどれかが解決に失敗した場合、 blocktrans は deactivate_all() を使って一時的に現在 有効な言語を無効化し、デフォルト言語にフォールバックします。

このタグは複数形も扱えます:

  • count という名前でカウンタの値を定義し、バインドします。この値は 適切な複数形の形式を選択するために使われます。
  • {% blocktrans %}{% endblocktrans %} タグの中で、単数形と 複数形の両方の形式を {% plural %} タグで区切って指定します。

例:

{% blocktrans count counter=list|length %}
There is only one {{ name }} object.
{% plural %}
There are {{ counter }} {{ name }} objects.
{% endblocktrans %}

もう少し複雑な例:

{% blocktrans with amount=article.price count years=i.length %}
That will cost $ {{ amount }} per year.
{% plural %}
That will cost $ {{ amount }} per {{ years }} years.
{% endblocktrans %}

カウンタ値に加えて、複数形とローカル変数への値バインドを両方使いたいなら、 blocktrans は内部的に ungettext の呼び出しに変換されるということを心に 留めてください。これは notes regarding ungettext variables の適用と同じことを意味します。

リバース URL 参照は blocktrans の中で実行することはできないので、前もって検 索されて (保存されて) おかなければなりません:

{% url path.to.view arg arg2 as the_url %}
{% blocktrans %}
This is a URL: {{ the_url }}
{% endblocktrans %}
リリースノートを参照してください

{% blocktrans %}context キーワードを使った コンテキストマーカー もサポートします:

{% blocktrans with name=user.username context "greeting" %}Hi {{ name }}{% endblocktrans %}
その他のタグ

Requestcontext は 3 つの翻訳処理用の変数にアクセスします:

  • LANGUAGES はタプルのリストです。最初の要素は language code で、二番目は (現在アクティブなロケール に翻訳された) 言語名です。
  • LANGUAGE_CODE は現在のユーザ設定言語で、文字列です。例: en-us (後述の “言語設定の検出メカニズム” を参照してください)。
  • LANGUAGE_BIDI は現在の言語の表記方向 (direction) です。 True ならば、ヘブライ語やアラビア語のように右から左に記述する言語を示し、 False なら英語、フランス語、ドイツ語のように左から右に記述する言 語を指します。

RequestContext 拡張を使わなければ、以下の 3 つのタグを使って値を取得でき ます:

{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_current_language_bidi as LANGUAGE_BIDI %}

これらのタグを使うには {% load i18n %} が必要です。

翻訳フックは定数文字列を使うテンプレートブロック全てでも利用できます。 _() 構文を使って翻訳文字列を指定してください。例えば:

{% some_special_tag _("Page not found") value|yesno:_("yes,no") %}

このばあい、タグとフィルタの両方は翻訳済みの文字列を扱うことになるので、翻 訳の有無について気を配る必要がなくなります。

Note

上の例では、翻訳インフラストラクチャには文字列 "yes,no" が渡されま す。 "yes""no" の別々の文字列が渡されるわけではありません。 フィルタが引数の文字列を正しく分割できるように、翻訳済みの文字列にはカ ンマが入っていなければなりません。例えば、ドイツ語の翻訳は、 (カンマを そのまま残して) "yes,no""ja,nein" に翻訳せねばなりません。

リリースノートを参照してください

提供されるテンプレートタグとフィルタを使って利用可能な言語のいずれかについ ての情報を検索することもできます。単一の言語の情報を得るには {% get_language_info %} タグを使います:

{% get_language_info for LANGUAGE_CODE as lang %}
{% get_language_info for "pl" as lang %}

そのあとで情報にアクセスできます:

Language code: {{ lang.code }}<br />
Name of language: {{ lang.name_local }}<br />
Name in English: {{ lang.name }}<br />
Bi-directional: {{ lang.bidi }}

言語のリストについての情報を検索するなら {% get_language_info_list %} テンプレートタグも使えます。 (例えば :LANGUAGE で指定されたアク ティブな言語についてなど) {% get_language_info_list %} を使った言語セ レクタを表示する例を見たいなら、 set_language リダイレクトビューにつ いてのセクション を参照してください。

LANGUAGES のネストしたタプル形式に加えて、 {% get_language_info_list %} は言語コードの単純なリストもサポートして います。ビューの中で使うなら:

return render_to_response('mytemplate.html', {
    'available_languages': ['en', 'es', 'fr'],
}, RequestContext(request))

テンプレートの中でこれらの言語をイテレートできます:

{% get_language_info_list for available_languages as langs %}
{% for lang in langs %} ... {% endfor %}

簡単にするため、シンプルなフィルタもあります:

  • {{ LANGUAGE_CODE|language_name }} (“German”)
  • {{ LANGUAGE_CODE|language_name_local }} (“Deutsch”)
  • {{ LANGUAGE_CODE|bidi }} (False)
JavaScript コードでの国際化

JavaScript に翻訳を追加しようとすると、いくつかの問題に直面します:

  • JavaScript コードには gettext 実装へのアクセス手段がありません。
  • JavaScript コードには .po や .mo ファイルへのアクセス手段がありません。 というのも、これらのファイルはサーバに置かれているからです。
  • JavaScript の翻訳カタログはできるだけ小さくしておかねばなりません。

Django では、これらの問題に対する解決策を組み込みで提供しています。この解決 策は翻訳を JavaScript に渡して、 gettext などを JavaScript コード内で呼 び出せるようにします。

javascript_catalog ビュー
javascript_catalog(request, domain='djangojs', packages=None)

前述の問題に対する解決策は、 django.views.i18n.javascript_catalog`() ビューにあります。このビューは gettext インタフェースをまねた関数の入っ た JavaScript コードと、翻訳文字列のアレイを送信します。翻訳文字列のアレイは info_dict や URLの指定に従ってアプリケーションやプロジェクト、Django コ ア部分から取り出されます。 LOCALE_PATHS のパスリストも含まれます。

例えば以下のようにフックをかけたとしましょう:

js_info_dict = {
    'packages': ('your.app.package',),
}

urlpatterns = patterns('',
    (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
)

packages のタプルに入っている各文字列は Python のドット区切りのパッケー ジ表記 (INSTALLED_APPS で使われている書式と同じ) で、 locale ディレ クトリの入っているパッケージにします。複数のパッケージを指定した場合、全て のカタログが一つのカタログに統合されます。この仕様は、複数のアプリケーショ ンの文字列を扱うような JavaScript で便利です。

翻訳の優先度は、 packages 引数で後に現れるパッケージが、最初に現れるもの よりも高くなります。同じリテラルで翻訳が壊れる場合、このことが情報です。

このビューはデフォルトでは djangojs gettext ドメインを使います。代わりの domain 引数によって変更できます。

URL パターンにパッケージ名を入れておけば、ビューを動的にできます:

urlpatterns = patterns('',
    (r'^jsi18n/(?P<packages>\S+?)/$', 'django.views.i18n.javascript_catalog'),
)

こうしておいて、パッケージ名を ‘+’ で区切ったパッケージ名リストとして指定で きます。これは、複数のアプリケーションからのコードを使っていて、変更が頻繁 に起きている場合、巨大なカタログファイルを毎回プルしなくてすむので便利です。 セキュリティ上の理由から、パッケージ名リストに指定できるのは、 django.confINSTALLED_APPS 設定に入っているアプリケーションだけ です。

LOCALE_PATHS 設定のパスリストで見つけられる JavaScript 翻訳は常に 含められます。 Python とテンプレートで使われる翻訳の検索順序アルゴリズムの一 貫性を保つため、 LOCALE_PATHS のディレクトリリストは、最初に現れ るものとともに、最も高い優先度を持ちます。

LOCALE_PATHS のディレクトリリストはバージョン 1.3 までは 検索アルゴリズムに含まれていませんでした。
JavaScript 翻訳カタログを使う

カタログを使うには、単に以下のようにして動的に生成されたスクリプトをプルし ます:

.. code-block:: html+django
<script type=”text/javascript” src=”{% url django.views.i18n.javascript_catalog %}”></script>

このコードはJavaScript カタログビューのURLを探すために、リバース URL 参照を使っ ています。カタログをロードしたら、JavaScript から標準的な gettext インタフ ェースを使ってアクセスできるようになります:

document.write(gettext('this is to be translated'));

ngettext インタフェースもあります:

var object_cnt = 1 // or 0, or 2, or 3, ...
s = ngettext('literal for the singular case',
        'literal for the plural case', object_cnt);

文字列補完を行う関数もあります:

function interpolate(fmt, obj, named);

補完の構文は Python から借りたもので、固定引数と名前つきの文字列補完をサポー トしています:

  • 固定引数型の補完: obj には JavaScript の Array オブジェクトが入り ます。 interpolate は Array の各要素を使って、 fmt 内のプレー スホルダを順番に置換してゆきます。例えば:

    fmts = ngettext('There is %s object. Remaining: %s',
            'There are %s objects. Remaining: %s', 11);
    s = interpolate(fmts, [11, 20]);
    // s is 'There are 11 objects. Remaining: 20'
    
  • 名前つき補完: このモードは、オプションの named パラメタに true を指定して選択します。 obj には JavaScript のオブジェク トか、連想配列が入ります。例えば:

    d = {
        count: 10,
        total: 50
    };
    
    fmts = ngettext('Total: %(total)s, there is %(count)s object',
    'there are %(count)s of a total of %(total)s objects', d.count);
    s = interpolate(fmts, d, true);
    

とはいえ、この文字列補完を派手に使わない方がよいでしょう: 補完機能は JavaScript で動いており、中では何度も正規表現置換を行っています。この処理は Python の文字列補完ほど高速ではないので、本当に必要な場合 (例えば ngettext を使って適切な複数形表現を実現したい場合) だけにしてください。

URL パターンでの国際化
リリースノートを参照してください

Django は URL パターンでの国際化のために 2 つのメカニズムを提供しています:

  • LocaleMiddleware がリクエスト URL からアク アクティブな言語を判別できるように、 ルート URL パターンに言語プレフィックス をつけます。
  • URL パターン自体を django.utils.translation.ugettext_lazy() 関数を通 して翻訳できるようにします。

Warning

これらの機能のいずれかを使うには、各々のリクエストに対してアクティブな言語 がセットされる必要があります。言い換えると MIDDLEWARE_CLASSES 設定に django.middleware.locale.LocaleMiddleware を含める必要があります。

URL パターンの言語プレフィックス
i18n_patterns(prefix, pattern_description, ...)

この関数はルート URLconf で、通常の django.conf.urls.patterns() 関数の代わりに使うことができます。Django は i18n_patterns() で定義された全ての URL バターンの 先頭に自動で現在アクティブな言語コードを挿入します。例の URL パターン:

from django.conf.urls import patterns, include, url
from django.conf.urls.i18n import i18n_patterns

urlpatterns = patterns(''
    url(r'^sitemap\.xml$', 'sitemap.view', name='sitemap_xml'),
)

news_patterns = patterns(''
    url(r'^$', 'news.views.index', name='index'),
    url(r'^category/(?P<slug>[\w-]+)/$', 'news.views.category', name='category'),
    url(r'^(?P<slug>[\w-]+)/$', 'news.views.details', name='detail'),
)

urlpatterns += i18n_patterns('',
    url(r'^about/$', 'about.view', name='about'),
    url(r'^news/$', include(news_patterns, namespace='news')),
)

このように URL バターンが定義されたら、 Django は URL パターンに対して i18n_patterns 関数により言語プレフィックスを追加します。

from django.core.urlresolvers import reverse from django.utils.translation import activate

>>> activate('en')
>>> reverse('sitemap_xml')
'/sitemap.xml'
>>> reverse('news:index')
'/en/news/'
>>> activate('nl')
>>> reverse('news:detail', kwargs={'slug': 'news-slug'})
'/nl/news/news-slug/'

Warning

i18n_patterns() はルートの URLconf でしか使え ません。インクルードされた URLconf の中で使うと、 ImproperlyConfigured 例外を送出します。

Warning

自動で追加された言語プレフィックスと衝突しないように、プレフィックスのない URL パターンがないことを確認してください。

URL パターンを翻訳する

URL パターンは ugettext_lazy() 関数を使って翻訳 可能としてマークすることができます。例えば:

from django.conf.urls import patterns, include, url
from django.conf.urls.i18n import i18n_patterns
from django.utils.translation import ugettext_lazy as _

urlpatterns = patterns(''
    url(r'^sitemap\.xml$', 'sitemap.view', name='sitemap_xml'),
)

news_patterns = patterns(''
    url(r'^$', 'news.views.index', name='index'),
    url(_(r'^category/(?P<slug>[\w-]+)/$'), 'news.views.category', name='category'),
    url(r'^(?P<slug>[\w-]+)/$', 'news.views.details', name='detail'),
)

urlpatterns += i18n_patterns('',
    url(_(r'^about/$'), 'about.view', name='about'),
    url(_(r'^news/$'), include(news_patterns, namespace='news')),
)

翻訳を作成した後には reverse() 関数はアクティブ な言語でのURLを返します。例えば:

from django.core.urlresolvers import reverse
from django.utils.translation import activate

>>> activate('en')
>>> reverse('news:category', kwargs={'slug': 'recent'})
'/en/news/category/recent/'

>>> activate('nl')
>>> reverse('news:category', kwargs={'slug': 'recent'})
'/nl/nieuws/categorie/recent/'

Warning

ほとんどの場合、 URL の翻訳は ( i18n_patterns() を使った) 言語コードプレフィッ クスの箇所でのみ使うのがベストです。不注意な URL の翻訳が、翻訳されない URL との衝突を起こすことを避けるためです。

テンプレートでのリバース参照

ローカライズされた URL がテンプレート中でリバース参照される場合、常に現在の言語 が使われます。他の言語の URL にリンクするには、 language テンプレートタグを 使ってください。これはタグに囲まれたセクションで与えられた言語を有効にします:

{% load i18n %}

{% get_available_languages as languages %}

{% trans "View this category in:" %}
{% for lang_code, lang_name in languages %}
    {% language lang_code %}
    <a href="{% url category slug=category.slug %}">{{ lang_name }}</a>
    {% endlanguage %}
{% endfor %}

language タグは引数に言語コードだけが渡されることを期待します。

ローカライズ: 言語ファイルの作成方法

文字列に翻訳用のタグをつけたら、今度は翻訳文自体を書く (または手に入れる) 必要があります。ここでは翻訳文を書く方法について示します。

ロケールの制約

Django は、 Django 本体に対する翻訳カタログのない言語への地域化をサポー トしていません。ある言語向けの自作のカタログを提供しても、 Django 本体 にその言語のサポートがなければ、カタログは無視されます。自作のアプリケー ションに特定の言語のロケールをサポートさせたいのなら、まずは Django の コア部分に対する最小限の翻訳カタログを作成する必要があるでしょう。また、 その場合、翻訳されたメッセージ (自作のアプリケーション内のカタログ) と 英語のメッセージ (Django 自体の不完全なカタログ) が入り混じった表示になっ てしまうでしょう。

Django の英語 .po ファイルをコピーし、少なくともいくつかの 翻訳 文字列 を翻訳することから始めると良いでしょう。

メッセージファイル

最初のステップは、新たに追加する言語用の メッセージファイル の作成です。 メッセージファイルは平文テキストファイルで、言語ごとに作成され、翻訳文字列 全てと、言語ごとの対応する表現が収められています。メッセージファイルの拡張 子は .po です。

Django には django-admin.py makemessages というツール が付属しています。このツールはメッセージファイルの作成や維持を自動化します。

Gettext ユーティリティ

makemessages コマンド (および後で議論する compilemessages) は GNU gettext ツールセットのコマンド: xgettext, msgfmt, msgmerge, msguniq を使います。

リリースノートを参照してください

対応している gettext の最低バージョンは 0.15 です。

メッセージファイルの作成や更新を行うには、以下のようにコマンドを実行します:

django-admin.py makemessages -l de

ここで、 de は作成したいメッセージファイルの言語コードです。言語コードは ロケール表示の形式 にします。例えば、ブラジル系ポルトガル 語の場合には pt_BR で、オーストリアドイツは de_AT です。

スクリプトは以下の 2 種類の場所のいずれかで実行します:

  • Django プロジェクトのルートディレクトリ。
  • Django アプリケーションのルートディレクトリ。

スクリプトはプロジェクトのソースツリーやアプリケーションのソースツリーを走 査して、翻訳用にマークされた全ての文字列を取り出します。スクリプトは /locale/LANG/LC_MESSAGES 下にメッセージファイルを作成 (もしくは更新) し ます。 de の例では、ファイルは /locale/de/LC_MESSAGES/django.po で す。

デフォルトの設定では、 django-admin.py makemessages は拡張子 .html.txt のファイルも検索します。デフォルトの設定をオーバライドしたけ れば、 --extension または -e オプションを使って、拡張子を指定してくださ い:

django-admin.py makemessages -l de -e txt

複数の拡張子を扱いたいのなら、カンマで区切るか、 -e--extension を複数回指定します:

django-admin.py makemessages -l de -e html,txt -e xml

Warning

JavaScriptソースコードからメッセージファイルを作成する 場合は、 -e js ではなく 特別な ‘djangojs’ ドメインを使わなければなりません。

gettext がなかったら?

gettext ユーティリティをインストールしていない場合、 makemessages は空のファイルを作成します。その場合、 gettext ユーティリティをインストールするか、英語用の空のメッセージファイル ( locale/en/LC_MESSAGES/django.po) をコピーして使って下さい。

Windows で動かしたいのですが?

Windows を使っていて、 makemessages を動作させるため に GNU gettext ユーティリティをインストールしたいのなら、 Windows で gettext を使う を参照してください。

.po ファイルは素直な形式で書かれています。 .po ファイルには翻訳メン テナのコンタクト情報のようなわずかなメタデータが入っています。それ以外の大 部分は メッセージ のリストです。メッセージは翻訳文字列と特定の言語用の 実際の翻訳テキストです。

例えば、 Django アプリケーションに "Welcome to my site." というテキスト の翻訳文字列が以下のように入っていたとします:

_("Welcome to my site.")

django-admin.py makemessages を実行すると、以下のよう なコード断片を含む .po ファイルを作成するはずです:

#: path/to/python/module.py:23
msgid "Welcome to my site."
msgstr ""

上の内容を簡単に説明しましょう:

  • msgid は翻訳文字列で、ソースコードに書かれていたものです。変更し てはなりません。
  • msgstr には各言語の翻訳を入れます。最初は空になっており、変更する のはユーザの責任です。翻訳文字列の周りにクオートを忘れないように注意 してください。
  • 便宜上、各メッセージには該当する翻訳文字列のあったファイル名と行番号 が msgid 行の上の # ではじまる行に入っています。

長いメッセージは特別なケースとして扱います。 msgstr (または msgid) の直後の文字列が空文字列の場合、コンテンツ自体はその次の複数行にわたって書 かれているものとみなします。これらの文字列は直接結合されるので、文字列の中 間では末尾にスペースを忘れないようにしましょう。さもないと、空白なしで文字 列がくっついてしまいますよ!

文字コードセットに注意

PO ファイルをテキストエディタで作成するときには、文字コードセット の行 ("CHARSET" を探して下さい) をまず編集して、これから編集に使う 文字セットにしてください。 gettext ツールの内部動作の仕組み上、また、 Django のコア部分やアプリケーションで非 ASCII のソース文字列を扱えるよ うにするために、 PO ファイルのエンコーディングは必ず UTF-8 にしてくださ い。つまり全員が同じエンコーディングを使うことになります。これは Django が PO ファイルを処理する時に大切なことです。

全てのソースコードとテンプレートを新たな翻訳文字列でためし、 全ての 言 語用にメッセージファイルを更新するには、以下のようにします:

django-admin.py makemessages -a
メッセージファイルのコンパイル

メッセージファイルを作成して、変更し終えたら gettext を使ってメッセージ ファイルをより効率的な形式にコンパイルします。作業は django-admin.py compilemessages ユーティリティで行 いましょう。

このツールは全ての .po ファイルをコンパイルして .mo ファイルを作成 します。 .mo ファイルはバイナリファイルで、 gettext で使うために最 適化されています。 django-admin.py makemessages を実 行したのと同じディレクトリで、以下のように django-admin.py compilemessages を実行してくだ さい:

django-admin.py compilemessages

これで終わりです。もう翻訳を使えるようになっているはずです。

Windows で動かしたいのですが?

Windows を使っていて、 django-admin.py compilemessages を動作させるた めに GNU gettext ユーティリティをインストールたいのなら、 Windows で gettext を使う を参照してください。

.po ファイルのエンコーディングと BOM

Django は BOM (バイトオーダーマーク) なしで UTF-8 でエンコードされたファイル しか扱えません。使っているテキストエディタがデフォルトでファイルの先頭に BOM を追加する場合、設定を変更してください。

JavaScript のソースコードからメッセージファイルを作成する

JavaScript のメッセージファイルの作成と更新方法は、他の Django の翻訳カタログの 場合と同じで、 django-admin.py makemessages ツールを使います。唯一違 うのは、 gettext の用語でドメインとして知られているもの、この場合は djangojs ドメインを明示的に指定しなければならないことです。このように -d djangojs パ ラメタを指定してください:

django-admin.py makemessages -d djangojs -l de

上の例では、ドイツ語向けの JavaScript のメッセージファイルを作成または更新して います。翻訳カタログを更新したら、通常の Django メッセージファイルと同じように、 django-admin.py compilemessages を実行してください。

Windows で gettext を使う

この節の操作が必要なのは、 メッセージ ID を抜き出したり、メッセージファイル を (.po に) コンパイルしたいときだけです。翻訳の作業自体はファイルを編 集するだけですが、メッセージファイルを自分で作成したい場合や、変更したメッ セージファイルをテストしたりコンパイルしたい場合には、以下のようにして gettext ユーティリティを入れる必要があります:

  • 以下の ZIP ファイルを GNOME のサーバ、 http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ミラーサイト からダウンロードします。

    • gettext-runtime-X.zip
    • gettext-tools-X.zip

    X はバージョン番号で、 0.15 以上が必要です。

  • 両方のファイルの bin\ ディレクトリの中身をどこかのフォルダに展開します ( 仮に C:\Program Files\gettext-utils とします)

  • システム環境変数の PATH を変更します:

    • コントロールパネル > システム > 高度な設定 > 環境変数 の順に辿 ります。
    • システム環境変数 リストで、 Path を選び、 編集 を押しま す。
    • 変数値 フィールドの値の末尾に ;C:\Program Files\gettext-utils\bin を追加します。

xgettext --version コマンドの結果が 0.15 以上なら、別の場所で入手した gettext バイナリを使ってもかまいません。 もし Windows のコマンドプロンプト で xgettext --version を入力した時に “xgettext.exe でエラーが発生しました。” といったポップアップウィンドウが表示されるなら、Django の翻訳ユーティリティに その gettext パッケージを使わないようにしてください。

雑多な情報
set_language リダイレクトビュー
set_language(request)

Django は便利な django.views.i18n.set_language() ビューを提供しています。 これはユーザの言語を設定し、与えられた URL かデフォルトでは 直前のページに戻る ビューです。

URLconf に次の行を足すとこのビューを有効にできます:

(r'^i18n/', include('django.conf.urls.i18n')),

(この例は /i18n/setlang/ にビューを作っています。)

このビューは language パラメータつきで POST メソッドのリクエストによっ て呼ばれることを想定しています。セッションサポートが有効になっていると選択され た言語がユーザのセッションに保存されます。無効の場合は、 django_language という名前のクッキーに言語設定を保存します。 (この名前は LANGUAGE_COOKIE_NAME 設定で変更できます。)

選ばれた言語を設定したら、 Django はユーザを以下のアルゴリズムでリダイレクトし ます:

  • Django は POST データの next パラメータを探します。
  • なかったり空の場合、 Django は Referrer ヘッダの URL を使おうとします。
  • これも空なら、つまりユーザのブラウザが Referrer ヘッダを抑制している場合 ユーザは / (サイトのルート) にリダイレクトされます。

次に示すのは簡単な HTML テンプレートコードです:

<form action="/i18n/setlang/" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}">{{ language.name_local }} ({{ language.code }})</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>

この例では Django は redirect_to コンテキスト変数からユーザがリダイレクトさ れるページの URL を見つけます。

ビューやテンプレートの外で翻訳を使う

Django はビューとテンプレートで使うために豊富な国際化ツールセットを提供していま す。 Django 専用のコード以外でもこれを使うことはできます。 Django の翻訳メカニ ズムは任意のテキストを Django がサポートする言語に翻訳するために使うことができ ます (もちろん適切な翻訳カタログがあればですが) 。翻訳カタログをロードし、アク ティベートして、選択した言語にテキストを翻訳することができますが、元の言語に戻 すのを忘れないでください。翻訳カタログのアクティベートはスレッド単位で行われ、 同じスレッドで動くコードに影響するからです。

例えば:

from django.utils import translation
def welcome_translated(language):
    cur_language = translation.get_language()
    try:
        translation.activate(language)
        text = translation.ugettext('welcome')
    finally:
        translation.activate(cur_language)
    return text

‘de’ という値を渡してこの関数を呼ぶと LANGUAGE_CODE やミドルウェアに よる言語設定に関わらず "Willkommen" が返されます。

特別な目的のための関数として django.utils.translation.get_language() は、 現在のスレッドで使われている言語を返します。 django.utils.translation.activate() は現在のスレッドで翻訳カタログをアクテ ィベートします。 django.utils.translation.check_for_language() は指定された 言語 が Django でサポートされているかを調べます。

実装に関する注意点
Django 翻訳の特徴

Django の翻訳機構は Python 標準の gettext モジュールを使います。 gettext について詳しければ、 Django の翻訳機能には以下のような特徴があることに気づくで しょう:

  • 文字列ドメイン (string domain) は django または djangojs です。文字列 ドメインは別のプログラムが共通のメッセージファイルライブラリにデータを保存す る時に区別するために使われます。 django ドメインは Python とテンプレート の翻訳文字列に使われ、グローバルの翻訳カタログにロードされます。 djangojs ドメインは JavaScript の翻訳カタログができるだけ小さくなるように、それだけの ために使われます。
  • Django は xgettext を単体では使いません。 xgettextmsgfmt を Python ラッパを通して使います。これは主に利便性のためです。
言語設定の検出メカニズム

翻訳の準備を完了した、あるいは Django 付属の翻訳を使いたいだけなら、あとは アプリケーションで翻訳を有効にするだけです。

背後では、 Django はユーザの使用言語を決めるモデルを備えています。このモデ ルは柔軟で、インストール全体、あるいは特定のユーザ、またはその両方に対して 使用言語を決定できます。

インストール全体での使用言語を設定するには、 LANGUAGE_CODE を設 定します。 Django はこの設定をデフォルトの翻訳言語、すなわち他の適切な翻訳が ない場合に試みる言語に設定します。

Django をネイティブの言語で動かしたいだけで、かつ自分の言語に対する言語ファ イルをすでに準備しているのなら、 LANGUAGE_CODE を設定するだけで済みます。

個々のユーザが自分の使いたい言語を選択できるようにするには LocaleMiddleware を使ってください。 LocaleMiddleware は、リクエスト に埋め込まれたデータに基づいた言語の選択を可能にし、ユーザごとにコンテンツ をカスタマイズします。

LocaleMiddleware を使うには、 MIDDLEWARE_CLASSES 設定に 'django.middleware.locale.LocaleMiddleware' を追加します。ミドルウェア の順番は重要で、以下のガイドラインに従って下さい:

  • まず、インストール済みのミドルウェアの先頭にくるようにしてください。
  • LocaleMiddleware はセッションを使うので、 SessionMiddleware の後ろに配置してください。 また、CommonMiddleware より前にしてください。 CommonMiddleware はリクエスト URL を解決するためアクティブな言語を必要と します。
  • CacheMiddleware を使っているなら、その後ろに LocaleMiddleware を配置してください。

例えば、 MIDDLEWARE_CLASSES は以下のようになります:

MIDDLEWARE_CLASSES = (
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.middleware.locale.LocaleMiddleware',
   'django.middleware.common.CommonMiddleware',
)

(For more on middleware, see the middleware documentation.)

(ミドルウェアの詳細は ミドルウェアのドキュメント を参照してください。)

LocaleMiddleware はユーザの言語設定を以下のようなアルゴリズムで決定しよ うと試みます:

リリースノートを参照してください
  • はじめに、リクエストされた URL に言語プレフィックスを探します。これはルート URLconf で i18n_patterns 関数を使った場合だけ行われます。 言語プレフィックスと URL パターンの国際化については URL パターンでの国際化 がもっと詳しいです。

  • 見つからなければ、現在のユーザのセッションに django_language キーがない か探します。

  • なければ、クッキーを探します。

    クッキーの名前は LANGUAGE_COOKIE_NAME 設定の値がセットされます。 (デフォルトの名前は django_language です。)

  • うまく行かなければ、 Accept-Language HTTP ヘッダを見ます。このヘッダは ブラウザから送られ、ユーザの望む言語を優先度順に伝えます。 Django は利用可能 な翻訳が見つかるまで、渡された全ての言語を調べます。

  • それも失敗したら、グローバルな LANGUAGE_CODE 設定を使います。

注意:

  • 上記のどのステップでも、言語設定は標準の言語名表記法に従った文字列で 書かれているものと想定しています。例えば、ブラジル系ポルトガル語は pt-br です。

  • 基本言語 (base language) が指定されていて、副言語 (sublanguage) が指 定されていない場合、 Django は基本言語の設定を優先します。例えば、ユー ザが de-at (オーストリアドイツ語) を指定しているのに対して、 Django 側には de のしかない場合、 Django は de を使います。

  • LANGUAGES 設定にリストアップした言語しか選択できません。 (全ての言語に対する翻訳を提供できないなどの理由で) 言語選択を指定の言 語のサブセットに制限したい場合には、 LANGUAGES を設定します。例え ば:

    LANGUAGES = (
      ('de', _('German')),
      ('en', _('English')),
    )
    

    この例では、自動生成されるメニューで利用可能な言語をドイツ語:de と 英語:en (および de-ch や en-us のような副言語) に制限しています。

  • 上の項で説明したように、カスタムの LANGUAGES 設定を行った場合、そ の言語を翻訳対象文字列に含めても構いません。ただし、 django.utils.translationugettext() ではなく、「ダミーの」 ugettext() でマークしてください。循環 import を防ぐため、 決して 設定ファイル中で django.utils.translation を import しないでくだ さい。

    カスタム LANGUAGES のマークアップは「ダミーの」 ugettext() 関 数で解決します。以下に設定ファイルでの記述例を示します:

    ugettext = lambda s: s
    
    LANGUAGES = (
        ('de', ugettext('German')),
        ('en', ugettext('English')),
    )
    

    このように設定しておいても、 django-admin.py makemessages は翻訳 文字列を検出して翻訳対象としてマークします。ただし、実行時の翻訳はお こなわれません。したがって、実行時には LANGUAGES を使うコードを 本当の ugettext() でラップしておかねばなりません。

  • LocaleMiddleware で選択できるのは、 Django が基本的な部分の翻訳を 提供している言語だけです。 Django のソースツリーの翻訳セットに入って いない言語の翻訳を提供したければ、 ロケールの制約 に説明されているように まずその言語むけの基本部分の翻訳を提供する必要があります。

LocaleMiddleware がユーザ設定を検出すると、その設定に HttpRequestrequest.LANGUAGE_CODE でアクセスで きます。この値はビューコードで自由に読みだしてかまいません。以下に一例を挙 げます:

def hello_world(request, count):
    if request.LANGUAGE_CODE == 'de-at':
        return HttpResponse("You prefer to read Austrian German.")
    else:
        return HttpResponse("You prefer to read another language.")

静的な (ミドルウェアを使わない) 翻訳では、言語設定は settings.LANGUAGE_CODE の値になり、動的な (ミドルウェアを使った) 翻訳で は、言語設定は request.LANGUAGE_CODE の値になるので注意してください。

Django が翻訳を探す方法

実行時に、 Django はメモリ上に統合されたリテラル - 翻訳のカタログを作ります。 これを実現するために、次に示すアルゴリズムによって翻訳を探します。このアルゴリ ズムは、コンパイルされた メッセージファイル (.mo) を ロードするために複数のファイルパスを調べ、同じリテラルに対して複数の翻訳がある 時の優先度を調べます:

  1. LOCALE_PATHS で設定されたディレクトリのリストが最も優先されます。 このなかでは前に書かれたものが後のものより優先されます。
  2. 次に INSTALLED_APPS に列挙されたアプリケーションに local ディ レクトリがあれば、それを見つけて使います。後のものより先に書かれたものが優先 されます。
  3. 次に、プロジェクトディレクトリ、もっと正確に言うと設定ファイルがあるディレク トリで locale ディレクトリを探します。
  4. 最後に、フォールバックとして Django が提供する基本の djang/conf/locale を使います。

Deprecated since version 1.3: 設定ファイルがあるディレクトリから locale サブディレクトリを探す方法 ( 上の 3) は 1.3 から非推奨になっていて、 Django 1.5 では廃止されます。 代わりに LOCALE_PATHS 設定に locale のようなディレクトリの絶 対ファイルパスを書いてください。

See also

JavaScript ファイルに含まれるリテラルの翻訳文字列は、同様な、しかし特別に用 意されたアルゴリズムによって探します。 詳しくは javascript_catalog ビューのドキュメント を 参照してください。

どの場合でも翻訳を含むディレクトリの名前は de, pt_BR, es_AR といっ た ロケール名 表記にしなければなりません。

こうすることで、独自の翻訳の入ったアプリケーションを書いたり、基本の翻訳の 内容をプロジェクトパスに置いた翻訳でオーバライドしたりできます。また、複数 の小さなアプリケーションで大きめのプロジェクトを構築するときに、全ての翻訳 を一つのプロジェクト単位のメッセージファイルにまとめておけます。どういう方 法をとるかはユーザ次第です。

Note

DJANGO_SETTINGS_MODULE を使わない設定方法 に示したように、 DJANGO_SETTINGS_MODULE を使わずに手動で設定を行った場合、プ ロジェクトディレクトリ内の locale ディレクトリはチェックされません。 これは Django がプロジェクトディレクトリの場所を調べる術を持たないから です (Django は通常、設定ファイルのある場所を基準に locale ディレク トリの場所を調べますが、手動で設定を行うと設定ファイルが存在しなくなっ てしまうからです)。

メッセージファイルリポジトリも同じような構成になっています:

  • 設定ファイルの LOCALE_PATHS に書かれた全てのパスから <language>/LC_MESSAGES/django.(po|mo) を探します。
  • $PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo) を探します。上記のように非推奨です。
  • $APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
  • $PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)

メッセージファイルの作成には django-admin.py makemessages を使ってください。 locale/ ディレクトリがあるディレクトリで行わねばなりません。 また、 gettext が使うバイナリ形式の .mo ファイルを作成するには django-admin.py compilemessages を使います。

django-admin.py compilemessages --settings=path.to.settings を実行すれ ば、コンパイラに LOCALE_PATHS に設定された全てのディレクトリを処理させ られます。

最後に、翻訳ファイルをどのように構成するかしっかりと考えておくように勧めま す。自分の作ったアプリケーションを他のユーザに配ったり、他のプロジェクトで 利用したりするなら、アプリケーション固有の翻訳が必要になるでしょう。しかし、 アプリケーション固有のメッセージやプロジェクトごとの翻訳は makemessages にまつわる困った問題を引き起こすことがあります: makemessages は現在のパス以下の全てのディレクトリを検索してしまうので、 すでにアプリケーションメッセージファイルに入っているメッセージ ID が、プロ ジェクトのメッセージファイルに入ってしまうことがあるのです。

この問題の最も簡単な解決法は、プロジェクトを直接的に構築しない (なおかつ独 自の翻訳を備えている) アプリケーションをプロジェクトツリーの外に配置してお くというものです。こうすれば、プロジェクトレベルで django-admin.py make-messages を実行しても、自分 のプロジェクトに明に関係する部分の文字列だけを翻訳し、別個に配布されたアプ リケーションの文字列を対象にしなくなります。

書式ローカライズ

リリースノートを参照してください
概要

Django の書式設定システムでは、使用中の ロケール 向けの 書式を使って、日時や数字をテンプレートに表示することができます。 また、フォームでのローカライズされた入力を扱うこともできます。

そうすることで、同じコンテンツにアクセスしている二人のユーザーが、それぞれの ロケール設定に依存した書式で日時や数字を見ることになります。

この書式設定システムはデフォルトでは無効となっています。有効とするには、ファ イル設定で USE_L10N = True と設定する必要があります。

Note

django-admin.py startproject によって生成され るデフォルトの settings.py ファイルは、利便性のため USE_L10N = True を含むものとなっています。

Note

別の、しかし関連する設定 USE_I18N は、Djangoが翻訳を有効化す べきかの制御を行います。詳細については、 翻訳 を参照してください。

ロケールを考慮したフォームの入力

書式設定が有効となったら、 Django は、ローカライズ書式を、日時や数字をフォー ムにおいて解析する場合に使うことができます。つまり、ユーザがフォームに入力す る際に使った書式を推測しながら、異なるロケールの異なる書式を試すということで す。

Note

Django はデータ解析のために使う書式とは違う書式を、データを表示する際 に使います。とりわけ、データ解析のための書式では、 %a (省略された 曜日名) や %A (省略されない曜日名) %b (省略された月の名前) %B (省略されない月の名前) %p (AM/PM) を使うことはできません。

フォームフィールドがデータの入出力をローカライズできるようにするには、 localize 引数を使うだけです:

class CashRegisterForm(forms.Form):
   product = forms.CharField()
   revenue = forms.DecimalField(max_digits=4, decimal_places=2, localize=True)
テンプレートでのローカライズ制御

USE_L10N によって書式設定を有効化すると、 Django はテンプ レートへの出力値が何であろうと、ロケール向けの書式を使おうとします。

しかしながら、ローカライズされた値を使うことはいつも正しいとはかぎり ません。たとえば、機械解読可能なように設計された Javascript あるいは XML で出力している場合、値がつねにローカライズされることは望ましくな いでしょう。また、全ての箇所でローカライズするより、選択したテンプレ ート内でそうしたいと思うかもしれません。

ローカライズの細かな制御のためには、 Django は、以下のタグやフィルタ を含む l10n のテンプレートライブラリを用意しています。

テンプレートタグ
localize
リリースノートを参照してください

ブロック内のテンプレート変数のローカライズを有効または無効にします。

このタグにより USE_L10N よりも細かいローカライズの粒度制御が可能 となります。

テンプレートブロックへのローカライズを有効化、または無効化するためにはこのよ うにします:

{% load l10n %}

{% localize on %}
    {{ value }}
{% endlocalize %}

{% localize off %}
    {{ value }}
{% endlocalize %}

Note

{% localize %} ブロックの内部では USE_L10N の値は 考慮されません。

変数ごとに同じ働きをするテンプレートフィルタについては localizeunlocalize を参照してください。

テンプレートフィルタ
localize
リリースノートを参照してください

単独の値のローカライズを強制します。

例:

{% load l10n %}

{{ value|localize }}

単独の値のローカライズを無効化するためには unlocalize を使います。 テンプレートの大きなセクションのローカライズを制御するには、 localize テンプレートタグを使います。

unlocalize
リリースノートを参照してください

ローカライズ無しで単独の値を出力することを強制します。

例:

{% load l10n %}

{{ value|unlocalize }}

単独の値のローカライズを強制するには、 localize を使います。テンプ レートの大きなセクションのローカライズを制御するには localize テンプ レートタグを使います。

カスタムフォーマットファイルの作成

Django は多くのローカルに限定された書式を用意していますが、ときには、ロケール に書式ファイルがないとか、値を上書きしたいとかいった理由で、あなた自身の書式 を作りたくなるかもしれません。

カスタムフォーマットを使うには、最初にフォーマットファイルを保存するパスを指定 します。 FORMAT_MODULE_PATH 設定にフォーマットファイルを保存するパッ ケージを設定するだけです。たとえばこんな具合です:

FORMAT_MODULE_PATH = 'mysite.formats'

ファイルはこのディレクトリに直接ではなく、ロケール名のディレクトリに保存します。 formats.py という名前で保存してください。

英語の書式をカスタマイズするには、このような構造が必要です:

mysite/
    formats/
        __init__.py
        en/
            __init__.py
            formats.py

formats.py にカスタムフォーマットの定義が含めます。例えば:

THOUSAND_SEPARATOR = u'\xa0'

これは 3 桁ごとの区切りとして、英語のデフォルトのカンマの代わりにノーブレーク スペース (Unicode の 00A0) を使う場合です。

提供されるロケールフォーマットの制限

数字については、いくつかのロケールではコンテキストに依存した書式が使いられ ますが、それらに関しては Django のローカライズシステムは自動的には操作しません。

スイス (ドイツ語)

スイスの数字フォーマットは、フォーマットされる数字の種類に依存します。金額の 値では、 3 桁ごとの区切りにカンマが使われ、小数点の区切りには小数点が使われ ます。他の全ての数字では、カンマが小数点として使われ、空白が 3 桁ごとの区切 りに使わ れます。 Django が提供するロケールフォーマットは、汎用区切り文字を 使い、小数点にはカンマを、 3 桁ごとの区切りには空白を使います。

タイムゾーン

revision-up-to:17812 (1.4)
リリースノートを参照してください
概要

タイムゾーンを有効にすると、 Django はデータベースに日時の情報を UTC で保存しま す。内部的にはタイムゾーンを考慮した datetime オブジェクト を使用し、テンプレー トとフォームでエンドユーザのタイムゾーンに変換します。

これは、ユーザが複数のタイムゾーンに渡っていて、それぞれのユーザの時計に合わせ た日時を表示したい場合に便利です。

Web サイトがただ一つのタイムゾーンのみで使えるものだとしても、データベースに UTC でデータを保存しておくのは良い習慣です。一つの大きな理由は、 Daylight Saving Time (DST) があることです。多くの国では DST の制度があり、春には時計の針を進め て秋には遅れさせます。ローカル時間を使っていると、一年に二度時間の移動が起こっ てエラーにぶつかることになります。 (pytz ドキュメントは これらの問題 につい て深く議論しています。) これはおそらくブログでは気にならないでしょうが、毎年 2 回、1 時間ずれて顧客に過大請求や過小請求をしてしまうとしたら問題です。解決方法 はプログラムで UTC を使うこと、そしてエンドユーザとやり取りをする時だけローカル 時間を使うことです。

タイムゾーンのサポートはデフォルトで無効になっています。有効にするには USE_TZ = True を設定ファイルで設定します。強制ではありませ んが pytz をインストールすることを強くお薦めします。インストール方法は簡単です:

$ sudo pip install pytz

Note

django-admin.py startproject が作成する settings.py ファイルは利便性のため USE_TZ = True を含んでいます。

Note

別の関連する設定として USE_L10N 設定があります。これは Django が 書式ローカライズを有効にするかを決める設定です。詳しくは 書式ローカライズ を参照してください。

特定の問題と格闘しているなら タイムゾーン FAQ から探し てください。

概念
naive な datetime オブジェクトと aware な datetime オブジェクト

Python の datetime.datetime オブジェクトは tzinfo 属性を持っていま す。この属性は datetime.tzinfo のサブクラスのインスタンスで、タイムゾ ーン情報を保存するために使われています。この属性がセットされ、オフセットを表し ている時、 datetime オブジェクトは aware になります。そうでなければ ** naive ** なものになります。

datetime が aware か naive かを判断するには is_aware() 関数および is_naive() 関数を使います。

タイムゾーンサポートが無効の場合、 Django はローカル時間の naive な datetime オブジェクトを使用します。これはシンプルであり、多くの使い方ではこれで問題あり ません。このモードでは、現在時刻を取得するためにこのように書きます:

import datetime

now = datetime.datetime.now()

タイムゾーンサポートが有効な時は Django は aware な datetime オブジェクトを使 用します。ソースコードで datetime オブジェクトを作るなら、それらも aware であ るべきです。このモードでは、上の例はこうなります:

import datetime
from django.utils.timezone import utc

now = datetime.datetime.utcnow().replace(tzinfo=utc)

Note

django.utils.timezone モジュールは now() 関数を提供しています。 USE_TZ に従って、 naive な datetime オブジェクトか、 aware な datetime オブジェクトのいずれかを返します。

Warning

aware な datetime オブジェクトの扱いは必ずしも直感的とは言えないことがあり ます。例えば標準の datetime のコンストラクタに渡す tzinfo 引数は DST タイムゾーンでは正しく動作しません。 UTC を使えば概して安全です。 他のタイムゾーンを使っているなら、 pytz のドキュメントをよく読んでくださ い。

Note

Python では datetime.time オブジェクトも tzinfo 属性を備えてお り、 PostgreSQL の time with time zone 型に適合します。しかし、 PostgreSQL のドキュメントにあるように、この型は利便性に疑問がある情報を表し ています。

Django は naive な time オブジェクトだけをサポートしており、 aware な time オブジェクトを保存しようとすると例外を送出します。

naive な datetime オブジェクトの解釈

USE_TZTrue の場合でも、 Django は後方互換性のため naive な datetime オブジェクトを受け付けることができます。データベースレイヤがこのオブ ジェクトを受け取ると、 デフォルトタイムゾーン のもとでタイムゾーンを考慮するように変換し、警告 を送出します。

残念ながら DST での変換では datetime が存在しなかったり、曖昧だったりすること があります。このような状況では pytz は例外を送出します。別の tzinfo の実装では、 pytz がインストールされていない場合のフ ォールバックに使われるローカルタイムゾーンが例外を起こしたり、不正確な結果を返 す可能性があります。ですから、タイムゾーンサポートを有効にした場合は、常に aware な datetime オブジェクト を作るようにしてください。

実用上は、これが問題を起こすことはまれです。 Django はモデルやフォームで aware な datetime オブジェクトを使えるようになっています。 もっと多いのは新しい datetime オブジェクトは timedelta との 計算で作られます。アプリケーションのコードでよく作られるのは現在時刻です。 timezone.now() は自動で正しい動作をします。

デフォルトタイムゾーンとカレントタイムゾーン

デフォルトタイムゾーンTIME_ZONE で定義されたタイムゾーンで す。

カレントタイムゾーン はレンダリングに使われるタイムゾーンです。

カレントタイムゾーンは activate(). を使ってエンド ユーザの実際のタイムゾーンをセットしておきましょう。そうしなければ、デフォルト タイムゾーンが使われることになります。

Note

TIME_ZONE のドキュメントで説明しているように、 Django は自分自 身のプロセスがデフォルトタイムゾーンで実行されるように環境変数を設定しま す。 これは USE_TZ やカレントタイムゾーンの値にかからわず起こり ます。

USE_TZTrue の時、この動作はローカル時間に依存しているア プリケーションとの後方互換性を保つために便利です。しかし 先ほど説明したように これは完全に信頼できる 動作ではありませんので、ソースコードでは UTC のもとでタイムゾーン考慮の処理 をするべきです。例えば、 fromtimestamp() の代わり に utcfromtimestamp() を使います。そして utctzinfo に設定するのを忘れないよう にしましょう。

カレントタイムゾーンの選択

カレントタイムゾーンは翻訳における ロケール名 に相当しま す。しかし、 Accept-Language HTTP ヘッダに相当するものはないので、 Django は自動的にユーザのタイムゾーンを判別することができません。代わりに Django は タイムゾーン選択関数 を提供しています。 この関数を使ってタイムゾーン選択ロジックを構築してください。

多くの Web サイトは ユーザが生活しているタイムゾーンを訊ね、その情報をユーザプ ロフィールに保存します。匿名ユーザには主要なユーザ層のタイムゾーンか UTC を使い ます。 pytz は国ごとのタイムゾーンリストのような ヘルパ を提供していますので 開発者はもっともありえそうな選択肢を前もって選んでおくことができます。

次の例ではセッションにカレントタイムゾーンを保存しています。 (簡単にするため エラーハンドリングは省略しています。)

MIDDLEWARE_CLASSES にこのミドルウェアを追加してください:

from django.utils import timezone

class TimezoneMiddleware(object):
    def process_request(self, request):
        tz = request.session.get('django_timezone')
        if tz:
            timezone.activate(tz)

カレントタイムゾーンを設定するビューを作りましょう:

import pytz
from django.shortcuts import redirect, render

def set_timezone(request):
    if request.method == 'POST':
        request.session[session_key] = pytz.timezone(request.POST['timezone'])
        return redirect('/')
    else:
        return render(request, 'template.html', {'timezones': pytz.common_timezones})

このビューに POST するフォームを template.html に書きます:

{% load tz %}{% load url from future %}
<form action="{% url 'set_timezone' %}" method="POST">
    {% csrf_token %}
    <label for="timezone">Time zone:</label>
    <select name="timezone">
        {% for tz in timezones %}
        <option value="{{ tz }}"{% if tz == TIME_ZONE %} selected="selected"{% endif %}>{{ tz }}</option>
        {% endfor %}
    </select>
    <input type="submit" value="Set" />
</form>
タイムゾーンを考慮したフォームからの入力

タイムゾーンサポートを有効にすると、 Django は カレントタイムゾーン によってフォームから入力された日時を解釈し、 cleaned_data で aware な datetime オブジェクトを返します。

DST による時間移動で日時が存在しなかったり曖昧になって、カレントタイムゾーンが 例外を送出する場合 (pytz が提供するタイムゾーンはこのような動作をします) 、 そうした日時データは不正な値として報告されます。

タイムゾーンを考慮したテンプレートでの出力

タイムゾーンサポートを有効にしていると、 Django は aware な datetime オブジェ クトをテンプレートでレンダする時に カレントタイムゾーン に変換します。この振舞は 書式ローカライズ ととてもよく似ています。

Warning

Django は naive な datetime オブジェクトを変換しません。理由は、それが曖昧 であることと、タイムゾーンサポートが有効な時には決して naive な datetime を作るべきではないからです。しかし下に述べるテンプレートフィルタを使えば 強引に変換することもできます。

ローカル時間に変換することがいつも適切であるとは限りません。人間ではなくコンピ ュータのために出力を生成したいこともあるでしょう。以下のフィルタやタグは tz テンプレートタグライブラリにあり、開発者はタイムゾーン変換をコントロールするこ とができます。

テンプレートタグ
localtime

aware な datetime オブジェクトを現在のタイムゾーンに変換するかどうかを切り替え ます。

このタグはテンプレートエンジンに関係することを除けば USE_TZ 設定と同 じ効果がありますが、もっと細かい粒度で変換を制御できます。

テンプレートブロックで変換を有効化、無効化するにはこのようにします:

{% load tz %}

{% localtime on %}
    {{ value }}
{% endlocaltime %}

{% localtime off %}
    {{ value }}
{% endlocaltime %}

Note

{% localtime %} ブロックの中では USE_TZ の値は考慮されません。

timezone

囲んだブロックでカレントタイムゾーンを設定したり無効にしたりします。カレントタ イムゾーンが設定されていない場合、デフォルトタイムゾーンが使われます:

{% load tz %}

{% timezone "Europe/Paris" %}
    Paris time: {{ value }}
{% endtimezone %}

{% timezone None %}
    Server time: {{ value }}
{% endtimezone %}

Note

2 番目のブロックで None は Python の None オブジェクトになりますが、 None という名前のためではなく、テンプレートコンテキストで定義されていな いからに過ぎません。

get_current_timezone

django.core.context_processors.tz() コンテキストプロセッサが有効になって いれば (デフォルトで有効です) RequestContext は カレントタイムゾーンの名前を表す TIME_ZONE 変数を持ちます。

RequestContext を使わないなら、 get_current_timezone でカレントタイムゾーンの名前を取得できます。

{% get_current_timezone as TIME_ZONE %}
テンプレートフィルタ

これらのフィルタは aware な datetime と naive な datetime の両方を受け取ること ができます。変換のため、 naive な datetime はデフォルトタイムゾーンのもとの値 と仮定されます。返す値はつねに aware な datetime です。

localtime

1 つの値をカレントタイムゾーンに変換することを強制します。

例:

{% load tz %}

{{ value|localtime }}
utc

1 つの値を UTC に変換することを強制します。

例:

{% load tz %}

{{ value|utc }}
timezone

1 つの値を任意のタイムゾーンに変換することを強制します。

引数は tzinfo のサブクラスかタイムゾーン名でなければなりませ ん。タイムゾーン名を使う場合、 pytz が必要になります。

例:

{% load tz %}

{{ value|timezone:"Europe/Paris" }}
移行ガイド

Django がタイムゾーンをサポートする前につくられたプロジェクトを移行する方法を説 明します。

データベース
PostgreSQL

PostgreSQL バックエンドは datetime を timestamp with time zone として保存し ます。 これは、 datetime をデータベース接続のタイムゾーンから、ストレージ上では UTC に変換するということです。検索時には UTC からコネクションのタイムゾーンに変 換されます。

結果的に PostgreSQL を使っているなら、 USE_TZ = FalseUSE_TZ = True を自由に変更してよいことになります。データベース接続のタイムゾーンにはそれぞれ TIME_ZONEUTC が設定されます。どちらの場合でも Django は正し い datetime を得ることができます。データの変換を自分でする必要はありません。

その他のデータベース

他のバックエンドは datetime をタイムゾーンつきで保存しません。 もし設定を USE_TZ = False から USE_TZ = True に変更したら、自分でデータをローカル 時間から UTC に変換する必要があります。ローカル時間が DST を持っているかどうか は決定論的に決まるものではありません。

コード

最初に USE_TZ = True を設定ファイルに追加し、 (可能なら) pytz をインストールしましょう。これでもう、だいたいうまく行くでしょう。 ソースコードで naive な datetime オブジェクトを作成すると、 Django はそれらを 必要な時に aware なオブジェクトに変換します。

しかし、 DST 移動がある場合はこの変換は失敗します。そのため開発者はタイムゾーン サポートから最大限に利益を得ることができません。また、 naive な datetime と aware な datetime を比較することは不可能なため、いろいろと問題にぶつかるに違い ありません。 Django は aware な datetime を返すので、モデルやフォームからの datetime を、自分のコードで作成した naive な datetime と比較すると、常に例外が 発生することになります。

そのため、 2 番目のステップとして、 datetime オブジェクトを生成している全ての箇 所で、 aware にリファクタリングしましょう。これは少しずつ行うことができます。 django.utils.timezone モジュールは互換性のあるコードのために手軽なヘルパ ーを数点定義しています: now(), is_aware(), is_naive(), make_aware(), make_naive() です。

最後に、アップグレードが必要なコードを見つけやすくするために、 naive な datetime をデータベースに保存しようとすると Django は警告を送出します。

RuntimeWarning: DateTimeField received a naive datetime (2012-01-01 00:00:00) while time zone support is active.

開発中は、設定ファイルに以下を記述しておけば、この警告を例外に変更しトレースバ ックを見ることができます:

import warnings
warnings.filterwarnings(
        'error', r"DateTimeField received a naive datetime",
        RuntimeWarning, r'django\.db\.models\.fields')
フィクスチャ

aware な datetime をシリアライズすると、このように UTC オフセットが含まれるよ うになります:

"2011-09-01T13:20:30+03:00"

naive な datetime では含まれていません:

"2011-09-01T13:20:30"

この違いのため DateTimeField を含むモデルでは タイム ゾーンありでもなしでも動作するフィクスチャを書き出すことはできません。

USE_TZ = False で生成したフィクスチャや、 Django 1.4 以前では、 “naive な” フォーマットが使われます。プロジェクトにこのようなフィクスチャが含まれていると、 タイムゾーンサポートを有効にした後でそれらをロードした時に RuntimeWarning を見ることになるでしょう。警告が出ないようにするにはフィクスチャを “aware な” フォーマットに変換する必要があります。

loaddata してから dumpdata することでフィクスチャを再生成 できます。または、それらが少量なら単に編集して TIME_ZONE に合わせた UTC オフセットを付加するだけでもかまいません。

FAQ
セットアップ
  1. 複数のタイムゾーンは必要ないけど、タイムゾーンサポートを有効にするべき ?

    はい。タイムゾーンサポートを有効にしておくと、 Django はローカル時間のモデル をより正確に使えます。これによって Daylight Saving Time (DST) まわりの微妙で 再現しにくいバグを防ぐことができます。

    この点では、タイムゾーンは Python の unicode と比較できます。あなたはエ ンコーディングエラーやデコーディングエラーを起こします。それからあなたは規則 を学びます。すると色々な問題が消えてなくなります。あなたはもうアプリケーショ ンが非 ASCII の入力を受け取った時に出力をめちゃくちゃにすることはないでしょう。

    タイムゾーンサポートを有効にしても、 Django が aware な datetime を期待して いる場所で naive な datetime を使うと色々なエラーに遭遇します。それらのエ ラーはテストを実行すると発見でき、簡単に直せます。誤った操作を避けるにはど うすれば良いかを素早く学ぶことができるでしょう。

    一方、タイムゾーンサポートがないことによるバグは、防いだり、原因を突き止めた り、直すのがもっと難しいものです。スケジュールされたタスクや datetime の計算 を含む箇所ではどこでも、 1 年に 1 度か 2 度しか起こらない微妙なバグを含む可 能性があります。

    このような理由でタイムゾーンサポートは新しいプロジェクトでは有効になっていま す。そうしないことにとても良い理由がない限りは、そのままにしておいてください。

  2. タイムゾーンサポートを有効にしておけば安全ですか ?

    おそらく。そうしておけば DST 関連のバグは防ぎやすくなっています。ただ、 naive な datetime を aware な datetime へと不注意に変えることで墓穴を掘る可 能性は残されています。

    あなたがアプリケーションを他のシステムに接続するなら – 例えば、ある Web サ ービスにクエリを発行するとか – datetime が適切に指定されているかを確認して ください。安全に datetime を伝えるには、表記に UTC オフセットを含めるか、値 を UTC にするか (または両方!) であるべきです。

    このカレンダーシステムはコンピュータにとって奇妙な罠があります:

    >>> import datetime
    >>> def substract_one_year(value):       # DON'T DO THAT!
    ...     return value.replace(year=value.year - 1)
    >>> one_year_before(datetime.datetime(2012, 3, 1, 10, 0))
    datetime.datetime(2011, 3, 1, 10, 0)
    >>> one_year_before(datetime.datetime(2012, 2, 29, 10, 0))
    Traceback (most recent call last):
    ...
    ValueError: day is out of range for month
    

    (この関数を実装するには、2012-02-29 マイナス 1 年が 2011-02-28 なのか 2011-03-01 なのかを決定しなければなりません)

  3. pytz をインストールするべきですか ?

    はい。 Django は外部依存を必要としないというポリシーをもっているので、 pytz は必須ではありません。でも、インストールするほうがより安全です。

    タイムゾーンサポートを有効にした瞬間から Django はデフォルトタイムゾーンの定 義を必要とします。 pytz が有効であれば Django はこの定義を tz database か らロードします。これはより正確な解決方法です。 pytz が使えなければ OS が報告 するローカル時間と UTC の差に頼って変換を計算することになります。これは信頼 性がそれほど高くありません。 DST の移動が起こる場合は特にそうです。

    さらにまた、ユーザが 1 つ以上のタイムゾーンを使えるようにしたいなら、 pytz はタイムゾーン定義のリファレンスになります。

トラブルシューティング
  1. TypeError: can't compare offset-naive and offset-aware datetimes という メッセージで アプリケーションがクラッシュします – 何がまずいの?

    naive な datetime と aware な datetime を比較してこのエラーを再現してみま しょう。

    >>> import datetime
    >>> from django.utils import timezone
    >>> naive = datetime.datetime.utcnow()
    >>> aware = naive.replace(tzinfo=timezone.utc)
    >>> naive == aware
    Traceback (most recent call last):
    ...
    TypeError: can't compare offset-naive and offset-aware datetimes
    

    このエラーに出会ったならあなたのコードがこの 2 つを比較しているに違いありま せん:

    • Django によって作られた datetime – 例えばフォームやモデルフィールドから読 み込まれた値。タイムゾーンサポートを有効にしていると、 aware な値です。
    • a datetime generated by your code, which is naive (or you wouldn’t be reading this).
    • あなたのコードが生成した naive な datetime (でなければここを読んでいない でしょう)

    一般論として、 aware な datetime を使うようにコードを変えるのが正しい方法で す。

    USE_TZ の値と関係なく動作しなければいけないプラガブルなアプリケー ションを書いているのであれば django.utils.timezone.now() が便利だと思 います。この関数は USE_TZ = False の時は naive な datetime を返しますし、 USE_TZ = True の時は aware な datetime を返します。必要なら datetime.timedelta を足したり引いたりすることもできます。

  2. RuntimeWarning: DateTimeField received a naive datetime (YYYY-MM-DD HH:MM:SS) while time zone support is active というエラ ーを良く見ます。これって良くない?

    タイムゾーンサポートが有効な時、データベース層はあなたのコードから aware な datetime のみを受け取ることを期待しています。この警告は naive な datetime を受け取った時に起こります。あなたのコードはタイムゾーンサポートのための移 植が終わっていないということになります。移植のコツは マイグレーション ガイド を参考にしてください。

    移植が終わるまでは、後方互換性のため datetime はデフォルトタイムゾーンにある とみなされます。これはたいていあなたが期待していることでしょう。

  3. now.date() が昨日 (あるいは明日) です !

    あなたがいつも naive な datetime を使っているなら、おそらく date() メソッドを呼び出して date に変換できると考え ているのでしょう。また、 datedatetime によく似ていて、時間の精度が低いだけだと思ってい るでしょう。

    aware な環境では、いずれも正しくありません:

    >>> import datetime
    >>> import pytz
    >>> paris_tz = pytz.timezone("Europe/Paris")
    >>> new_york_tz = pytz.timezone("America/New_York")
    >>> paris = paris_tz.localize(datetime.datetime(2012, 3, 3, 1, 30))
    # This is the correct way to convert between time zones with pytz.
    >>> new_york = new_york_tz.normalize(paris.astimezone(new_york_tz))
    >>> paris == new_york, paris.date() == new_york.date()
    (True, False)
    >>> paris - new_york, paris.date() - new_york.date()
    (datetime.timedelta(0), datetime.timedelta(1))
    >>> paris
    datetime.datetime(2012, 3, 3, 1, 30, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)
    >>> new_york
    datetime.datetime(2012, 3, 2, 19, 30, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
    

    この例が示すように、同じ datetime でもそれを表現するタイムゾーンによっては違 う日付を持っています。ですが、本当の問題はもっと基本的なことです。

    ある datetime は 1 つの時点 を表します。これは絶対的なことで、何にも依存 していません。対照的に、 date は カレンダー上の概念 です。 date が考慮さ れるタイムゾーンに依存して範囲が決まる、時間の区切りです。この 2 つの概念は 根本的に異なっていて、 datetime から date への変換は決定論的な操作ではないの です。

    これは実用上何を意味するのでしょうか。

    一般的に datetime から date への変換を 避けるべきです。例えば date テンプレートフィルタを使って datetime の日付の部分だけを表示することができます。このフィルタは datetime をカレント タイムゾーンの上で変換し、それからフォーマットしますので、正しく結果が表示さ れることが保証できます。

    本当に自分自身で変換する必要があるなら、 datetime がまず適切なタイムゾーンに 変換されることを保証しなければなりません。それは普通、カレントタイムゾーンで しょう:

    >>> from django.utils import timezone
    >>> timezone.activate(pytz.timezone("Asia/Singapore"))
    # For this example, we just set the time zone to Singapore, but here's how
    # you would obtain the current time zone in the general case.
    >>> current_tz = timezone.get_current_timezone()
    # Again, this is the correct way to convert between time zones with pytz.
    >>> local = current_tz.normalize(paris.astimezone(current_tz))
    >>> local
    datetime.datetime(2012, 3, 3, 8, 30, tzinfo=<DstTzInfo 'Asia/Singapore' SGT+8:00:00 STD>)
    >>> local.date()
    datetime.date(2012, 3, 3)
    
使用法
  1. "2012-02-21 10:28:45" という文字列があり "Europe/Helsinki" タイムゾーンでのものだと分かっています。どうやって aware な datetime にすれば良いでしょうか ?

    まさに pytz がこのためにあります。

    >>> from django.utils.dateparse import parse_datetime
    >>> naive = parse_datetime("2012-02-21 10:28:45")
    >>> import pytz
    >>> pytz.timezone("Europe/Helsinki").localize(naive)
    datetime.datetime(2012, 2, 21, 10, 28, 45, tzinfo=<DstTzInfo 'Europe/Helsinki' EET+2:00:00 STD>)
    

    `` localize`` は pytz における tzinfo API の拡張であるこ とに注意してください。 InvalidTimeError を把捉したいかもしれま せん。 pytz のドキュメントには もっと多くの例 があります。タイムゾーン考 慮の datetime を操作しようと試みる前に、見てみるほうが良いでしょう。

  2. ローカルタイムゾーンでの現在時刻を得るにはどうすればいい ?

    そうですね、最初の質問は、本当にそれが必要なのかということです。

    ローカル時間を使うのは人間とのインタラクションの時だけにすべきです。テンプレ ート層は datetime をあなたが選んだタイムゾーンに変換するための フィルタとタグ を提供しています。

    さらにまた、 Python は必要な時に UTC オフセットを考慮して、 aware な datetime を比較することができます。

    しかし念のため、本当にローカルタイムゾーンの現在時刻が必要なら、このようにし て得ることができます:

    >>> import datetime
    >>> from django.utils import timezone
    >>> datetime.datetime.now(tz=timezone.get_default_timezone())
    datetime.datetime(2012, 3, 3, 20, 10, 53, 873365, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)
    

    この例では pytz がインストールされていて TIME_ZONE"Europe/Paris" に設定されています。

  3. 使えるタイムゾーンを全て見たいのですが ?

    pytz はカレントタイムゾーンのリストと全ての使えるタイムゾーン (一部は歴史的 な関心しか持たれません) のリストを含んだ ヘルパ を提供しています。

概要

国際化とローカライズの目的は、一つの Web アプリケーションが閲覧者に合わせた言 語や書式でコンテンツを提供できるようにすることにあります。

Django は テキスト翻訳日時と数字の書式設定タイムゾーン をフルサポートしています。

Django が行っているのは、本質的には以下の二つの作業です:

  • 開発者やテンプレート作成者に、アプリケーションのどの部分がローカルな言語と 文化に翻訳およびフォーマットされるべきかを、指定させます。
  • 指定したフックを使って、特定のユーザの言語設定に従って Web アプリケーショ ンをローカライズします。

言うまでもなく、翻訳は対象言語に依存し、書式は対象の国に依存します。これらの 情報はブラウザの Accept-Language ヘッダで与えられます。ただし、タイムゾ ーンを読み取ることはできません。

定義

「国際化 (internationalization) 」と「ローカライズ (localization) 」という言 葉はよく混乱を招きます。ここでは簡単に定義しましょう:

国際化 (internationalization)
ソフトウェアをローカライズに備えさせること。通常、開発者によって行われ ます。
ローカライズ (localization)
翻訳およびローカルな書式を記述すること。通常、翻訳者によって行われます。

より詳しくは、 W3C Web Internationalization FAQWikipediaの記事GNU gettext documentation で知ることができます。

Warning

翻訳と書式設定は USE_I18NUSE_L10N 設定によって 制御されますが、どちらも国際化とローカライズを含む設定です。この設定名は Django の歴史によってこうなってしまったものです。

共通言語を扱うため、他にいくつかの用語が助けになるでしょう:

ロケール名 (locale name)
ll 形式の言語指定、または ll_CC 形式での言語および国指定です。 it, de_AT, es, pt_BR など。 言語部分は常に小文字で、国部分は大文字です。アンダースコアで区切りま す。
言語コード (language code)
言語名を表します。ブラウザは Accept-Language HTTPヘッダの中でこの 書式を使って表示可能な言語名を通知します。 it, de-at, es, pt-br など。言語部分と国部分の両方が小文字で、ダッシュ (-) で区切られています。
メッセージファイル
メッセージファイルは一つの言語を表すプレーンテキストファイルです。利用 可能な全ての 翻訳文字列 (translation strings) と、それ らがその言語でどのように表されるかが記述されます。ファイル拡張子は .po です。
翻訳文字列 (translation string)
翻訳可能なリテラル文字列です。
書式ファイル (format file)
指定されたロケールでのデータ書式を表す Python モジュールです。

ロギング

revision-up-to:17812 (1.4)
リリースノートを参照してください

クイックロギング入門

Django は Python の組込モジュール logging を使ってシステムのログ出力を 行います。このモジュールの使用法は Python 自体のドキュメントで詳しく議論され ています。しかし、 Python のロギングフレームワークを使ったことがなければ (あ っても) このクイック入門を読んでみてください。

プレイヤーの配役

Python のロギング設定は 4 つの部分からなります:

ロガー

ロガー (logger) はロギングシステムのエントリポイントです。ロガーはメッセージが 処理のために書き込まれる名前つきの容れ物です。

個々のロガーは ログレベル を持つように設定されます。ログレベルは、そのロガー が処理するメッセージの深刻度を表します。 Python は以下のログレベルを定義してい ます:

  • DEBUG: デバッグ目的で低いレベルのシステム情報
  • INFO: 一般的なシステム情報
  • WARNING: 発生した小さな問題についての情報
  • ERROR: 発生した大きな問題についての情報
  • CRITICAL: 発生した致命的な問題についての情報

ロガーに書き込まれるメッセージは ログレコード です。個々のログレコードも特定 のメッセージの深刻度を示す ログレベル を持ちます。ログレコードは記録されるイ ベントを説明する有益なメタデータを含むこともできます。スタックトレースやエラー コードのような詳細を含みます。

メッセージがロガーに渡されると、メッセージのログレベルとロガーのログレベルが比 較されます。メッセージのログレベルが、ロガーのログレベルと同じかそれより高けれ ば、メッセージは処理に進みます。そうでなければメッセージは無視されます。

ロガーがメッセージを処理すべきと決定したなら、メッセージは ハンドラ に渡され ます。

ハンドラ

ハンドラ (handler) はロガーの持つ個々のメッセージに何が起こるかを決定するエン ジンです。ハンドラは、メッセージを画面やファイルやネットワークソケットに出力し たりといった、ロギングの決まった動作を示します。

ロガーと同様に、ハンドラもまたログレベルを持っています。ログレコードのログレベ ルがハンドラのレベルより低ければ、ハンドラはメッセージを無視します。

ロガーは複数のハンドラを持つことができます。それぞれのハンドラは異なるログレベ ルに設定できます。こうすることで、メッセージの重要性に従って、異なる通知の形式 を提供することが可能になります。例えば、ページ出力サービスに ERRORCRITICAL メッセージを渡すハンドラを設定し、別のハンドラでは ERRORCRITICAL を含む全てのメッセージを、後で分析するためにファイルに記録す る、といったことができます。

フィルタ

フィルタ (filter) はロガーからハンドラに渡されるログレコードに対する追加の操作 を提供するために使われます。

デフォルトでは必要なログレベルを満たす全てのログメッセージが処理されます。しか しフィルタを設定することでロギングプロセスに追加の基準を作ることができます。例 えば、特定のソースからの ERROR メッセージだけを発行することを許可するフィ ルタを作れます。

フィルタはまたログレコードの発行される優先度を変更するために使うことができま す。例えば、決まった一連の基準を満たすと ERROR ログレコードを WARNING に落とすフィルタを作ることができます。

フィルタはロガーまたはハンドラに対して設定することができます。複数のアクション を実行するために、複数のフィルタをチェーンとして使うことができます。

フォーマッタ

ログレコードは究極的にはテキストとして描画されます。フォーマッタ (formatter) はそのテキストの正確な形式を表します。フォーマッタは普通 Python のフォーマット 文字列からなります。しかし、特定のフォーマット動作を実装したカスタムのフォー マッタを作ることもできます。

ロギングを使う

ロガー、ハンドラ、フィルタ、フォーマッタを設定したら、コードの中にロギングの呼 び出しを入れなければなりません。ロギングフレームワークの使い方はとてもシンプル です。例を挙げましょう:

# logging ライブラリをインポートする
import logging

# ロガーインスタンスを取得
logger = logging.getLogger(__name__)

def my_view(request, arg1, arg):
    ...
    if bad_mojo:
        # エラーメッセージをログ出力
        logger.error('Something went wrong!')

これだけです ! bad_mojo 条件が満たされるたびにエラーログレコードが書き出さ れます。

ロガーの命名

logging.getLogger() の呼び出しによりロガーインスタンスが取得 (必要な場 合は生成) されます。ロガーインスタンスは名前により特定されます。この名前は設定 でロガーを特定するためにも使われます。

慣習的に、ロガーの名前は通常 __name__ を使います。これはロガーを含む Python モジュール名です。こうするとロギングの呼び出しをモジュール単位でフィル タしたりハンドルできます。しかしながら、ロギングメッセージを整理する別の方法が あるなら、ロガーを特定するためにドットで分割された任意の名前を使うことができま す:

# 特定の名前のロガーインスタンスを取得
logger = logging.getLogger('project.interesting.stuff')

ロガー名のドットパスによって階層が定義されます。 project.interesting ロガ ーは project.interesting.stuff ロガーの親と見なされます。 project ロ ガーは project.interesting ロガーの親です。

なぜ階層が重要なのでしょう。それは、ロガーの呼び出しをロガーが親に 伝播させる (propagate) ことができるようにするためです。この方法で、ロガー階層のルートに 1 つのハンドラの集合を定義できます。 project 名前空間で定義されたロガーハ ンドラは、 project.interesting および project.interesting.stuff ロガー から発行された全てのロギングメッセージをつかまえることになります。

伝播はロガー単位で制御できます。特定のロガーでは親に伝播させたくないなら、この 動作をオフにすることができます。

ロギングの実行

ロガーインスタンスはデフォルトログレベルのそれぞれに対するメソッドを持っていま す:

  • logger.critical()
  • logger.error()
  • logger.warning()
  • logger.info()
  • logger.debug()

他に 2 つの呼び出し方法があります:

  • logger.log(): 指定したログレベルでロギングメッセージを発行します。
  • logger.exception(): 現在の例外スタックトレースをラップした ERROR レ ベルのログメッセージを作成します。

ロギングの設定

当然ながらコードにロギングの実行を入れただけでは不十分です。ロガー、ハンドラ、 フィルタ、フォーマッタを設定してログ出力がされることを確認しなければなりませ ん。

Python の logging ライブラリはロギングを設定する方法を複数用意しています。その 方法はプログラムによるインタフェースから設定ファイルまで多岐にわたります。 デフォルトでは Django は dictConfig フォーマット を使います。

Note

logging.dictConfig は Python 2.7 の組込ライブラリです。もっと古いバー ジョンの Python を使っている場合にこのライブラリを使えるようにするため、 Django は django.utils.log の一部としてそれをコピーしています。 Python 2.7 を使っているなら、システムのネイティブライブラリが使われますが、 2.6 以前では Django 内のコピーが使われます。

ロギング設定をするためには LOGGING を使ってロギング設定の辞書を定義 してください。この設定にはセットアップしたいロガー、ハンドラ、フィルタ、フォー マッタを記述し、ログレベルやコンポーネントに持たせたい他の設定を書きます。

ロギングは設定ファイルがロードされた後直接設定されます。設定ファイルのロードは Django が一番最初にすることの 1 つなので、プロジェクトコードではロガーが準備済 になっていることを確信してかまいません。

dictConfig フォーマット の全体ドキュメントはロギング設定辞書の一番良い情報 源です。しかしながら、その可能性を味わっていただくために、ここでは logging.dictConfig() を使ったかなり複雑なロギングセットアップ例を示しま す:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'filters': {
        'special': {
            '()': 'project.logging.SpecialFilter',
            'foo': 'bar',
        }
    },
    'handlers': {
        'null': {
            'level':'DEBUG',
            'class':'django.utils.log.NullHandler',
        },
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['special']
        }
    },
    'loggers': {
        'django': {
            'handlers':['null'],
            'propagate': True,
            'level':'INFO',
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myproject.custom': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}

このロギング設定は以下のことを行います:

  • 設定が ‘dictConfig version 1’ フォーマットであることを特定します。現在のとこ ろこれは dictConfig フォーマットの唯一のバージョンです。

  • 既存のロギング設定を全て無効にします。

  • フォーマッタを 2 つ定義します:

    • simple はログレベル名 (DEBUG など) とログメッセージだけを出力しま す。

      format 文字列は通常の Python のフォーマット文字列で、各ロギング行で出力 される詳細を記述します。出力できる詳細の完全なリストは フォーマッタドキュメント にあります。

    • verbose はログレベル名、ログメッセージに加えて、時間、プロセス、スレッ ド、ログメッセージを生成したモジュールを出力します。

  • フィルタを 1 つ、 project.logging.SpecialFilter を定義し、別名を special とします。このフィルタを作成する時に追加の引数が必要であれば、 フィルタ設定辞書にそれらを追加のキーとして含めます。今の場合だと SpecialFilter のインスタンスが作られる時 foo 引数に値 bar が与えられます。

  • ハンドラを 3 つ定義します:

    • null NullHandler です。 DEBUG 以上の全てのメッセージを /dev/null に捨てます。
    • console StreamHandler です。 DEBUG 以上の全てのメッセージを標準エ ラー出力に出力します。このハンドラは simple 出力フォーマットを使います。
    • mail_admins AdminEmailHandler です。 ERROR 以上の全てのメッセージ をサイト管理者にメール送信します。このハンドラは special フィルタを使 います。
  • ロガーを 3 つ定義します:

    • djangoINFO 以上のメッセージを null ハンドラに渡します。
    • django.request は全ての ERROR メッセージを mail_admins ハンド ラに渡します。さらに、このロガーはメッセージを伝播 しない ように印をつけ られています。これにより django に書かれたログメッセージを django ロガーは扱わないことになります。
    • myproject.customINFO 以上の全てのメッセージと special フィ ルタを 2 つのハンドラ consolemail_admins に渡します。全ての INFO レベル以上のメッセージはコンソールに出力され、 ERRORCRITICAL メッセージはメール経由で出力されることになります。

カスタムハンドラと循環インポート

もし settings.py がカスタムハンドラクラスを指定していて、そのクラスを 定義したファイルが settings.py をインポートしていたら、循環インポート が起こります。

例えば、 settings.pyLOGGING に以下の設定をしているとし ます:

LOGGING = {
  'version': 1,
  'handlers': {
    'custom_handler': {
      'level': 'INFO',
      'class': 'myproject.logconfig.MyHandler',
    }
  }
}

そして myproject/logconfig.pyMyHandler の定義より前に以下の行 があるとします:

from django.conf import settings

すると dictconfig は以下のような例外を起こすでしょう:

ValueError: Unable to configure handler 'custom_handler':
Unable to configure handler 'custom_handler':
'module' object has no attribute 'logconfig'
カスタムロギング設定

自分のロガーを設定するのに Python の dictConfig フォーマットを使うことを望まな いなら、自分自身の設定スキームを指定することができます。

LOGGING_CONFIG 設定は Django のロガーが使う呼び出し可能オブジェクト (callable) を定義します。デフォルトでは Python の logging.dictConfig() メソッドを指しています。しかし、別の設定プロセスを使いたいなら、引数を 1 つと るどんな呼び出し可能オブジェクトでも使えます。ロギングが設定される時に LOGGING の内容がその引数の値として渡されます。

ロギング設定の無効化

ロギングを設定することを全く望んでいない (または自分のアプローチによって手動で 設定をしたい) なら、 LOGGING_CONFIGNone をセットしてくださ い。設定プロセスが無効になります。

Note

LOGGING_CONFIGNone をセットすることは設定プロセスを無効 化するだけで、ロギングそのものは無効化されません。設定プロセスを無効にして も Django は依然としてロギングを実行し続け、定義されているデフォルトのロギ ング動作にフォールバックします。

Django によるロギング拡張

Django は Web サーバ環境でのロギング固有の要求をハンドルするユーティリティを数 多く提供しています。

ロガー

Django には 3 つの組込ロガーがあります。

django

django は全てをキャッチするロガーです。どんなメッセージもこのロガーに直接 投稿されることはありません。

django.request

リクエストのハンドリングに関係するログメッセージです。 5XX レスポンスは ERROR メッセージとして送出され、 4XX レスポンスは WARNING メッセージと して送出されます。

このロガーへのメッセージは以下の追加されたコンテクストを持ちます:

  • status_code: リクエストに対応する HTTP レスポンスコード
  • request: ロギングメッセージを生成したリクエストオブジェクト
django.db.backends

コードとデータベースの相互作用に関するメッセージ。例えばリクエストによって実行 された SQL 文は DEBUG レベルでこのロガーに記録されます。

このロガーへのメッセージは以下の追加されたコンテクストを持ちます:

  • duration: SQL 文の実行にかかった時間
  • sql: 実行された SQL 文
  • params: SQL 呼び出しで使われたパラメータ

パフォーマンス上の理由により、 SQL ロギングはロギングレベルや使用させるハンド ラに関わりなく settings.DEBUGTrue の時にだけ有効になります。

ハンドラ

Django は Python の logging モジュールが提供するものに加えて 1 つのログハンド ラを提供します。

class AdminEmailHandler([include_html=False])

このハンドラは受け取ったログメッセージごとにサイト管理者に E メールを送信 します。

ログレコードが request 属性を持っていれば、リクエストの全ての詳細が E メールに含まれることになります。

ログレコードがスタックトレース情報を含んでいたら、そのスタックトレースが E メールに含まれます。

AdminEmailHandlerinclude_htmlDEBUGTrue だった時に用意されるデバッグ用 Web ページの全ての内容を HTML で添付するか どうかを制御します。この値をセットするには django.utils.log.AdminEmailHandler のハンドラ定義に含めてください。こ んな具合です:

'handlers': {
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler',
        'include_html': True,
    }
},

E メールの HTML 版はスタックトレースの各レベルでのローカル変数名と値、さら に Django 設定の値を含むことに注意してください。この情報は潜在的にとてもセ ンシティブなもので、 E メールで送りたくないかもしれません。完全なスタック トレースの豊富な情報と、 E メールで情報を送らないことの安全性、この両方の 世界の一番良いところを取るには、 django-sentry のようなものを使うことを 検討してください。また、エラーリポートから確実にセンシティブな情報を除外す るように、明示的に設計することもできます。 エラーリポートのフィルタリング でもっと多 くのことを学んでください。

フィルタ

Django は Python の logging モジュールが提供するものに加えて 2 つのログフィル タを提供します。

class CallbackFilter(callback)
リリースノートを参照してください

このフィルタはコールバック関数 (1 つの引数でログレコードを受け取れる必要が あります) を受け取り、フィルタを通るレコードごとにそれを実行します。コール バックが False を返すと、そのレコードのハンドリングは中止されます。

class RequireDebugFalse
リリースノートを参照してください

このフィルタは settings.DEBUG が False の時にだけレコードを通します。

このフィルタは、以下のようにデフォルトの LOGGING 設定で、 DEBUGFalse の時にだけエラーメールを送ることを保証するため に使われています:

'filters': {
     'require_debug_false': {
         '()': 'django.utils.log.RequireDebugFalse',
     }
 },
 'handlers': {
     'mail_admins': {
         'level': 'ERROR',
         'filters': ['require_debug_false'],
         'class': 'django.utils.log.AdminEmailHandler'
     }
 },

ペジネータ (paginator)

revision-up-to:17812 (1.4)

Django は、ページ分割された (paginated) データを扱うためのペジネータ (paginator) クラスを提供しています。ページ分割とは、データが複数のページに わたって表示され、それぞれのページに「前へ/次へ」といったリンクがある状態 を指します。ペジネータのクラスは、 django/core/paginator.py モジュー ルで定義されています。

使い方

ペジネータを使うには、まず Paginator クラスにオブジェクトのリスト と、各ページに表示したい要素数を指定してインスタンスを生成します。生成され るインスタンスは、各ページの要素にアクセスするためのメソッドを提供していま す:

>>> from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2)

>>> p.count
4
>>> p.num_pages
2
>>> p.page_range
[1, 2]

>>> page1 = p.page(1)
>>> page1
<Page 1 of 2>
>>> page1.object_list
['john', 'paul']

>>> page2 = p.page(2)
>>> page2.object_list
['george', 'ringo']
>>> page2.has_next()
False
>>> page2.has_previous()
True
>>> page2.has_other_pages()
True
>>> page2.next_page_number()
3
>>> page2.previous_page_number()
1
>>> page2.start_index() # The 1-based index of the first item on this page
3
>>> page2.end_index() # The 1-based index of the last item on this page
4

>>> p.page(0)
Traceback (most recent call last):
...
EmptyPage: That page number is less than 1
>>> p.page(3)
Traceback (most recent call last):
...
EmptyPage: That page contains no results

Note

Paginator にはリストやタプル、 Django の QuerySet の他に、 count()__len__() をメソッドを備えた任意のオブジェクトを渡せ ることに注意してください。 Paginator は、渡されたコンテナ内のオブジェ クトの数を調べるのに、まず count() を呼び出そうとし、 count() がなければ len() にフォールバックします。これにより、 QuerySet のようなオブジェクトで、より効率的な count() を呼び出しています。

Paginator をビューで使う

今度は、ビューの中でクエリセットをページ分割するために Paginator を 使うもう少し複雑な例です。どのように結果が表示されるかが分かるように、ビュー とビューが使うテンプレートの両方を示します。この例では Contacts モデルが 既にインポートされているものとします。

ビュー関数は以下のようになります:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def listing(request):
    contact_list = Contacts.objects.all()
    paginator = Paginator(contact_list, 25) # Show 25 contacts per page

    page = request.GET.get('page')
    try:
        contacts = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        contacts = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        contacts = paginator.page(paginator.num_pages)

    return render_to_response('list.html', {"contacts": contacts})

テンプレート list.html では、ページ間のナビゲーションを組み込みたいで しょう。ページはオブジェクトをもとにした何らかの興味深い情報を含んでいます:

{% for contact in contacts %}
    {# Each "contact" is a Contact model object. #}
    {{ contact.full_name|upper }}<br />
    ...
{% endfor %}

<div class="pagination">
    <span class="step-links">
        {% if contacts.has_previous %}
            <a href="?page={{ contacts.previous_page_number }}">previous</a>
        {% endif %}

        <span class="current">
            Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
        </span>

        {% if contacts.has_next %}
            <a href="?page={{ contacts.next_page_number }}">next</a>
        {% endif %}
    </span>
</div>
以前は Page オブジェクトがイテレーション可能ではなかったので {% for contact in contacts.object_list %} とする必要がありました。

Paginator オブジェクト

Paginator クラスは、以下のようなコンストラクタを持っています:

class Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True)
必須の引数
object_list
リスト、タプル、Django の QuerySet, または count()__len__() メソッドを備えたオブジェクトを指定します。
per_page
一ページに表示するオブジェクトの最大個数です (後述のオプション引数 orphans も参照してください)。
オプションの引数
orphans
最後のページに表示する要素の個数です。デフォルト値はゼロに設定されてい ます。最後のページに表示するオブジェクトの個数を一定以上にしたい場合に 使ってください。 orphans を設定すると、ページ分割した要素の末尾のグ ループの個数が orphans の設定値以下のときに、そのグループの要素だけ のページを表示するのではなく、ひとつ前のページの要素に繰り入れて表示し ます(すなわち、一つ手前のページが最終ページになります)。例えば、 per-page=10 かつ orphans=3 のペジネータで 23 個のオブジェクトを 表示すると、ページは二つに分割され、最初のページには 10 個、二つ目のペー ジ(最終ページ)には 13 個の要素を表示します。
allow_empty_first_page
先頭のページが空でもよいかどうかを決めるパラメタです。 False に設定 すると、 object_list が空のときに EmptyPage 例外を送出します。
メソッド
Paginator.page(number)

指定ページの Page オブジェクトを返します。ページ番号は 1 から 始まる数です。存在しないページを指定すると InvalidPage を送出し ます。

属性
Paginator.count

全てのページにわたるオブジェクトの合計数です。

Note

object_list に入っているオブジェクトの個数を調べるときに、 Paginator はまず object_list.count() を呼びます。 object_listcount() メソッドがなければ、 Paginatorlen(object_list) に切り替えます。これにより、 QuerySet のようなオブジェクトで、より効率的な count() を呼 び出しているのです。

Paginator.num_pages

総ページ数です。

Paginator.page_range

[1, 2, 3, 4] のように、 1 から始まるページ番号です。

InvalidPage 例外

exception InvalidPage

ペジネータが不正なページ番号を渡された時に送出される例外の基底クラス です。

リクエストされたページが無効なページ (整数でないページ番号) であったり、ペー ジにオブジェクトが含まれていない場合、 Paginator.page() メソッドは例外 を送出します。通常はこの InvalidPage 例外をトラップするだけですみますが、 より細かく例外処理するには、以下の例外をトラップしてください:

exception PageNotAnInteger

page() に整数でない値を渡したときに送出されます。

exception EmptyPage

page() には有効な値が渡されているが、ページにオブジェクトが含まれな い場合に送出されます。

どちらの例外も :exc:InvalidPage のサブクラスなので、単に except InvalidPage としておけば両方の例外を捕捉できます。

Page オブジェクト

普通は Page オブジェクトを手動で作ろうとは思わないでしょう。 Paginator.page() を使って取得できます。

Page(object_list, number, paginator):
len() を使ったり直接イテレーションする場合、ページは Page.object_list のように振る舞います。
メソッド
Page.has_next()

次のページがある場合に True を返します。

Page.has_previous()

前のページがある場合に True を返します。

Page.has_other_pages()

前後 いずれか のページがある場合に True を返します。

Page.next_page_number()

次のページが存在するかどうかに関係なく、「次のページ」のページ番号を返 します。

Page.previous_page_number()

前のページが存在するかどうかに関係なく、「前のページ」のページ番号を返 します。

Page.start_index()

ページの先頭のオブジェクトの通番を、ペジネータ全体にわたるオブジェクト のリストの通番で返します。通番は 1 から始まります。例えば、ページあたり 2 個のオブジェクトを表示するペジネータで 5 個のオブジェクトをページ分割 している場合、2 ページ目の start_index()3 を返します。

Page.end_index()

ページの末尾のオブジェクトの通番を、ペジネータ全体にわたるオブジェクト のリストの通番で返します。通番は 1 から始まります。例えば、ページあたり 2 個のオブジェクトを表示するペジネータで 5 個のオブジェクトをページ分割 している場合、2 ページ目の end_index()4 を返します。

属性
Page.object_list

ページ上のオブジェクトのリストです。

Page.number

1 から数えたページ番号です。

Page.paginator

ページの結びついている Paginator オブジェクトです。

Django のセキュリティ

このドキュメントは Django のセキュリティ機能の概要です。 Django を使ったサイト をセキュアにするためのアドバイスも含んでいます。

クロスサイトスクリプティング (XSS) 対策

XSS 攻撃は、ユーザが他のユーザのブラウザ内にクライアントサイドスクリプトを挿入 することを可能にするものです。普通これは、悪意のあるスクリプトをデータベースに 保存し、他のユーザに検索、表示させたり、攻撃者の JavaScirpt が実行されるリンク をユーザにクリックさせることによって行われます。しかしながら XSS 攻撃は、デー タがページに含められる前に十分にサニタイズしておかなければ、他の信頼できない データソース、例えばクッキーや Web サービスのようなものから、起こる可能性があ ります。

Django テンプレートを使うとほとんどの XSS 攻撃を防ぐことができます。しかしなが ら Django が提供している防御と制限を理解しておくことが大切です。

Django テンプレートは HTML にとって特に危険な 特定の文字列をエスケープ します。これによって、ユーザはほとんどの悪意ある入 力から保護されますが、完全なフールプルーフではありません。例えば、以下は保護さ れません。

<style class={{ var }}>...</style>

もし var'class1 onmouseover=javascript:func()' がセットされていた ら、作成者不明の JavaScript が実行されることになります。これはブラウザが不完全 な HTML をどのようにレンダするかにも依存します。

また、カスタムテンプレートタグとともに is_safe を使ったり、 :safe テンプレートタグや mark_safe を使ったり、オー トエススケープをオフにしている時には、特に注意することが大切です。

加えて、テンプレートシステムを使って HTML ではない何かを出力しようとしているな ら、エスケープが必要な文字と単語は全く違ったものになります。

また、データベースに HTML を保存する時、特にそのHTMLが取り出されて表示される時 はとても注意深くならなければいけません。

クロスサイトリクエストフォージェリ (CSRF) 対策

CSRF 攻撃は悪意のあるユーザが、別のユーザの知識も同意もなく認証済情報を使った 行為を行えてしまうものです。

Django はほとんどの種類の CSRF 攻撃に対する組込の対策を備えていて、開発者はそ れを適切に 有効化して使う ことができます。しかしながら、他 の制限緩和テクニックと同様、対策に制限をかけることもできます。例えば CSRF モ ジュールを全体的に無効化したり、特定のビューで無効にすることが可能です。開発者 は、自分が何をしているのか分かっている時にだけしかそうすべきではありません。も しもサイトがコントロール不能なサブドメインを持っているなら、他の 制限 もあります。

CSRF 対策の動作 は POST リクエスト中のナンス (nonce) を検証することで成り立っています。これによって悪意のあるユーザが単純にウェブサ イトへのフォームでの POST を「再現」できないようになり、他のログインユーザが知 らずにサブミットしてしまうことを防げます。悪意あるユーザはユーザ個別の (クッ キーを使った) ナンスを知らなければなりません。

そうすることが絶対に必要なのでなければ、ビューを csrf_exempt デコレータで マークしないようにしてください。

SQL インジェクション対策

SQL インジェクションは悪意のあるユーザが任意の SQL コードをデータベース上で実 行できてしまう種類の攻撃です。この結果、レコードが削除されたり、データが漏洩す るといったことが起こりえます。

Django のクエリセットを使うと、出力される SQL は下層のデータベースドライバに よってうまくエスケープされます。しかし、 Django は開発者が 生のクエリ を書いたり カスタム SQL を実行することも許可しています。こ れらの技術はあくまで代替的な手段として使い、ユーザが変更できるパラメータは適切 にエスケープするよう注意しなければなりません。さらに extra() メソッドを使う場合は練習が必要です。

クリックジャッキング対策

クリックジャッキングは悪意のあるサイトがフレームの中に別のサイトを包み込む種類 の攻撃です。この攻撃の結果、疑いを持っていないユーザはターゲットサイトで意図し ない行為を実行させられてしまいます。

Django は クリックジャッキング対策X-Frame-Options middleware のフォームに含んでいます。 これはサポートしているブラウザがフレーム内にサイトを表示することを防ぐものです。 ビュー単位で対策を無効化したり、送信するヘッダの正確な値を設定することができま す。

サードパーティサイトによってフレーム内に表示される必要がない、またはサイトのご く一部でしかそれを許可しないサイトは、このミドルウェアを使うことを強くお勧めし ます。

SSL/HTTPS

全てのケースで現実的ではないかもしれませんが、サイトを HTTPS の背後にデプロイ することは、常にセキュリティ上良いことです。HTTPS を使わない場合、悪意のある ネットワークユーザが認証情報やクライアント・サーバ間でやりとりされる他の情報を 盗聴できてしまいます。そして場合によっては – 積極的な ネットワーク攻撃者 は – どちらかの方向に送られるデータを書き換えてしまいます。

HTTPS による対策が必要であり、サーバで HTTPS を有効にしたいなら、いくつかのス テップで、重要な情報が漏洩しないかをよく考えてください。

  • HTTP でのリクエストが HTTPS にリダイレクトされるように設定してください。

    小さな Django ミドルウェアで可能です。しかし Django アプリケーションがリバー スプロキシの後ろで動いているという一般的な場合の問題があります。 よくあることとして、リバースプロキシは X-Forwarded-SSL ヘッダ (または同 等の何か) を HTTPS での接続に対してセットするように設定されています。そこで このヘッダがなければリクエストが HTTPS ではないことを検知できます。しかしな がら、この方法は常に信頼できるわけではありません。クライアントや悪意のある ネットワーク攻撃者はこのヘッダをセットすることができます。

    そのため、リバースプロキシを使っている場合は、メインの Web サーバを HTTPS に リダイレクトするようにするか、アプリケーションへの HTTP リクエストを無条件に HTTPS にリダイレクトするように設定することをお勧めします。

  • 「セキュア」クッキーを使ってください。

    もしブラウザが最初に HTTP で接続してきたら、これはほとんどのブラウザのデフォ ルトですが、既に存在するクッキーが漏洩してしまいます。このため SESSION_COOKIE_SECURECSRF_COOKIE_SECURETrue に設定するべきです。これらのクッキーを HTTPS 接続でのみ送信するよう にというブラウザへの指示になります。 HTTP ではセッションが使えなくなり、 CSRF 対策によって HTTP での POST データは受け付けられなくなることに注意して ください。 (もし全ての HTTP トラフィック を HTTPS にリダイレクトしているので あれば問題ないでしょう)

Host ヘッダとバーチャルホスティング

Django はクライアントから送られた Host ヘッダを URL の構築に利用することが あります。クロスサイトスクリプティングを防ぐためにこの値をサニタイズしても、あ る環境ではクロスサイトリクエストフォージェリやキャッシュポイズニング攻撃に利用 されてしまいます。そのため Web サーバを以下のように設定することをお勧めします:

  • 渡された HTTP Host ヘッダが期待するホスト名か必ず検証する
  • Host ヘッダのないリクエストを許容しない
  • 全てのバーチャルホストへのリクエストを Django アプリケーションに転送する 設定にしない

加えて、 1.3.1 では、設定上必要であれば X-Forwarded-Host のサポートを明示 的に有効化するように Django は求めます。

さらなるセキュリティのトピック

Django は良いセキュリティ対策を提供していますが、アプリケーションを適切に配備 し、 Web サーバや OS や他のコンポーネントによるセキュリティ対策を利用すること も大切です。

  • Python コードが Web サーバの root 権限外で動作させてください。 Python コード がプレーンテキストで公開されていないか (または意図せず実行されていないか) を 確かめてください。
  • ユーザによるファイルアップロード の全てに気を 使ってください
  • Django は認証ユーザへのリクエストを抑制しません。認証システムへのブルート フォース攻撃を防ぐには Django のプラグインを使うか、これらのリクエストを制限 する Web サーバモジュールの利用を検討してください。
  • サイトがファイルアップロードを許可しているなら、サービス拒否 (DOS) 攻撃を防 ぐため、 Web サーバへのアップロードに制限をかけるよう強く忠告します。 Apache では LimitRequestBody ディレクティブで簡単に設定できます。
  • SECRET_KEY を秘密にしてください。
  • キャッシュシステムやデータベースへのアクセスをファイアウォールを使って制限す るのは良い考えです。

Django オブジェクトのシリアライズ

revision-up-to:17812 (1.4)

Django のシリアライズフレームワークを使うと、 Django オブジェクトを他の形式 に「翻訳」できます。通常、こうした形式はテキストベースで、 Django オブジェ クトをネットワーク越しに伝送するために使われますが、 Django のシリアライザ は任意の形式 (テキストベースもそうでないものも) 扱えます。

See also

もしテーブルに入っているデータをシリアライズされた形式で取り出したいだ けなら、 dumpdata コマンドを使うことができます。

データのシリアライズ

高水準では、データのシリアライズは極めて簡単な操作です:

from django.core import serializers
data = serializers.serialize("xml", SomeModel.objects.all())

serialize 関数の引数には、データのシリアライズに使うフォーマット (シリアライズの形式 参照) と、シリアライズ対象の QuerySet (実際には、第二引数は Django オブジェク トを返す任意のイテレータにできますが、大抵の場合は QuerySet を使うことにな るでしょう)。

シリアライザオブジェクトを直接使ってもかまいません:

XMLSerializer = serializers.get_serializer("xml")
xml_serializer = XMLSerializer()
xml_serializer.serialize(queryset)
data = xml_serializer.getvalue()

シリアライザオブジェクトを直接使うと、以下のようにファイルライクオブジェク ト (もちろん HttpResponse も使えます) に対して直接シ リアライズできるので便利です:

out = open("file.xml", "w")
xml_serializer.serialize(SomeModel.objects.all(), stream=out)

Note

get_serializer() に不明な format を渡すと、 SerializerDoesNotExist が送出されます。

一部のフィールドだけをシリアライズする

一部のフィールドだけをシリアライズしたい場合には、シリアライザに fields 引数を指定します:

from django.core import serializers
data = serializers.serialize('xml', SomeModel.objects.all(), fields=('name','size'))

上の例では、 namesize だけがシリアライズされます。

Note

モデルによっては、フィールドの一部だけをシリアライズすると、そこからデ シリアライズできない場合があります。シリアライズ後のオブジェクトに、モ デル上で必須のフィールドがひとつでも抜け落ちていると、デシリアライザは デシリアライズ後のインスタンスを保存できないでしょう。

継承を行っているモデルインスタンスのシリアライズ

抽象ベースクラス を使って定義したモデルを扱っ ていても、モデルのシリアライズのために特に行うことはありません。単にシリア ライズしたオブジェクトに対してシリアライザを呼び出せば、完全なシリアライズ 済みオブジェクトが出力されます。

ただし、 マルチテーブル継承 を使って定義さ れているモデルを扱う場合、モデルの全てのベースクラスをシリアライズする必要 があります。これは、モデルごとに固有に定義されたフィールドがシリアライズさ れるためです。例えば、以下のようなモデルを考えましょう:

class Place(models.Model):
    name = models.CharField(max_length=50)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField()

ここで、 Restaurant モデルだけをシリアライズしたとします:

data = serializers.serialize('xml', Restaurant.objects.all())

シリアライズ後の出力には、 serves_hot_dogs という属性しか入りません。 ベースクラスの name 属性は無視されるのです。

上の Restaurant インスタンスを完全にシリアライズするには、以下のように して Place モデルもシリアライズする必要があります:

all_objects = list(Restaurant.objects.all()) + list(Place.objects.all())
data = serializers.serialize('xml', all_objects)

データのデシリアライズ

データのデシリアライズもまた、かなり単純な操作です:

for obj in serializers.deserialize("xml", data):
    do_something_with(obj)

見ての通り、 deserialize 関数は serialize 関数と同様、文字列または データストリームを引数にとり、イテレータを返します。

しかしながら、少しだけややこしい部分もあります。 deserialize イテレータ の返すオブジェクトは単純な Django オブジェクト ではなくDeserializedObject という特殊なインスタンスです。このインスタンスは 作成されただけでまだ保存されていないデータであり、リレーションも張られてい ません。

DeserializedObject.save() を呼び出すと、データベースにオブジェクトを保 存します。

上のような仕様から、デシリアライズは、たとえシリアライズされていたデータの 表現形式が現在のデータベースの構成と一致していなかったとしても非破壊的な操 作になるよう保証されています。通常、 DeserializedObject インスタンスの 操作は以下のように行います:

for deserialized_object in serializers.deserialize("xml", data):
    if object_should_be_saved(deserialized_object):
        deserialized_object.save()

すなわち、デシリアライズしたオブジェクトを保存する場合、前もって保存に適し ているかどうかを調べるのが普通のやり方なのです。もちろん、データソースを信 頼できるのなら、単にデータを保存してもかまいません。

Django オブジェクト自体に対するインスペクションは、 deserialized_object.object で行えます。

シリアライズの形式

Django は複数のシリアライズ形式に対応しています。そのうちいくつかではサード パーティモジュールのインストールが必要です。

名前 情報
xml 単純な XML シリアライザです。
json JSON シリアライザ (Django に付属の simplejson を使ったも の) です。
python 「単純な」Python オブジェクト (リスト、辞書、文字列など) の シリアライザです。単体では取り立てて便利ではありませんが、 他のシリアライザのベースになっています。
yaml YAML (YAML Ain’t a Markup Language) へのシリアライザです。 このシリアライザは PyYAML がインストールされている場合のみ 利用できます。
各シリアライズ形式についての注意
json

UTF-8 (や、非 ASCII エンコーディング) でエンコードされたデータを JSON シリ アライザで扱うには、 serialize() のパラメタに ensure_ascii=False を 指定してください。さもないと、出力のエンコードがおかしくなってしまいます。

例:

json_serializer = serializers.get_serializer("json")()
json_serializer.serialize(queryset, ensure_ascii=False, stream=response)

Django のソースコードには simplejson モジュールが付属しています。 ですが、もし (組み込みバージョンのモジュールが付属する) Python 2.6 かそれ以 降のバージョンを使っているなら、 Django は自動的に組み込みの json モジュ ールを使います。Cベースの高速化拡張を含むシステムインストール版や、もっと最 近のバージョンを使っているなら Django に付属しているバージョンの代わりにシス テムバージョンが使われます。

注意してほしいのは、このモジュールを直接使ってシリアライズを実行すると、一 部の Django オブジェクトは何らかの変更が加えられた上で simplejson に渡されて しまうということです。特に、 遅延翻訳オブジェクト をシリアライズする場合は、 特殊なエンコーダ が必要 です。以下のように書くと、うまくいくでしょう:

from django.utils.functional import Promise
from django.utils.encoding import force_unicode

class LazyEncoder(simplejson.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Promise):
            return force_unicode(obj)
        return obj

自然キー (natural keys)

リリースノートを参照してください

外部キーや多対多のリレーションをシリアライズする時の基本方針は、リレーションオ ブジェクトの主キー値をシリアライズすることです。 この方針はたいていのオブジェクトに対してうまくいきますが、特定の状況では難しい 問題を引き起こします。

ContentType を参照する外部キーを 持つオブジェクトのリストを考えてください。オブジェクトをシリアライズしようとす ると、 ContentType を参照する方法がなければいけません。 ContentType オブジェクトはデータベースへの同期処理で Django が自動的に生成 するので、 ContentType の主キーを予測するのは困難です。それはいつ syncdb が実行されたかによって決まるでしょう。このことはオブジェクト を生成する全てのモデル、特に PermissionGroupUser において成り立ちます。

Warning

自動生成されたオブジェクトを、フィクスチャや他のシリアライズされたデータに 含めるべきではありません。フィクスチャの中の主キーが偶然データベースの中の 主キーに一致すると、フィクスチャのロードが効果を持たなくなってしまいます。 もっとありそうなのは、主キーが一致せずにロードが IntegrityError を出して失敗するということです。

これは利便性の問題とも言えます。整数のIDはオブジェクトを参照するのにいつも一番 良い方法というわけではありません。時にはより分かりやすい自然な参照があるかもし れません。

これらの理由から Django は 自然キー を提供します。自然キーは値の タプルで、主キーを使わずにオブジェクトインスタンスを特定するために使うことがで きます。

自然キーのデシリアライズ

次のような2つのモデルを考えてください:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    birthdate = models.DateField()

    class Meta:
        unique_together = (('first_name', 'last_name'),)

class Book(models.Model):
    name = models.CharField(max_length=100)
    author = models.ForeignKey(Person)

通常、 Book のシリアライズ済みデータは著者を参照するのに整数を使います。 例えば JSON では、 Book はこのようにシリアライズされるかもしれません:

...
{
    "pk": 1,
    "model": "store.book",
    "fields": {
        "name": "Mostly Harmless",
        "author": 42
    }
}
...

これは著者を参照するための特に自然な方法とは言えません。著者を参照する主キーの値 を知っていなければなりませんし、主キーの値は変更がなく、予測可能なものでなければ なりません。

しかし、 Person を扱う自然キーを追加すれば、このフィクスチャはより理解しや すいものになります。自然キーの扱いを追加するには、 Person のデフォルトマネ ジャに get_by_natural_key() メソッドを定義してください。 Person の場合、 ファーストネームとラストネームが良い自然キーかもしれません:

from django.db import models

class PersonManager(models.Manager):
    def get_by_natural_key(self, first_name, last_name):
        return self.get(first_name=first_name, last_name=last_name)

class Person(models.Model):
    objects = PersonManager()

    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    birthdate = models.DateField()

    class Meta:
        unique_together = (('first_name', 'last_name'),)

これで Book は Person オブジェクトを参照する自然キーを使えます:

...
{
    "pk": 1,
    "model": "store.book",
    "fields": {
        "name": "Mostly Harmless",
        "author": ["Douglas", "Adams"]
    }
}
...

シリアライズ済みデータをロードしようとすると、 ["Douglas", "Adams"] を実際 の Person オブジェクトの主キーへと解決するために、 Django は get_by_natural_key() を使います。

Note

自然キーに使うフィールドは、オブジェクトを一意に特定することができなけ ればなりません。これは普通、そのモデルがユニーク句を持っていることを意味しま す。(単独のフィールドで unique=True であるか、複数のフィールドに対して unique_together であるか)しかし、データベースレベルでユニークであること は強制されません。実際上ユニークだという確証があれば、それらのフィールドをナ チュラルキーとして使うことができます。

自然キーのシリアライズ

さて、オブジェクトをシリアライズする時に Django に自然キーを発行させるにはど うすれば良いでしょうか。まず、もう一つのメソッドを、今度はモデル自身に追加する必 要があります:

class Person(models.Model):
    objects = PersonManager()

    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    birthdate = models.DateField()

    def natural_key(self):
        return (self.first_name, self.last_name)

    class Meta:
        unique_together = (('first_name', 'last_name'),)

このメソッドは常に自然キーのタプルを返すべきです。この例では (first name, last name) です。それから、 serializers.serialize() を呼ぶ時 に use_natural_keys=True 引数を渡します:

>>> serializers.serialize('json', [book1, book2], indent=2, use_natural_keys=True)

use_natural_keys=True が指定されると、 Django はこのメソッドを定義している型の オブジェクト参照をシリアライズするために、 natural_key() メソッドを使います。

シリアライズデータを生成するために dumpdata を使う時は、 –natural コマンドラインフラグを使います。

Note

natural_key()get_by_natural_key() の両方を定義する必要はありませ ん。シリアライズの時に自然キーを出力させたくなく、しかも自然キー をロードすることもできるようにするには、 natural_key() メソッドを実装しな いということも可能です。

逆に言えば、(何かの変わった理由で)シリアライズ時に自然キーを出力させ たく、かつこれらのキーを出力できないようにしたければ、 get_by_natural_key() メソッドを定義するだけにすれば良いのです。

シリアライズ中の依存関係

自然キーは参照を解決するためにデータベースのルックアップに依存するので、参 照される前にデータが存在することが大切です。自然キーで forward refernce を作ることはできません。自然キーをデータに含める前に、参照したいデータが存 在していなければならないのです。

この制限に適応させるため、 dumpdata--natural オプシ ョンを使うと、どんなモデルでも標準的な主キーオブジェクトでのシリアライズより前に natural_key() メソッドでシリアライズされます。

しかし、いつもこれで充分とは限りません。外部キーか自然キーによってナチュラ ルキーの一部である別のオブジェクトを参照している時には、シリアライズされたデータ のなかでは依存される側のオブジェクトが先に出現することを保証できなければなりませ ん。

この順序を保証するため、 natural_key() メソッドに依存関係を定義できます。 natural_key() メソッド自体に dependencies 属性を設定するのです。

例えば、 上の例で見た Book モデルに自然キーを与えましょう:

class Book(models.Model):
    name = models.CharField(max_length=100)
    author = models.ForeignKey(Person)

    def natural_key(self):
        return (self.name,) + self.author.natural_key()

Book の自然キーは名前と著者の組み合わせです。つまり PersonBook より先にシリアライズされる必要があります。この依存関係を定義するため、 もう一行加えます:

def natural_key(self):
    return (self.name,) + self.author.natural_key()
natural_key.dependencies = ['example_app.person']

この定義により、どんな Person オブジェクトも Book オブジェクトより先に シリアライズされることが保証されます。逆に、 Book を参照するどんなオブジェ クトも、 PersonBook の両方がシリアライズされた後にシリアライズされ るでしょう。

Django の設定

revision-up-to:17812 (1.4)

Django の設定ファイルには、インストールした Django の使う全ての設定が入って います。このドキュメントでは、各設定の役割と、どのような設定を利用できるか について説明します。

基礎

設定ファイルはモジュールレベルの変数の入った単なる Python モジュールです。

設定の例をいくつか示します:

DEBUG = False
DEFAULT_FROM_EMAIL = 'webmaster@example.com'
TEMPLATE_DIRS = ('/home/templates/mike', '/home/templates/john')

設定ファイルは Python モジュールなので、以下のような性質を備えています:

  • Python の構文エラーが入っていてはなりません。

  • 通常の Python 構文を使って動的に値を設定できます。 例えば:

    MY_SETTING = [str(i) for i in range(30)]
    
  • 他の設定ファイルから値を import できます。

設定ファイルの特定

Django を使う場合、どの設定を使っているのかを Django に教えなければなりませ んが、これには環境変数 DJANGO_SETTINGS_MODULE を使います。

DJANGO_SETTINGS_MODULE は Python のモジュールパス構文、たとえば mysite.settings のようにします。設定モジュールは Python の モジュール検索パス になければなりません。

django-admin.py ユーティリティ

django-admin.py を使う場合、環境変数をあらかじめ 指定しておくか、ユーティリティを起動する度に設定モジュールを明示的に渡しま す。

例 (Unix Bash シェル):

export DJANGO_SETTINGS_MODULE=mysite.settings
django-admin.py runserver

例 (Windows コマンドプロンプト):

set DJANGO_SETTINGS_MODULE=mysite.settings
django-admin.py runserver

コマンドライン引数で設定モジュールを指定するには --settings を使います:

django-admin.py runserver --settings=mysite.settings
サーバ (mod_wsgi) の設定

実際のサーバ環境では、 WSGIアプリケーショにどの設定モジュールを使うのか教え る必要があります。これには os.environ を使います:

import os

os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

より詳しい情報やその他Django WSGIアプリケーションに一般的な事項に関しては mod_wsgiでDjango を使うためのドキュメント を参照してください。

デフォルトの設定

Django の設定ファイルでは、特に必要のない限り設定をおこなう必要はありません。 各々の設定には注意深く決められたデフォルト値が入っています。デフォルト値は django/conf/global_settings.py ファイルに収められています。

Django が設定をコンパイルする際には、以下のようなアルゴリズムを使います:

  • global_settings.py から設定を読みだします。
  • 指定の設定ファイルから設定を読み出し、 グローバルな設定をオーバライドします。

設定ファイルから global_setting を import するのは無駄で、 必要ありません

変更結果を確かめる

デフォルトの設定と自分の設定の違いを確かめる簡単な方法があります。 python manage.py diffsettings を実行すると、現在の設定と Django のデフォ ルト設定との違いを表示します。

詳しくは diffsettings のドキュメントを参照してください。

Python コード内で設定を参照する

自作の Django アプリケーションから設定を参照するには、 django.conf モ ジュールから settings オブジェクトを import します:

from django.conf import settings

if settings.DEBUG:
    # Do something

django.conf.settings はモジュールではなくオブジェクトです。このため、 個々の設定は別々に import できません:

from django.conf.settings import DEBUG  # This won't work.

また、 global_settings や自作の設定ファイルを直接 import しては ならない ので注意して下さい。 django.conf.settings はデフォルト設定と サイト固有の設定を抽象化しており、単一のインタフェースで設定を提供するとと もに、設定を使うコードとユーザの設定ファイルの置き場所とを脱カップリングし ています。

実行時に設定を変更する

実行時に設定を変更してはなりません。たとえば、ビューの中で以下のような操作 を行ってはなりません:

from django.conf import settings

settings.DEBUG = True   # やってはダメ!

設定を書いてよいのは設定ファイルの中だけです。

セキュリティ

設定ファイルにはデータベースのパスワードのような重要な情報が入っているので、 設定ファイルへのアクセスはできるだけ制限してください。例えば、設定ファイル のパーミッションを、Web サーバを駆動しているユーザとあなただけが読み書きで きるように変更してください。共有ホスティング環境で運用するような場合、これ は極めて重要な事項です。

利用可能な設定

利用可能な設定は setting リファレンス を参照してください。

設定項目を自作する

設定項目は自由に自作でき、 Django アプリケーションから利用できます。いくつ か取り決めがあるので従うようにして下さい:

  • 設定名は全て大文字にします。
  • 既に存在する設定の再発明はやめましょう。

DJANGO_SETTINGS_MODULE を使わない設定方法

場合によっては、環境変数 DJANGO_SETTINGS_MODULE をバイパスしたい場合も あるでしょう。たとえばテンプレートシステムを単体で使いたい場合、設定ファイ ルの在処を指すような環境変数を取り入れたくはないかもしれません。

こうした場合のために、 Django の設定は手動で行えるようになっています。手動 の設定には django.conf.settings.configure() を呼び出します。

django.conf.settings.configure(default_settings, **settings)

例えば:

from django.conf import settings

settings.configure(DEBUG=True, TEMPLATE_DEBUG=True,
    TEMPLATE_DIRS=('/home/web-apps/myapp', '/home/web-apps/base'))

configure() には必要なだけキーワードを指定してかまいません。各キーワー ドは設定とその値を表します。各引数名は全て大文字で、上記の各設定名と同じに せねばなりません。 configure() に渡さなかった指定が後で必要になった場合、 Django はデフォルトの設定値を使います。

ほとんどの場合、この方法で Django を設定する必要がありますし、より大規模な アプリケーション内でフレームワークの一部を使う場合には、実際上記の方法がお 勧めです。

settings.configure() で設定を行った場合、 Django はプロセスの環境変数に 何ら変更を加えません (理由は前述の TIME_ZONE の説明を参照してください。) これらのケースでは、ユーザがすでに環境変数を自由に制御できるものと仮定して います。

カスタムのデフォルト設定

デフォルト設定を django.conf.global_settings 以外の場所から取り込みたい 場合、モジュールやクラスの中で configure() を呼び出し、 default_settings 引数 (または最初の固定引数) でデフォルト設定を渡せます。

以下の例では、デフォルトの設定を myapp_defaults から取り出し、 DEBUG の設定を myapp_defaults の設定に関わらず True になるよう にしています:

from django.conf import settings
from myapp import myapp_defaults

settings.configure(default_settings=myapp_defaults, DEBUG=True)

以下の例では、 myapp_defaults を固定引数にしており、上の例と同じ意味に なります:

settings.configure(myapp_defaults, DEBUG = True)

通常、このようなやり方でデフォルト値をオーバライドする必要はありません。 Django は十分に扱いやすい設定値をデフォルト値にしていて、ほぼ問題なく利用で きます。新たなデフォルトモジュールを渡すと、そのモジュールは Django のデフォ ルトを 完全に 置き換えてしまうため、 import している側のコードで必要な全 ての設定値を指定せねばならないので注意して下さい。設定の完全なリストは django.conf.global_settings にあります。

configure() または DJANGO_SETTINGS_MODULE のいずれかが必要です

環境変数 DJANGO_SETTINGS_MODULE を指定しない場合、設定を利用する何らか のコードが実行される前に、 必ず configure() を呼び出しておかねばなり ません。

環境変数 DJANGO_SETTINGS_MODULE を指定せず、 configure() も呼び出さ なかった場合、 Django は最初に設定にアクセスした時点で ImportError 例外を送出します。

環境変数 DJANGO_SETTINGS_MODULE を指定して、何らかの設定にアクセスした 後に configure() を呼び出すと、 Django は設定がすでに行われている旨の RuntimeError 例外を送出します。

また、 configure() を何度も呼び出したり、何らかの設定にアクセスした後に configure() を呼び出してもエラーになります。

つまりは、「 configure()DJANGO_SETTINGS_MODULE のどちらかを設定 してください」ということです。両方設定してはなりませんし、両方とも忘れても なりません。

シグナル

revision-up-to:17812 (1.4)

Django には「シグナルディスパッチャ (signal dispatcher)」が組み込まれていま す。シグナルディスパッチャにより、アプリケーションをフレームワークから脱カッ プリングしつつ、フレームワークのどこかで起きたアクションに応じた通知を受け られます。簡単にいえば、シグナルによって、ある「 送信側(sender) 」から 複数の「 受信側(receiver) 」に向けて、何らかのアクションが起きたことを通 知できるのです。シグナルは、たくさんのコードが同じイベントを待ち受けるよう な状況で特に便利です。

Django は、自分自身の特定のアクションを通知するための 組み込みシグナ ル を提供しています。組み込みシグナルの中には、以下のような 便利なものがあります:

組み込みシグナルの全容と各々の解説は、 組み込みシグナルのドキュメント で解説しています。

シグナルは 自分で定義したり送信したり できます。詳しくは以下を参照し てください。

シグナルを待ち受ける

シグナルを受信するには、シグナルが送信されたときに呼び出される レシーバ (receiver) 関数を、 Signal.connect() メソッドを使って登録する必要が あります。

Signal.connect(receiver[, sender=None, weak=True, dispatch_uid=None])
Parameters:
  • receiver – シグナルに結びつけられるコールバック関数を指定します。 詳細は レシーバ関数 を参照してください。
  • sender – シグナルを受け取るための特定のセンダを指定します。詳細は 特定のセンダから送信されたシグナルだけを結びつける を参照してください。
  • weak – デフォルトで Django は、シグナルハンドラを弱参照として保持 します。なのでレシーバがローカル関数の場合、ガベージコレクトされる恐れが あります。これを防ぐにはシグナルの connect() メソッドを呼び出す際に weak=False を渡してください。
  • dispatch_uid – ユニークな識別子。シグナルのレシーバに重複するシグナル が送られる場合に備えたものです。詳細は 重複するシグナルを防ぐ を参照してください。

HTTP リクエストの処理が終ったときに呼び出されるシグナルのレシーバを登録して、 この仕組みを見てみましょう。この例では、 request_finished シグナルをレシーバに結びつけます。

レシーバ関数

まず、レシーバ関数を定義します。レシーバは通常の Python の関数やメソッドと して定義します:

def my_callback(sender, **kwargs):
    print "Request finished!"

この関数は固定引数の sender と、ワイルドカードで表現された任意のキーワー ド引数 (**kwargs) をとります。シグナルハンドラは、全てこの形式の引数を とらねばなりません。

sender については 後で 説明するとして、今はまず **kwargs に注目しましょう。シグナルはすべてキーワード引数を伴い、キーワー ド引数の内容はいつでも変更される可能性があります。 request_finished の場合、ドキュメントにキーワー ド引数をもたないと明記されているので、シグナルハンドラを my_callback(sender) と書いていいと思いがちです。

しかしこれは誤っています。実際、 my_callback(sender) のように定義すると Django はエラーを送出します。というのも、将来シグナルに引数が追加されるかも しれず、そのときにもレシーバは新たに追加された引数を扱えねばならないからで す。

レシーバ関数を結びつける

レシーバをシグナルに結びつけるには 2 つの方法があります。手動での接続方法は 以下のようになります:

from django.core.signals import request_finished

request_finished.connect(my_callback)

あるいは、 receiver デコレータを使う方法があります。レシーバを定義するときに 使います:

from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print "Request finished!"

これで、 my_callback 関数は、リクエストの処理が終了するたびに呼び出され ます。

リリースノートを参照してください

receiver デコレータは Django 1.3 で追加されました。

シグナル処理のコードはどこにおけばよいのですか?

シグナルの処理や登録のためのコードは、どこでも好きな場所に置けます。 とはいえ、自分の登録したいシグナルが送信されるよりも前に、コードの入っ ているモジュールを早々に import しておきたいいでしょう。そのため、シグ ナルハンドラの登録は models.py に置くのがよいでしょう。

特定のセンダから送信されたシグナルだけを結びつける

シグナルには何度も送信されるものがありますが、その中でも特定のサブセットだ けを受け取りたい場合もあるでしょう。例えば、モデルインスタンスが保存される ときに送信される django.db.models.signals.pre_save を考えましょう。 大抵は、シグナルを受信したいのは すべての モデルの保存時ではなく、 特定の モデルの保存時のはずです。

こうしたケースのために、特定のセンダから送られるシグナルに対してレシーバを 登録できます。 django.db.models.signals.pre_save の場合、センダは インスタンスを保存しようとするモデルなので、以下のようにして、特定のモデル に対してのみシグナルを受信させられます:

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel

@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs):
    ...

これで、保存されるインスタンスが MyModel のインスタンスであるときだけ、 my_handler 関数が呼び出されます。

センダに入るオブジェクトは、シグナルによって異なります。個々のシグナルにつ いての情報は 組み込みシグナルのドキュメント を参照して ください。

重複するシグナルを防ぐ

いくつかの状況では、シグナルに結びつけたモジュールが複数回インポートされます。 これはレシーバ関数が 2 回以上登録されている可能性があり、 1 つのシグナルイベント が複数回呼び出されています。

この振る舞いに問題があるとき (例えばモデルが保存されたときにメールを送るシグナル を使うなど) は、ユニークな識別子である dispatch_uid 引数をレシーバ関数に 渡してください。普通この識別子は文字列ですが、ハッシュ可能オブジェクトも使え ます。個々のユニークな dispatch_uid 値のため、レシーバ関数はシグナルに 1 度 だけ結び付けられます。

from django.core.signals import request_finished

request_finished.connect(my_callback, dispatch_uid="my_unique_identifier")

シグナルの定義と送信

自分のアプリケーション内でも、シグナルのインフラストラクチャを使ったり、独 自のシグナルを提供したりできます。

シグナルを定義する
class Signal([providing_args=list])

シグナルは全て django.dispatch.Signal のインスタンスです。 providing_args は、シグナルがリスナに対して提供する引数の名前が入ったリ ストです。

例えば:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

上のコードは pizza_done シグナルを作成し、このシグナルが toppingsize という引数をもたらすことを宣言しています。

このリストはいつでも変更できるので、最初の時点で正確に API を定義しておく必 要はありません。

シグナルを送信する

Django にはシグナルを送信する方法が 2 つあります。

Signal.send(sender, **kwargs)
Signal.send_robust(sender, **kwargs)

シグナルを送信するには Signal.send()Signal.send_robust() を 呼び出します。 sender を必ず指定し、必要に応じて追加の引数を指定します。

例えば、 pizza_done シグナルを送信するには、以下のように書きます:

class PizzaStore(object):
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self, toppings=toppings, size=size)
        ...

send()send_robust() の両方とも、要素数 2 のタプルのリスト [(receiver, response), ... ] を返します。呼び出されたレシーバ関数とその レスポンス値が、リストになっています。

send()send_robust() の違いは、レシーバ関数から送出された例外をどの ように処理するかです。 send() はレシーバから送出される例外を一切 捕らえま せん 。単純にエラーが伝播されます。レシーバがエラーを起こすと、シグナルは通知 されません。

send_robust() は Python の Exception クラスから送出されるエラーを捕ら えます。シグナルがレシーバに通知されることを保証します。レシーバがエラーを送出 するとエラーインスタンス (そのレシーバとエラー内容のタプル) が返されます。

シグナルとの接続を断つ

Signal.disconnect([receiver=None, sender=None, weak=True, dispatch_uid=None])

シグナルとレシーバの接続を断つには Signal.disconnect() を呼び出します。 引数は Signal.connect() に述べられている通りです。

receiver 引数には、接続を断ちたい登録済みのレシーバを指定します。 レシーバを識別するために dispath_uid 使われている場合、 receiverNone で構いません。

Deprecated features

汎用ビュー

revision-up-to:17812 (1.4)
リリースノートを参照してください

Note

Django 1.3 から、クラスベースの汎用ビューが採用されたので、関数ベースの汎用 ビューは廃止されました。クラスベースビューの トピックガイド詳細なリファレンス に記述されています。

Web アプリケーションの作成は、同じパターンを何度も何度も繰り返し書くことに なるため、退屈なものです。 Django は、こうした単調作業をモデルやテンプレー トのレイヤで軽減しようとしていますが、 Web 開発者はビューレベルでも退屈さを 感じています。

Django の 汎用ビュー (generic views) はその苦労を無くすために開発されま した。ビューの開発時に見かける、特定の共通するイディオムとパターンを汎用ビュー という形で抽象化しています。余計なコードを書かずによく定義されるビューを素早く 実装できます。

我々はオブジェクトのリスト表示などの、ありふれたタスクを知っています。 任意の オブジェクトをリスト表示するコードも提供できます。その上、リスト表示させたい モデルは URLconf に追加の引数として渡せます。

Django の汎用ビューで以下のようなことができます:

  • 別のページへリダイレクトし、与えられたテンプレートをレンダリングするような、 よくある簡単なタスクの処理。
  • リストと単一オブジェクトの詳細ページを表示。カンファレンスを管理するアプリケー ションを作っているなら、 talk_list ビューと registerd_user_list ビュー にリストビューを、単一の発表に関するページに詳細ビューが使えます。
  • 日付ベースのオブジェクトを年/月/日のアーカイブで表示。詳細と最新ページで 関連付けて表示します。 Django のブログ (http://www.djangoproject.com/weblog/) の年月日ごとのアーカイブはこれで作られています。
  • 認証あり、または無しでユーザにオブジェクトを生成、更新、削除を許可。

汎用ビューは開発者が遭遇する、よくあるタスクを果たすための簡単なインターフェース を提供しています。

汎用ビューを使う

これらビューはすべて、 URLconf ファイルに設定の入った辞書を作成し、 URLconf で URL パターンを記述しているタプルの 3 つめのメンバにその辞書を渡せば使えます。

例えばここでは、静的な “about” ページを提示するために使えるシンプルな URLconf を 示します:

from django.conf.urls import patterns, url, include
from django.views.generic.simple import direct_to_template

urlpatterns = patterns('',
    ('^about/$', direct_to_template, {
        'template': 'about.html'
    })
)

これは一見、ちょっとした “魔法” のように見えるかもしません。だってほら、コー ド無しのビューですよ!実際には direct_to_template ビューは単に、特別なパ ラメータの入った辞書から情報を取得し、レンダリングに使用しています。

汎用ビューは独自のビュー内で再利用できます。汎用ビューは、その他ビューと同じよう に普通のビュー関数だからです。例として、 “about” を拡張して静的にレンダリングさ れた about/<whatever>.html にURL /about/<whatever>/ を対応させてみましょ う。まずは、ビュー関数を指定するように URLconf を変更します:

from django.conf.urls import patterns, url, include
from django.views.generic.simple import direct_to_template
from books.views import about_pages

urlpatterns = patterns('',
    ('^about/$', direct_to_template, {
        'template': 'about.html'
    }),
    ('^about/(\w+)/$', about_pages),
)

次に about_pages ビューを書きましょう:

from django.http import Http404
from django.template import TemplateDoesNotExist
from django.views.generic.simple import direct_to_template

def about_pages(request, page):
    try:
        return direct_to_template(request, template="about/%s.html" % page)
    except TemplateDoesNotExist:
        raise Http404()

ここでは direct_to_template をほかの関数と同じように扱っています。 direct_to_templateHttpResponse をそのまま返すので、戻り値を単純にそ のまま返せます。唯一トリッキーでやっかいなのが、存在しないテンプレートを扱ってい る点です。存在しないテンプレートがサーバエラーを引き起こさないように TemplateDoesNotExist 例外をキャッチし、代わりに404エラーを返しています。

セキュリティ上の脆弱性はありますか?

目ざとい読者ならセキュリティホールの可能性に気がついてるかもしれません。ブラ ウザから補間されたコンテンツを使ってテンプレート名を構築しているからです (template="about/%s.html" % page) 。一見すると、古典的な ディレクトリト ラバーサル の脆弱性のようです。しかし本当でしょうか?

そうではありません。たしかに、悪意をもって作成された page の値なら、 ディレクトリトラバーサルを引き起こす可能性があります。しかし、 page の値はリクエストURLから取得されますが、必ずしもすべての値が受け入れられるわ けではありません。鍵は URLconf にあります。正規表現 \w+page の URL の一部とマッチさせるために使っています。 \w はアルファベットと数字の み受け付けます。なので、悪意ある文字列 (ここではドットやスラッシュなど) は ビュー自体に到達する前に、 URL リゾルバに拒否されます。

オブジェクトの汎用ビュー

direct_to_template は確かに便利です。しかし、 Django の汎用ビューが真価を 発揮するのは、データベースの内容についてビューを提示するときです。驚くほど簡単に オブジェクトのリスト、詳細ビューを生成できる組み込みの汎用ビューが、 Django には少数付属しています。それらはよくあるタスクだからです。

それでは汎用ビューの 1 つ、 “オブジェクトリスト (object list)” ビューを見てみま しょう。以下のようなモデルを使います:

# models.py
from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    def __unicode__(self):
        return self.name

    class Meta:
        ordering = ["-name"]

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField('Author')
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

全ての出版社 (publisher) のリストページを構築するため、以下のような URLconf を 使います:

from django.conf.urls import patterns, url, include
from django.views.generic import list_detail
from books.models import Publisher

publisher_info = {
    "queryset" : Publisher.objects.all(),
}

urlpatterns = patterns('',
    (r'^publishers/$', list_detail.object_list, publisher_info)
)

書くべき Python コードは以上です。しかしテンプレートも書く必要があります。追加の 引数の辞書に template_name キーを含めることにより、どのテンプレートを使用す るべきであるか object_list ビューに明示的に伝えることができます。明示的なテ ンプレートがない場合 Django は、オブジェクトの名前からテンプレートを推論します。 今回の場合、推論されるテンプレートは "books/publisher_list.html" となるで しょう。 “books” という部分はモデルを定義しているアプリケーションの名前からきて います。 “publisher” は単にモデル名が lowercase になったものです。

このテンプレートは、 object_list 変数を含むコンテキストに対してレンダリング されます。 object_list はすべての Publisher オブジェクトからなります。とても シンプルなテンプレートにするなら以下のようになるでしょう:

{% extends "base.html" %}

{% block content %}
    <h2>Publishers</h2>
    <ul>
        {% for publisher in object_list %}
            <li>{{ publisher.name }}</li>
        {% endfor %}
    </ul>
{% endblock %}

本当にこれだけです。汎用ビューに渡される “info” 辞書を変更することで、クールな 機能をすべて使用できます。すべての汎用ビューとオプションの詳細は generic views reference に記されています。このドキュ メントの残りでは、よくある汎用ビューのカスタマイズ、拡張の方法を記しています。

汎用ビューの拡張

疑いようも無く、汎用ビューを使用すると開発スピードは大幅に上がります。しかし多 くのプロジェクトでは、汎用ビューでは物足りないときがあります。確かに、新米の Django 開発者からくる質問で典型的なのは、汎用ビューをより幅広い状況で扱うことに ついてです。

幸いほぼすべてのケースで、汎用ビューを簡単に拡張して、より大きいユースケースを 処理するようにできます。通常これらの状況は、以下のセクションで扱うごく少数の パターンに分類できます。

“フレンドリー” なテンプレートコンテキストを作る

サンプルの出版社リストテンプレートでは、 object_list 変数にすべての 書籍 (book) オブジェクトが格納されていると思ってしまうかもしれません。現状でも うまく動作しますが、テンプレートの作者にとって “フレンドリー” ではありません。 テンプレート作者は、ここでは出版社のことだけを知っているべきです。より良い変数名は publisher_list です。変数の内容がかなり明らかになっています。

template_object_name 引数を変更することで、簡単に object_list の名前を 変えられます:

publisher_info = {
    "queryset" : Publisher.objects.all(),
    "template_object_name" : "publisher",
}

urlpatterns = patterns('',
    (r'^publishers/$', list_detail.object_list, publisher_info)
)

便利な template_object_name を提供するのは常によいことです。テンプレートの デザインを担当する同僚は、あなたに感謝することでしょう。

追加のコンテキスト

汎用ビューで提供されるもの以上に、追加の情報を提示したいときがあります。例えば、 各出版社の詳細ページに、書籍の全リストを表示したいときなどです。汎用ビュー object_detail はコンテキストに Publisher オブジェクトを提供していますが、 テンプレートに追加の情報を与えることはできなさそうです。

しかしそうではありません。すべての汎用ビューは追加のパラメータ extra_context をとります。これは追加オブジェクトの辞書で、テンプレートコンテキストに追加され ます。書籍の全リストを詳細ビューに提供するには、以下のように info 辞書を使い ます。

from books.models import Publisher, Book

publisher_info = {
    "queryset" : Publisher.objects.all(),
    "template_object_name" : "publisher",
    "extra_context" : {"book_list" : Book.objects.all()}
}

これでテンプレートコンテキストで {{ book_list }} が使えるようになります。 このパターンは、汎用ビューのテンプレートに任意の情報を渡すために使えます。非常に 便利です。

しかし実際には、微妙なバグがあります。見つけられました?

その問題は extra_context 中のクエリが評価されるときに関係します。この例で は、 URLconf に Book.objects.all() を置いているので、クエリは 1 度だけ (URLconf が最初にロードされるとき) 評価されます。書籍を追加か削除すれば、 Web サーバをリロードするまで変更が反映されません。 (クエリセットが、いつキャッ シュ、評価されるかついては キャッシュとクエリセット を参照してください) 。

Note

この問題は汎用ビューの queryset 引数には当てはまりません。 特定の QuerySet は 絶対に キャッシュすべきでないと Django は知っています。 汎用ビューはビューがそれぞれレンダリングされるときに、キャッシュを消去して くれます。

解決策は、値の代わりに extra_context でコールバックを使うことです。 extra_context に渡される呼び出し可能オブジェクト (つまり関数) は、ビューが レンダリングされたときに (1 度だけではなく) 評価されます。明示的に定義した関数を 使います:

def get_books():
    return Book.objects.all()

publisher_info = {
    "queryset" : Publisher.objects.all(),
    "template_object_name" : "publisher",
    "extra_context" : {"book_list" : get_books}
}

明示性に欠けるも、短く書く方法もあります。 Book.objects.all 自体が呼び出し 可能なので、それを利用します:

publisher_info = {
    "queryset" : Publisher.objects.all(),
    "template_object_name" : "publisher",
    "extra_context" : {"book_list" : Book.objects.all}
}

Book.objects.all の後ろに丸括弧が足りませんね。実際に関数は呼び出されて いません (汎用ビューが後で呼び出します)。

オブジェクトのサブセットを表示

さて、ずっと使ってきた queryset キーを詳しく見ていきましょう。ほとんどの 汎用ビューは queryset 引数を取ります。それはビューがどのオブジェクト のセットを表示すべきかを指定します。 ( QuerySet オブジェクトのについては クエリを生成する 、詳細は 汎用ビューのリファレンス を参照してください)。

簡単な例として、出版日 (publication date) 順の書籍のリストを最新のものから取得 してみます:

book_info = {
    "queryset" : Book.objects.all().order_by("-publication_date"),
}

urlpatterns = patterns('',
    (r'^publishers/$', list_detail.object_list, publisher_info),
    (r'^books/$', list_detail.object_list, book_info),
)

かなり簡単な例ですが、うまく考えを表しています。もちろんオブジェクトを再整理する 以上のことをしたいでしょう。特定の出版社についての書籍を渡したい場合も、同じ テクニックが使えます:

acme_books = {
    "queryset": Book.objects.filter(publisher__name="Acme Publishing"),
    "template_name" : "books/acme_list.html"
}

urlpatterns = patterns('',
    (r'^publishers/$', list_detail.object_list, publisher_info),
    (r'^books/acme/$', list_detail.object_list, acme_books),
)

フィルタされた queryset 以外に、テンプレート名を指定しています。そうしな いと、汎用ビューは同じテンプレートを “ありきたりな” オブジェクトリストとして使い 回します。たぶん期待とは違うことでしょう。

これは、ある出版社固有の書籍を扱ううえでエレガントな方法ではありません。他の 出版社のページを追加したいなら、 URLconf に手動で追記する必要があるからです。 追記したうちのいくつかは不当 (unreasonable) になるでしょう。詳しくは次のセク ションで扱います。

Note

/books/acme/ をリクエストするの際に 404 になったときは、 ‘ACME Publishing’ という名の Publisher が実際に存在するか確かめてください。 こういったケースに備えて、汎用ビューは allow_empty というパラメータを 持っています。詳細は 汎用ビューのリファレンス を参照してください。

ラッパー関数で多重フィルタリング

他によくあるニーズは、 URL のキーでオブジェクトをフィルタしてから、オブジェクト をリストページに渡すことです。すでに出版社名は URLconf にハードコードしてい ますが、ある任意の出版社について書籍をすべて表示するビューを書きたいなら、どう しますか? object_list 汎用ビューを “ラップ (wrap)” して大量のコードを手書き することを避けられます。いつも通り、 URLconf から書きます:

from books.views import books_by_publisher

urlpatterns = patterns('',
    (r'^publishers/$', list_detail.object_list, publisher_info),
    (r'^books/(\w+)/$', books_by_publisher),
)

次に、 books_by_publisher ビュー自体を書きます:

from django.http import Http404
from django.views.generic import list_detail
from books.models import Book, Publisher

def books_by_publisher(request, name):

    # publisher を取得 (見つからなければ 404 エラーを返します)。
    try:
        publisher = Publisher.objects.get(name__iexact=name)
    except Publisher.DoesNotExist:
        raise Http404

    # 重労働には object_list view ビューを使います。
    return list_detail.object_list(
        request,
        queryset = Book.objects.filter(publisher=publisher),
        template_name = "books/books_by_publisher.html",
        template_object_name = "books",
        extra_context = {"publisher" : publisher}
    )

汎用ビューはとくに特別なものでもないので、これで動作します。単なる Python の関数 です。他のビューのように、汎用ビューは引数のセットを期待し、 HttpResponse オブジェクトを返します。このように、汎用ビューを小さな関数でラップするのは非常に 簡単です。ラッパー関数は、汎用ビューに引き渡す前 (もしくは後。詳細は次のセクション で) に追加の処理をします。

Note

先の例では、表示されている Publisher オブジェクトを extra_context に 渡しています。この性質のラッパーにおいては良いアイディアです。どの “親” オブジェクトが現在閲覧されているかをテンプレートに知らせられるかれです。

追加の処理をさせる

最後の共通パターンは、汎用ビューを呼び出す前か後に、追加の処理をさせることです。

Author オブジェクト中に last_accessed フィールドがあると想像してください。 著者 (author) が最後に問い合わせされた時間を記録します:

# models.py

class Author(models.Model):
    salutation = models.CharField(max_length=10)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()
    headshot = models.ImageField(upload_to='/tmp')
    last_accessed = models.DateTimeField()

object_detail 汎用ビューはもちろん、このフィールドについては知りません。 しかし再び、このフィールドの更新を維持するためのカスタムビューを書けます。

初めに、カスタムビューを指定するために URLconf に著者の詳細に関する 1 行を追加 します:

from books.views import author_detail

urlpatterns = patterns('',
    #...
    (r'^authors/(?P<author_id>\d+)/$', author_detail),
)

そしてラッパー関数を書きます:

import datetime
from books.models import Author
from django.views.generic import list_detail
from django.shortcuts import get_object_or_404

def author_detail(request, author_id):
    # Author を取得 (見つからなければ 404 エラーを返します)。
    author = get_object_or_404(Author, pk=author_id)

    # 最終アクセス日時を記録します。
    author.last_accessed = datetime.datetime.now()
    author.save()

    # 詳細ページを表示します。
    return list_detail.object_detail(
        request,
        queryset = Author.objects.all(),
        object_id = author_id,
    )

Note

実際には、このコードには books/author_detail.html テンプレートが必要 です。

汎用ビューのレスポンスを変更するために、同じイディオムが使えます。著者リストの プレーンテキスト版をダウンロード可能にするには、以下のようなビューが使えます:

def author_list_plaintext(request):
    response = list_detail.object_list(
        request,
        queryset = Author.objects.all(),
        mimetype = "text/plain",
        template_name = "books/author_list.txt"
    )
    response["Content-Disposition"] = "attachment; filename=authors.txt"
    return response

これで動作するのは、汎用ビューがシンプルな HttpResponse オブジェクトを返す からです。 HttpResponse オブジェクトを辞書のように扱って、 Http セッダを設定 できます。この Content-Disposition の編集によって、ブラウザにページ表示する 代わりに、ダウンロードと保存するよう指示します。

HOWTO ガイド

revision-up-to:17812 (1.4)

このセクションでは、「〜するにはどうしたらいいですか?」という種の質問に対 する回答を扱っています。 HOWTO ガイドでは、それぞれの問題をあまり深く掘り下 げて説明しません。詳しい話題は、 Django を使うAPI リファレンス で扱っています。とはいえ、ここにあるガイドを読めば、よくある作業を簡単に実 現できるはずです。

Apache での認証に Django のユーザデータベースを使う

revision-up-to:17812 (1.4)

Warning

mod_python のサポートは、 Django で廃止予定です。廃止された時点で、 認証用のメソッドは Django で提供されなくなります。コミュニティーとして は、 WSGI ミドルウェアやその他のアプローチを使用した代替案を提案して います。

Apache を使っていると、同期を保ちながら複数の認証データベースを維持するとい う問題によくぶつかります。 Apache の認証を Django の 認証システム で行えば、以下のような処理を実現できます:

  • 認証ユーザだけを対象に、静的ファイル/メディアファイルを Apache から 直接提供できます。
  • 特定のパーミッションを持つ Django ユーザだけに Subversion リポジト リへのアクセスを許すよう認証をかけられます。
  • mod_dav で作成した WebDAV 共有への接続を特定ユーザに許可できます。

Apache の設定

Django の認証データベースを Apache 設定ファイルからチェックするには mod_python の標準の Auth* および Require ディレクティブと共に、 PythonAuthenHandler ディレクティブを使います:

<Location /example/>
    AuthType Basic
    AuthName "example.com"
    Require valid-user

    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
    PythonAuthenHandler django.contrib.auth.handlers.modpython
</Location>

Apache 2.2 で認証ハンドラを使う場合

Apache 2.2 を使っている場合には、あと 2 ステップほど作業が必要です。

まず、 mod_auth_basicmod_authz_user をきちんとロードさせね ばなりません。これらのモジュールは、 Apache のコンパイル時に静的に組み 込まれているか、 LoadModule を使って動的に組み込みます (この囲みの 末尾に例があります) 。

また、 Apache が他の認証用モジュールを使おうとしないように、設定のため のディレクティブを挿入しておき、 AuthUserFile/dev/null に指 定しておく必要があります。ロードした認証モジュールによって、以下のいず れか、または複数のディレクティブが必要です:

AuthBasicAuthoritative Off
AuthDefaultAuthoritative Off
AuthzLDAPAuthoritative Off
AuthzDBMAuthoritative Off
AuthzDefaultAuthoritative Off
AuthzGroupFileAuthoritative Off
AuthzOwnerAuthoritative Off
AuthzUserAuthoritative Off

Apache 2.2 での設定全体を、2.0 との違いを太字にして示します:

LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_user_module modules/mod_authz_user.so

...

<Location /example/>
    AuthType Basic
    AuthName "example.com"
    AuthUserFile /dev/null
    AuthBasicAuthoritative Off
    Require valid-user

    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
    PythonAuthenHandler django.contrib.auth.handlers.modpython
</Location>

デフォルトでは、認証ハンドラは staff のマークのついたメンバだけに /example/ へのアクセスを制限します。この挙動を変更したければ、 以下の PythonOption ディレクティブを使います:

PythonOption 説明
DjangoRequireStaffStatus

on に設定すると、 “staff” ユーザ (is_staff フラグの立っているユーザ) だけにアクセスを許可します。

デフォルトの設定値は on です。

DjangoRequireSuperuserStatus

on に設定すると、スーパユーザ (is_superuser フラグの立っている ユーザ) だけにアクセスを許可します。

デフォルトの設定値は off です。

DjangoPermissionName

アクセスに必要なパーミッションの名前 です。詳しくは カスタムのパーミッション を参照 してください。

デフォルトの設定では、 特定のパーミッションを必要としません。

場合によって、 SetEnv が mod_python の設定としてうまく働きません。 この原因はよくわかっていません。 mod_python が DJANGO_SETTINGS_MODULE をうまく認識できない場合、 SetEnv の代りに PythonOption を使ってみ て下さい。以下の二つのディレクティブは同じ意味です:

SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonOption DJANGO_SETTINGS_MODULE mysite.settings

REMOTE_USER を使った認証

revision-up-to:17812 (1.4)

このドキュメントでは、 (Web サーバが環境変数 REMOTE_USER を設定するよう な環境で) Django から外部の認証ソースを利用する方法について解説します。 このタイプの認証がよく行われるのは、イントラネットサイトで IIS や Integrated Windows Authentication によるシングルサインオンを使う場合や、 Apache と mod_authz_ldap , CAS, Cosign, WebAuth, mod_auth_sspi などを使う場合です。

通常、 Web サーバが認証を行う場合、アプリケーション側には環境変数 REMOTE_USER がセットされて渡されます。 Django の中では、 REMOTE_USERrequest.META ア トリビュートから取り出せます。 django.contrib.auth モジュールの RemoteUserMiddlewareRemoteUserBackend クラスを使えば、 REMOTE_USER を利用するように Django を設定できます。

設定

まず、 MIDDLEWARE_CLASSES 設定の中で、 django.contrib.auth.middleware.RemoteUserMiddlewaredjango.contrib.auth.middleware.AuthenticationMiddleware よりも後に 入れておきます:

MIDDLEWARE_CLASSES = (
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.RemoteUserMiddleware',
    ...
    )

次に、 AUTHENTICATION_BACKENDS 設定の中の ModelBackendRemoteUserBackend と置き換えます:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.RemoteUserBackend',
)

これで、 RemoteUserMiddlewarerequest.META['REMOTE_USER'] を使っ てユーザ名を検出し、 RemoteUserBackend の中で認証と自動ログインを行うよ うになります。

Note

RemoteUserBackendModelBackend を継承しているので、 ユーザは ModelBackend の定義しているパーミッションチェックをすべてパ スする必要があります。

認証メカニズムが REMOTE_USER 以外のカスタムの HTTP ヘッダを使っていてい る場合には、以下の例のように、 RemoteUserMiddleware をサブクラス化して、 クラスの header アトリビュートを適切な request.META のキー名に設定 してください:

from django.contrib.auth.middleware import RemoteUserMiddleware

class CustomHeaderMiddleware(RemoteUserMiddleware):
    header = 'HTTP_AUTHUSER'

RemoteUserBackend

class django.contrib.auth.backends.RemoteUserBackend

認証メカニズムをより細かく制御したいなら、 RemoteUserBackend を継承する 独自の認証バックエンドクラスを作成して、以下のメソッドをオーバライドしてく ださい:

アトリビュート
RemoteUserBackend.create_unknown_user

True または False です。 User のデータベースに該当ユーザが 存在しないときに、新たにユーザを作成するかどうかを決めるパラメタです。 デフォルトの値は True です。

メソッド
RemoteUserBackend.clean_username(username)

User オブジェクトを取り出したり、新 たに作成したりするときに、(LDAP で DN 情報をはぎ取るといったような) オブ ジェクトの username のクリーニングを行うメソッドです。クリーニング済 みのユーザ名を返します。

RemoteUserBackend.configure_user(user)

新たに作成したユーザの設定を行います。このメソッドは、新たにユーザが作成 された直後に呼び出されるので、ユーザのグループを LDAP 辞書から取り出すと いったような、独自のセットアップをを実行できます。ユーザオブジェクトを返 します。

アクションを自作する

revision-up-to:11321 (1.1)

manage.py には、アプリケーション固有のアクションを定義して登録できます。 例えば、配布したいアプリケーションの中に、 manage.py アクションを追加し たい場合があるとしましょう。

アクションを追加するには、アプリケーション内に management/commands ディ レクトリを作成します。このディレクトリを作成しておくと、 manage.py の実 行時にディレクトリ内のモジュールが自動的に検出され、アクションとして実行で きるコマンドが登録されます:

blog/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            __init__.py
            explode.py
    views.py

上の例では、 blog アプリケーションを settings.INSTALLED_APPS に登録 してあるプロジェクトで explode というコマンドを使えるようになります。

コマンドモジュールの必須の条件として、 explode.pydjango.core.management.base.BaseCommand を拡張した Command という名 前のクラスを定義していなければなりません。

自作のコマンドを定義する詳しい方法は、既存の django-admin.py コマンドの ソースコードを参照してください。ソースは /django/core/management/commands にあります。

カスタムのモデルフィールド

revision-up-to:11321 (1.1)

はじめに

モデルリファレンス ドキュメントでは、 CharFieldDateField といった、 Django の標準のフィールドク ラスの使用法について説明しています。ほとんどの用途には、これらの標準フィー ルドクラスだけで十分でしょう。とはいえ、現行の Django が自分の要求をうまく 満たしていない場合や、 Django が提供しているものと全く異なるフィールドを使 いたい場合もあるでしょう。

Django の組み込みフィールド型は、データベースのカラムとして利用できる全ての データ型をサポートしているわけではなく、 VARCHARINTEGER のよう な一般的な型しかサポートしていません。幾何多角形 (geographic polygon) 型や、 PostgreSQL カスタム型 のようなユーザ定義型といった特異な型を扱うには、 Field 型のサブクラスを定義せねばなりません。

Field 型のサブクラス定義には、別の用途もあります。複雑な Python オブジェ クトをシリアライズして、標準的なデータベースのカラム型に変換して保存したい 場合です。こうした場合にも、 Field のサブクラスを定義しておき、モデルで 使うと便利です。

ブリッジの手を例題に

カスタムフィールドを作成するには、ちょっと注意が必要です。説明についていけ るように、このドキュメントでは一貫して、 ブリッジ の「手」を表す Python オブジェクトをラップするという例題を使うことにします。 (ブリッジの遊び方をしらなくても、心配することはありません。知っておくべきな のは、ブリッジは、 52 枚のカードを 4 人のプレイヤーで扱う遊びで、プレイヤー は伝統的に north, east, south, west と呼ばれることだけです。) さて、 Hand クラスは以下のように定義されています:

class Hand(object):
    def __init__(self, north, east, south, west):
        # パラメタはカードのリスト ('Ah', '9s', など)
        self.north = north
        self.east = east
        self.south = south
        self.west = west

    # ... (他のメソッドはここでは省略) ...

Hand はただの普通の Python クラスで、 Django 固有の定義は一切ありません。 このクラスを、モデルで扱えるようにしましょう (モデルの hand という属性 に Hand のインスタンスを入れたいとします):

example = MyModel.objects.get(pk=1)
print example.hand.north

new_hand = Hand(north, east, south, west)
example.hand = new_hand
example.save()

上の例では、他の Python クラスと同じように、 hand アトリビュートを代入 や値の参照に使っています。このトリックは、 Django に Hand オブジェクト の保存やロードの方法を教えることで実現されています。

モデルから Hand クラスを扱うために、 Hand に手を加える必要は 全くありません 。その方が、例えば既存のクラスでソースコードに手を加えら れないような場合にも、簡単にモデル上でサポートできるからです。

Note

単に、カスタムのデータベースカラム型を使って、文字列や浮動小数点型といっ た標準の Python データを扱いたいという場合もあるでしょう。このケースも Hand の例とほぼ同様で、違いは後で説明します。

基本的な考え方

データベースストレージ

モデルフィールドの役割を理解するには、モデルフィールドが何らかの Python 型 オブジェクト、すなわち文字列型やブール型、 datetime 型、そして Hand ようなより複雑なデータ型を扱ったり、データベースの保存に適した形式との間で 相互変換するためのものだと考えるのが手っ取り早いでしょう (シリアライズ用の 変換もありますが、後で説明するように、一度データベース側の変換ができるよう になれば、シリアライザ用の変換は結構簡単です)。

モデル内のフィールド値は、データベース上では何らかのカラムタイプに変換され ねばなりません。使えるカラムタイプはデータベースによって違いますが、カラム タイプが何のデータを表現するかだけに注意していれば問題ありません。すなわち、 データベースに保存したいものと、データベースのカラムタイプを合わせればよい のです。

Hand の例の場合には、プレイヤーのカード情報を、予め決まった順番、 north, east, south, west の順番にくっつけて、 104 文字の文字列に変 換します。従って、 Hand オブジェクトはデータベースにテキスト型はキャラ クタ型で保存できます。

フィールドクラスの役割

Django のフィールド型 (このドキュメントで フィールド という場合には、基本 的に フォームフィールド ではなくモデルフィールド を指します) は、全て django.db.models.Field のサブクラスです。 Django がフィールドごとに記録する情報は、フィールドの名前、フィールド毎のヘ ルプテキスト、フィールドの値に対するバリデータのリスト、フィールドをユニー クキーにするかどうかのフラグ、といったもので、ほとんどのフィールドで共通し ています。こうした情報の保存は Field クラスが行います。 Field の動 作は後で詳しく説明しますが、さしあたっては、全ては Field から継承でき、 その中からクラスの挙動の鍵になる部分をカスタマイズするのだと考えておけば十 分です。

よくよく理解してほしいのは、「モデルの各アトリビュートには、 Django のフィー ルドクラスのインスタンスが保存されているのではない」ということです。モデル の各アトリビュートに入っているのは、アトリビュートの値を表すただ通常の Python オブジェクトです。モデルの中でフィールドを定義すると、そのフィールド のクラスは、モデルクラスの生成時に内部クラス Meta の中に保存されます (詳しい動作の仕組みは、ここではあまり重要ではあ りません)。モデルインスタン スのアトリビュートを作成したり変更する時には、フィールドクラスの機能は使わ れません。その代わり、フィールドクラスは、アトリビュートの値をデータベース に保存したり、 シリアライザ に送信するときに 必要な変換の手段を提供しているのです。

カスタムのフィールドクラスを定義する際には、上記のことを心に留めておいてく ださい。 Django の Field サブクラスは、 Python オブジェクトとデータベー スやシリアライザ向けの値との間で、色々な変換 (例えば、データを保存するた めの変換と、照合に使うための変換は別のものです) を実現するための機構を提供 します。この仕組みは一見トリッキーですが、心配しないでください。以下の例を 読み進めていくうちにはっきり分かるでしょう。ただ、たいていの場合、カスタム フィールドが必要な場面では、以下の二つのクラスを定義するということだけを覚 えておいてください:

  • 一つ目は、ユーザが操作する Python オブジェクトです。このオブジェクト はモデルのアトリビュートとして代入され、表示時に読み出されます。例で いうと Hand クラスです。
  • もう一つは Field のサブクラスです。このクラスには、上のクラスと データベースのような永続ストレージとの間で相互変換を行うための処理が 組み込まれています。

フィールドのサブクラスを定義する

Field のサブクラスを定義するときには、まずは作り たいフィールドに一番近い既存のフィールドクラスがないか考えましょう。既存の Django のフィールド型をサブクラス化すれば、作業が楽になるでしょうか? もしそうでなければ、 Field クラスをサブクラス化 します。

フィールドの初期化時には、 Field クラス (または 親クラス) 共通の引数と、新たなフィールドクラス固有の引数を分離して、前者を 親クラスの __init__() に渡します。

このドキュメントの例題では、定義するフィールドを HandField と呼ぶことに しましょう (フィールドを (何とか)Field と呼ぶようにしておけば、クラスが Field のサブクラスであるとすぐ分かるからです)。 HandField は既存のフィールドと似た部分はあまりないので、 Field クラスから直接サブクラス化します:

from django.db import models

class HandField(models.Field):
    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 104
        super(HandField, self).__init__(*args, **kwargs)

HandField は標準的なフィールドオプションのほとんどを指定できます。ただ し、このフィールドは高々 52 枚のカードの値と種類だけを保存できればよいので、 合計 104 文字分の固定長にしておきます。

Note

多くの Django のモデルフィールドは、そのフィールドに関係のないオプショ ンも引数に指定できます。例えば、 editableauto_now の両方を DateField に指定してもよく、 DateField は (auto_now を指定すると editable=False なので) editable パ ラメタを無視します。この場合、エラーは送出されません。

このような挙動にしておくと、不要なオプションをいちいちチェックしなくて よいので、フィールドクラスの定義が簡単になります。サブクラスでは、単に 全てのオプションを親クラスに渡しておけばよく、それ以上何もしなくてよい のです。選べるオプションを厳しく制限してもよいですし、簡単にしたければ、 何でも指定できるようにしておけばよいのです。

__init__() メソッドは、以下のパラメタを (並び 順通りに) 取ります:

上のリストで解説のないオプションは、通常の Django のフィールドと同じ意味を 持っています。詳しくは モデルのドキュメント を参 照してください。

SubfieldBase メタクラス

はじめに でも説明したように、フィールド型のサブクラスが必要な理由は主に 二つあります。一つはカスタムのデータベースカラム型を利用したい場合、もう一 つは複雑な Python のデータ型を扱いたい場合です。もちろん、二つを合わせて実 現するのも可能です。カスタムのデータベースカラム型を扱っているだけで、かつ Python からモデルフィールドを扱うときのデータ型が、データベースバックエンド から取り出したデータの型と一致している場合には、この節を気にする必要はあり ません。

Hand クラスのようにカスタムの Python 型を扱うフィールドを作成したい場合、 Django がモデルのインスタンスを生成して、フィールドのアトリビュート値をデー タベースに保存する時に、フィールドの値を適切な Python オブジェクトに変換す る必要があります。この処理のからくりはやや複雑ですが、 Field クラスを定 義するときに書かねばならないコードはいたって単純で、特殊なメタクラスを使っ てサブクラスを作成するだけです:

class django.db.models.SubfieldBase

例えば:

class HandField(models.Field):
    __metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        # ...

こうしておけば、属性値を初期化する際に、自動的に to_python() メソッド が呼び出されるようになります。 to_python() メソッドについては後で解説 します。

便利なメソッド

Field のサブクラスを作成して、 __metaclass__ を組み込んだら、次はフィールドの挙動に応じて標準メソッド をいくつかオーバライドします。以下のメソッドは上からよく使う順に挙げていま す。

データベース型のカスタマイズ
db_type(self)

DATABASE_ENGINE 設定に指定されているデータベースで、フィールドの データを保存するために使うカラム型を返します。

例えば、 PostgreSQL 固有のカスタム型 mytype を作成したとしましょう。 Django からこの型を使うには、以下のように Field をサブクラス化して、 db_type() メソッドを実装します:

from django.db import models

class MytypeField(models.Field):
    def db_type(self):
        return 'mytype'

MytypeField を定義したら、他のフィールド型と同じようにモデルで利用でき ます:

class Person(models.Model):
    name = models.CharField(max_length=80)
    gender = models.CharField(max_length=1)
    something_else = MytypeField()

データベースに依存しないアプリケーションを構築したいなら、データベース毎 のカラム型の違いに注意しておかねばなりません。例えば、 PostgreSQL では日付 や時間に関するカラム型は timestamp 型ですが、 MySQL では datetime 型です。この違いを db_type() メソッドの中で吸収するには、Djangoの settings モジュールを import しておいて、以下のように DATABASE_ENGINE 設定をチェックします:

class MyDateField(models.Field):
    def db_type(self):
        from django.conf import settings
        if settings.DATABASE_ENGINE == 'mysql':
            return 'datetime'
        else:
            return 'timestamp'

db_type() メソッドは、Django がアプリケーションのテーブルを生成する ための CREATE TABLE` 文を構築する瞬間、すなわち最初にテーブルを生成する 瞬間しか呼び出されません。それ以外の場合に呼び出されることはないので、上記 の DATABASE_ENGINE をチェックする例のような多少ややこしいコード を書いてもさして問題ではありません。

カラムのデータ型にはパラメタを取るものがあります。例えば CHAR(25) は、 25 がカラムの最大長を表しています。こうした場合には、 db_type() メソッド内でハードコードしておくよりも、モデル内でパラメタを指定して使える 方が柔軟性を高められます。例えば、以下に示すような CharMaxlength25Field はあまり便利ではありません:

# パラメタをハードコードしているおバカな例
class CharMaxlength25Field(models.Field):
    def db_type(self):
        return 'char(25)'

# モデル内での使い方
class MyModel(models.Model):
    # ...
    my_field = CharMaxlength25Field()

実行時、すなわちフィールドクラスをインスタンス化する時にパラメタを指定でき た方がよいでしょう。パラメタを指定できるようにするには、以下のように django.db.models.Field.__init__() を実装します:

# より柔軟性のある例
class BetterCharField(models.Field):
    def __init__(self, maxlength, *args, **kwargs):
        self.max_length = max_length
        super(BetterCharField, self).__init__(*args, **kwargs)

    def db_type(self):
        return 'char(%s)' % self.max_length

# モデル内での使い方
class MyModel(models.Model):
    # ...
    my_field = BetterCharField(25)

最後に、カラムの操作に非常に複雑な SQL が必要な場合には、 db_type()None を返させましょう。そうすれば、 Django の SQL 生成コードはこの フィールドの処理をスキップします。もちろん、その場合には、何らかの方法で正 しいテーブルに正しいカラムを生成する必要があります。

データベース上の値を Python オブジェクトに変換する
to_python(self, value)

データベース (またはシリアライザ) の返す値を Python オブジェクトに変換しま す。

デフォルトの実装では、単に value を返します。通常は、データベースバック エンドは正しい形式 (Python 文字列型など) でデータを返すからです。

カスタムのフィールドクラスで、文字列や日時、整数や浮動小数点型といったデー タ型よりも複雑なデータ構造を扱いたい場合、このメソッドをオーバライドする必 要があります。一般的な規則として、このメソッドは以下の引数をきちんと扱えね ばなりません:

  • 正しい型のインスタンス (このドキュメントの例では Hand オブジェク ト)
  • 文字列 (デシリアライザなどが返す値)
  • このフィールドのカラムタイプに対して、データベースバックエンドが返す 値

HandField クラスでは、データを VARCHAR フィールドで保存しているので、 to_python() は文字列と Hand インスタンスの両方を扱えねばなりません:

import re

class HandField(models.Field):
    # ...

    def to_python(self, value):
        if isinstance(value, Hand):
            return value

        # The string case.
        p1 = re.compile('.{26}')
        p2 = re.compile('..')
        args = [p2.findall(x) for x in p1.findall(value)]
        return Hand(*args)

このメソッドは常に Hand インスタンス、つまりモデルのアトリビュートとし て保存したい Python オブジェクトを返します。

忘れないで!: カスタムフィールドに対して to_python() を呼び出した ければ、上で述べた SubfieldBase メタクラス を使わねばなりません。メタク ラスを使わないと、 to_python() は自動的に呼び出されません。

Python オブジェクトをデータベース保存用の値に変換する
get_db_prep_value(self, value)

to_python() の逆のメソッドで、データベースバックエンドを扱うときに呼 び出されます。 value パラメタは、現在のアトリビュートの値です (フィール ドは自分を含むモデルインスタンスへの参照を持たないので、モデルインスタンス 経由でフィールドの値を取り出せません。そのため、 value パラメタで値を受 け取ります)。 このメソッドは、 value で受け取ったデータを、各データベー スバックエンドのクエリパラメタとして使える形式にフォーマットして返さねばな りません。

例を示します:

class HandField(models.Field):
    # ...

    def get_db_prep_value(self, value):
        return ''.join([''.join(l) for l in (value.north,
                value.east, value.south, value.west)])
get_db_prep_save(self, value)

前述のメソッドと同じですが、フィールドの値をデータベースに 保存 するとき に呼び出されます。デフォルトの実装では単に get_db_prep_value を呼び出し ています。従って、データベースにデータを保存するときに、通常のクエリパラメ タと違うものを使わねばならないような特殊な状況を除き、このメソッドを実装す る必要はありません (通常のクエリパラメタの変換は、 get_db_prep_value で で実装しています)。

保存前に値に前処理をほどこす
pre_save(self, model_instance, add)

このメソッドは、 get_db_prep_save() の直前に呼び出され、このフィール ドの model_instance での適切な値を生成して返さねばなりません。アトリビュ ートの名前は self.attrname で参照できます (この値はフィールドのインス タンス化時に設定されます)。モデルインスタンスをデータベースに初めて保存しよ うとしている場合、 add パラメタの値は True です。それ以外の値は False です。

このメソッドをオーバライドする必要があるのは、フィールドの値を、保存の直前 に前処理したい場合だけです。例えば、 Django の DateTimeField は、 auto_nowauto_now_add で生成された場合、このメソッド を使って正しい値をセットします。

このメソッドをオーバライドする場合、最後にアトリビュートの値を返さねばなり ません。また、フィールドの値を変更した場合、モデル上の対応する値も更新して、 モデルインスタンスを参照しているコードが正しい値を読み出せるようにせねばな りません。

データベース照合時のパラメタを SQL 用に変換する
get_db_prep_lookup(self, lookup_type, value)

データベース上で照合を行う時 (WHERE 制約付きで SQL を発行する時) にデー タベースに渡す値を前処理します。 lookup_type は、 Django のフィルタ照合 条件である exact, iexact, contains, icontains, gt, gte, lt, lte, in, startswith, istartswith, endswith, iendswith, range, year, month, day, isnull, search, regex, iregex のいずれかの値を取ります。

このメソッドをオーバライドする場合、上に挙げた lookup_type を全て扱えね ばなりません。また、 value が正しい値でない場合 (value に単一のオブ ジェクトが入っているはずなのに、リストが入っていた場合など) には ValueError を、フィールドが指定した照合に対応していない場合には TypeError を送出せねばなりません。たいていのフィールドでは、特別な扱い の必要な照合タイプだけを処理して、残りは親クラスの get_db_prep_lookup() メソッドに委ねればよいでしょう。

get_db_prep_save を定義するようなケースではたいてい、 get_db_prep_lookup も定義する必要があります。定義しなければ、 exact, gt, gte, lt, lte, in, range の照合時には、 デフォルトの実装に従って get_db_prep_value が呼び出されます。

また、カスタムのフィールド型でサポートする照合タイプを制限したい場合にも、 このメソッドを定義する必要があるでしょう。

rangein を使った照合を行う場合、 get_db_prep_lookup は 引数として (適切な型の) オブジェクトのリストを受け取り、データベースに渡せ るなにがしか適切な型のオブジェクトからなるリストに変換せねばなりません。 大抵の場合は get_db_prep_save を使い回したり、別のメソッドに共通の 処理を括り出しておけます。

例えば、以下のコードでは get_db_prep_lookup を実装して、照合タイプを exactin に制限しています:

class HandField(models.Field):
    # ...

    def get_db_prep_lookup(self, lookup_type, value):
        # 'exact' および 'in' だけを扱います。それ以外はエラーにします。
        if lookup_type == 'exact':
            return [self.get_db_prep_value(value)]
        elif lookup_type == 'in':
            return [self.get_db_prep_value(v) for v in value]
        else:
            raise TypeError('Lookup type %r not supported.' % lookup_type)
モデルフィールドに対応したフォームフィールドを指定する
formfield(self, form_class=forms.CharField, **kwargs)

このフィールドをモデルに組み込んで、フォームで表示したときに使うデフォルト のフォームフィールドを返します。このメソッドは、 ModelForm ヘルパから呼び出されます。

kwargs 辞書の内容は、全てフォームフィールドの Field__init__() メソッドに渡されます。通常、このメソッ ドの定義では、適切な form_class 引数のデフォルト値を設定して、それ以降 の処理を親クラスに移譲しているだけです。フォームフィールドを定義する場合、 カスタムのフォームフィールド (や、フォームウィジェット) を書く必要があるか もしれません。カスタムのフォームフィールドについては forms のドキュメント を参照してください。また、 カスタムウィジェットは django.contrib.localflavor のコードを参照する とよいでしょう。

これまでの例に合わせて書くと、 formfield() メソッドは以下のように書け ます:

class HandField(models.Field):
    # ...

    def formfield(self, **kwargs):
        # メソッドの呼び出し側がデフォルトをオーバライド
        # できるようにするための標準的な書き方
        defaults = {'form_class': MyFormField}
        defaults.update(kwargs)
        return super(HandField, self).formfield(**defaults)

上の例では、 MyFormField フィールドクラスを import しているのが前提です (そして、 MyFormField でデフォルトのウィジェットを定義しています)。カス タムのフォームフィールドの定義方法は、このドキュメントでは扱いません。

組み込みのフィールド型をエミュレートする
get_internal_type(self)

データベースレベルでエミュレーションしているフィールド型の名前を返すメソッ ドです。このメソッドは、簡単な方法でフィールド型を定義する際に、データベー スのカラム型を決定するために使われます。

db_type() メソッドを定義していれば、 get_internal_type() を気に する必要はありません。このメソッドは、ほとんど使われません。ただし、フィー ルド型のデータベースストレージが、他のフィールドと同じような型である場合、 このメソッドを定義しておくと、他のフィールドのロジックを使ってカラムを生成 させられます。

例を示します:

class HandField(models.Field):
    # ...

    def get_internal_type(self):
        return 'CharField'

どのデータベースバックエンドを使っているかに関わらず、上のように定義してお くと、 syncdb などの SQL 関係のコマンドを実行した時に、文字列を保存す るための正しいカラム型を生成します。

get_internal_type() が、 Django にもデータベースバックエンドにもない 型を示す文字列、すなわち django.db.backends.<db_name>.creation.DATA_TYPES に存在しない文字列を返 を返す場合、シリアライザはこの文字列をそのまま受け取りますが、デフォルトの db_type() 実装は None を返します。なぜこうした動作が適切なのかを 知りたければ、db_type() のドキュメントを読んでください。 たとえフィールドが DATA_TYPES にないデータ型を返す場合でも、 シリアライザの出力を Django の外で扱う予定があるのなら、シリアライザが扱え るように、 get_internal_type() にフィールドのデータ型を表す文字列を返 させるのがよいでしょう。

シリアライゼーション用にフィールドデータを変換する
value_to_string(self, obj)

このメソッドは、シリアライザがフィールドの値を出力する際に文字列に変換する ために使います。シリアライズデータを生成するには、 Field._get_val_from_obj(obj)() を呼び出すとよいでしょう。例えば、例え ば、 HandField はデータストレージに文字列を使っているので、既存の変換コー ドを再利用できます:

class HandField(models.Field):
    # ...

    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return self.get_db_prep_value(value)
一般的なアドバイス

カスタムフィールドの定義は、とりわけ Python 型とデータベース、そしてシリア ライゼーション形式との間で複雑な変換を行う場合には、トリッキーな処理になり がちです。よりスムーズにフィールドを定義するためのアドバイスを、以下に示し ます:

  1. 既存のフィールド型定義 (django/db/models/fields/__init__.py にあります) を見て、インスピレーションを得ましょう。全く何もない状態 からスクラッチでフィールドを定義するのではなく、自分の実現したいこと に近い処理を行っているフィールド型を探して、それをちょっとだけ拡張す るようにしましょう。
  2. フィールドとしてラップしたいクラスに、 __str__()__unicode__() メソッドを定義しましょう。フィールドの処理におけ るデフォルトの動作として、ラップしているクラスのインスタンスに対して force_unicode() を呼び出すような処理が たくさんあります。 (このドキュメントの例では、 valueHand のインスタンスであり、 HandField のインスタンスではないので) __unicode__() メソッドを定義しておき、 Python オブジェクトが自 動的に文字列形式に変換されるようにしておけば、作業を大幅に減らせます。

FileField のサブクラスを定義する

上に挙げたメソッドに加えて、ファイルを扱うフィールドを定義するときには、い くつか必要な条件があります。データベースストレージの操作やデータの取得など、 フィールド定義に必要なメカニズムのほとんどは FileField で定義しています が、特定のタイプのファイルをサポートするための処理はサブクラスに委ねていま す。

Django はファイルのコンテンツや操作をプロキシする File クラスを提供して います。このクラスはサブクラス化でき、ファイルのアクセス方法やメソッドをカ スタマイズできます。 File クラスは django.db.models.fields.files で 定義されており、デフォルトの動作は ファイルクラスのドキュメント で解説しています。

File のサブクラスを作ったら、 FileField サブクラスの attr_class に指定して、 FileField サブクラスに指定のファイルクラスを使うよう指示し てください。

アドバイス

上に挙げた説明に加えて、カスタムフィールドのコードの効率や可読性を挙げるた めのガイドラインをいくつか示しておきます。

  1. Django の ImageField (django/db/models/fields/files.py) は、 FileField をサブクラス化して特定のファイルタイプをサポートしてい る素晴らしい例題です。このクラスでは、上に述べたテクニックを余すとこ ろ無く使っています。
  2. 可能な限り、ファイルの属性をキャッシュしましょう。ファイルは遠隔のス トレージシステム上にあるので、ファイルデータの取得には時間もお金もか かります。しかも、常に必要なわけではありません。一度ファイルを取得し て、コンテンツに関するデータを収集したら、データ可能な限りキャッシュ して、以後のアクセスでファイルを再取得する回数を減らしましょう。

テンプレートタグやフィルタを自作する

revision-up-to:17812 (1.4)

Django テンプレートシステムには、いろいろな 組み込みタグとフィルタ が付属していて、アプリケーションのプレゼンテーショ ンロジックにまつわる問題を解決できます。とはいえ、コアのテンプレートタグプリミ ティブだけでは、要求を満たせない場合もあります。そういう場合のために、テンプ レートエンジンを拡張できます。Python で自作のタグやフィルタを書き、テンプレー ト上で {% load %} タグを使って使えるのです。

コードの配置

カスタムのテンプレートタグやフィルタは Django のアプリケーション内に置きま す。既存のアプリケーションに関連があるのなら、そのアプリケーションにバンド ルすればよいでしょう。そうでなければ、コードを入れておくための新たなアプリ ケーションを作成します。

アプリケーション内には、 templatetags ディレクトリを置かねばなりません。 このディレクトリは、 models.pyviews.py などと同じ階層に置きます。 templatetags がなければ、作成してください。ディレクトリ内に __init__.py を置いて、パッケージ化するのを忘れないでください。

カスタムのタグやフィルタは、 templatetags ディレクトリの下に置きます。 モジュールファイルの名前は、あとでタグをロードするときに使う名前にします。 ですから、他のアプリケーションのカスタムタグやフィルタと名前が衝突しないよ う、よく注意して名前を決めましょう。

poll_extras.py という名前のファイルに自作のタグ/フィルタを入れているの なら、アプリケーションのレイアウトは以下のようになるでしょう:

polls/
    models.py
    templatetags/
        __init__.py
        poll_extras.py
    views.py

そして、テンプレートでは以下のようにしてロードします:

{% load poll_extras %}

あるアプリケーションのカスタムタグを {% load %} で呼び出せるよう にするには、そのアプリケーションを INSTALLED_APPS にいれておかねば なりません。これは、一つのホストに複数の Django アプリケーションを置いたとき に、 Django アプリケーション同士が勝手に他のテンプレートライブラリにアクセスし ないようにするためのセキュリティ機能です。

templatetags パッケージには、いくつでもモジュールを入れられます。 {% load %} 文はアプリケーションの名前ではなく、 Python モジュー ル名に対応したタグ/フィルタをロードするということを心に留めておいてください。 有効なタグライブラリを作るには、 register という名前のモジュールレベル変数 に template.Library のインスタンスを入れておかねばなりません。このインスタ ンスには、全てのタグとフィルタが登録されます。そこで、モジュールの一番上の方 で、以下のコードを実行しておいてください:

from django import template

register = template.Library()

舞台裏

Django のデフォルトのフィルタやタグのソースコードには大量のサンプルが 収まっています。ソースコードはそれぞれ django/template/defaultfilters.pydjango/template/defaulttags.py にあります。

load タグについてもっと知りたければ、そちらのドキュメントを読んで ください。

カスタムのテンプレートフィルタ

カスタムフィルタは単なる Python の関数で、一つまたは二つの引数:

  • テンプレート変数 (入力) の値。文字列とは限りません。
  • 引数の値。デフォルトを持たせたり、無視させたりできます。

を取ります。例えば、フィルタ {{ var|foo:"bar" }} では、フィルタ foo はテンプレート変数 var と引数 "bar" を受け取ります。

フィルタ関数は常に何かを返さねばなりません。フィルタ関数は例外を送出しては ならず、失敗するときは暗黙のうちに失敗せねばなりません。エラーが生じた場合、 フィルタ関数は元の入力そのままか空文字列のうち、分かりやすい方を返すように せねばなりません。

フィルタの定義の例を以下に示します:

def cut(value, arg):
    """入力から arg の値を全て取り去る"""
    return value.replace(arg, '')

このフィルタは以下のように使います:

{{ somevariable|cut:"0" }}

ほとんどのフィルタは引数を取りません。引数を取らない場合には関数から引数を なくして下さい。例えば:

def lower(value): # Only one argument.
    """入力をすべて小文字にする"""
    return value.lower()
カスタムフィルタを登録する

フィルタ定義を書き終えたら、 Django テンプレート言語で使えるようにするため に Library インスタンスに登録する必要があります:

register.filter('cut', cut)
register.filter('lower', lower)

Library.filter() は二つの引数を取ります:

  1. フィルタの名前。文字列です。
  2. コンパイル関数。(関数名の文字列ではなく) Python 関数です。

register.filter() をデコレータとして使うこともできます:

@register.filter(name='cut')
def cut(value, arg):
    return value.replace(arg, '')

@register.filter
def lower(value):
    return value.lower()

上の例の下の定義のようにして name 引数を省略すると、 Django は関数名をその ままフィルタ名として使います。

最後に register.filter()is_safeneeds_autoescape の 2 つの キーワード引数をとることもできます。下の フィルタと自動エスケープ で説明しています。

テンプレートフィルタに文字列だけを処理させる

第一引数に文字列しかとらないテンプレートフィルタを書きたければ、 stringfilter デコレータを使ってください。このフィルタは、フィルタ処理の 関数を呼び出す前に、第一引数のオブジェクトを文字列に変換します:

from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.filter
@stringfilter
def lower(value):
    return value.lower()

こうすれば、例えばフィルタに整数型を渡したとしても、(整数型に lower() がないために) AttributeError が送出されるようなことはありません。

フィルタと自動エスケープ

カスタムフィルタを書く場合、フィルタが Django の自動エスケープとどう関わっ ているかに少し配慮しておく必要があります。まず、テンプレートのコード内では、 3 種類の文字列が受け渡しされています:

  • 生の文字列 は、 Python ネイティブの strunicode 型の オブジェクトです。出力時、自動エスケープが有効であればエスケープされ、 そうでなければ変更されません。

  • safe 文字列 は、出力時にさらなるエスケープ処理を行わなくてもよ い文字列です。safe 文字列は、必要なエスケープが済んでいる文字列です。 クライアント側でそのまま解釈されるべき生の HTML を含んだ文字列を表現 するのに使われます。

    内部的には、これらの文字列は SafeStringSafeUnicode 型で表 現されています。 SafeStringSafeUnicodeSafeData を 共通の基底クラスに持つので、以下のようにすれば判別できます:

    if isinstance(value, SafeData):
        # "safe" 文字列を扱う処理をここに
    
  • “エスケープが必要” であるとマークされている文字列 は、 autoescape ブロックの指定に関係なく、 必ず エスケープされます。 マークされている文字列は、自動エスケープの設定に関係なく、一度だけエ スケープ処理を受けます。

    内部的には、エスケープ必要文字列は、 EscapeStringEscapeUnicode 型で表現されています。通常、これらの型のことを気に する必要はありません。 EscapeStringEscapeUnicode は、 escape フィルタの実装のために用意されています。

テンプレートフィルタのコードは、以下の二つのうちどちらかに落ち着きます:

  1. フィルタコードの出力が、 HTML 出力として安全でない文字 (<, >, ', " or &) を含まない場合。この場合、自動エスケー プの処理は全て Django に任せられます。必要なのは、フィルタ関数の is_safe 属性に True を設定しておくことだけです:

    @register.filter(is_safe=True)
    def myfilter(value):
        return value
    

    この属性を設定しておくと、このフィルタは「安全な」文字列を渡したとき には出力は「安全な」ままであり、「安全でない」文字列を渡した時には、 必要に応じて自動的にエスケープします。

    is_safe は、「このフィルタは安全 (safe) であり、安全でない HTML を生成するおそれがない」という意味だと考えてください。

    is_safe が必要なのは、通常の文字列操作で、 SafeData オブジェ クトを strunicode オブジェクトに変換するものが数多くあ るからです。全てを try と catch で拾うのは難しいので、 Django はフィ ルタ処理が完了した時点でダメージを回復する戦略を取っています。

    例えば、入力の末尾に xx を追加するようなフィルタを書くとします。 このフィルタは危険な HTML 文字を出力しないので、フィルタ関数を is_safe でマークしておきます:

    @register.filter(is_safe=True)
    def add_xx(value):
        return '%sxx' % value
    

    このフィルタをテンプレート上の自動エスケープが有効な部分で使うと、 Django は “safe” にマークされていない入力の時にフィルタの出力をエス ケープします。

    デフォルトでは、 is_safeFalse なので、 is_safe が 必要でなければ無視してかまいません。

    フィルタを作成するときには、フィルタが本当に安全な文字を安全なままに 出力するのかをよく考えてください。例えば、フィルタが文字を 削除 す る場合、出力結果に、対応の取れていないタグや不完全なエンティティ表現 が意図せず混じる可能性があります。例えば、 > を入力から削ってし まうと、 <a> の出力は <a になってしまい、問題を起こさないよ うにするためには、出力をエスケープせねばならなくなってしまいます。同 様に、セミコロン (;) を除去すると、 &amp;&amp になっ てしまい、有効なエンティティ表現でないために、エスケープが必要になっ てしまいます。たいていのケースでは、このようなトリッキーなことは起こ りませんが、コードをレビューする際にはこの手のことが起こらないように よく確認してください。

    フィルタを is_safe にマークするとフィルタに文字列を返すように強制させる ことになります。真偽値や非文字列型の値を返すフィルタを is_safe にマーク すると、おそらく意図しない結果を起こすことになります (真偽値の False が文字 列の ‘False’ に変換されるなど) 。

  2. もう一つは、フィルタのコードで必要なエスケープを行うというものです。 出力に新たな HTML マークアップを含めたい場合に必要です。この場合、 出力する HTML マークアップがそれ以上エスケープされないよう、出力を safe にする必要があるので、入力は自分で扱わねばなりません。

    出力を safe 文字列としてマークするには、 django.utils.safestring.mark_safe() を使います。

    ただし、注意してください。出力を safe であるとマークするだけでは十分 ではありません。出力が本当に safe である ことを保証せねばならず、 それは自動エスケープが有効か無効かで変わります。自動エスケープがオン でもオフでも使え、テンプレートの作者が簡単に扱えるフィルタを書くのが 理想です。

    現在の自動エスケープ状態をフィルタに教えるには、関数の needs_autoescape 属性を True に設定します (この属性を設定 しない場合のデフォルト値は False です)。 needs_autoescapeTrue にすると、フィルタ関数には autoescape という追加の引 数が渡されます。自動エスケープが有効な状況でフィルタが呼び出されると、 autoescape には True が渡され、そうでない場合には False が渡されます。

    例えば、文字列の先頭の文字を強調表示にするようなフィルタを書いてみま しょう:

    from django.utils.html import conditional_escape
    from django.utils.safestring import mark_safe
    
    @register.filter(needs_autoescape=True)
    def initial_letter_filter(text, autoescape=None):
        first, other = text[0], text[1:]
        if autoescape:
            esc = conditional_escape
        else:
            esc = lambda x: x
        result = '<strong>%s</strong>%s' % (esc(first), esc(other))
        return mark_safe(result)
    

    フィルタ関数の needs_autoescape 属性と autoescape キーワード 引数の存在によって、フィルタ関数は自身が呼び出されたときの自動エスケー プ状態を検知できます。上の例では、 autoescape を使って、入力デー タを django.utils.html.conditional_escape で処理するべきかどうか 判定しています。 (conditional_escape が不要の場合、 esc を アイデンティティ関数にしています) conditional_escape()escape() に似ていますが、入力が SafeData インスタンスで ない 場合にのみエスケープを適用します。 conditional_escape()SafeData を渡すと、データは変更されません。

    最後に、上の例では、フィルタ結果を mark_safe で safe にマークし て、出力結果の HTML をこれ以上エスケープせず、最終的なテンプレート出 力に挿入させています。

    このケースでは、 is_safe 属性について触れていません (実際には、 設定しても何の影響もありません)。自動エスケープの問題を手動で解決し て、 safe 文字列を返している場合、 is_safe 属性は何ら影響をもた ないのです。

リリースノートを参照してください

is_safeneeds_autoescape はフィルタ関数の属性として使われていまし た。この構文は廃止されています。

@register.filter
def myfilter(value):
    return value
myfilter.is_safe = True
@register.filter
def initial_letter_filter(text, autoescape=None):
    # ...
    return mark_safe(result)
initial_letter_filter.needs_autoescape = True
フィルタとタイムゾーン
リリースノートを参照してください

datetime オブジェクトを操作するカスタムフィルタを書く場合、 普通は expects_localtime フラグを True にセットして登録します:

@register.filter(expects_localtime=True)
def businesshours(value):
    try:
        return 9 <= value.hour < 17
    except AttributeError:
        return ''

このフラグがセットされると、もし最初の引数がタイムゾーン aware な datetime な ら Django はそれをフィルタに渡す前に テンプレートでのタイムゾーン変換ルール に従っ て、適切なカレントタイムゾーンに変換します。

カスタムテンプレートタグを書く

タグはフィルタよりもやや複雑です。というのも、タグを使えば何でもできるから です。

テンプレートタグの概要

前に、このドキュメントで、テンプレートシステムはコンパイルとレンダリングと いう二段階のプロセスで動作すると説明しました。カスタムテンプレートタグを定 義するには、コンパイルがどのように行われ、レンダリングがどのように行われる かを指定する必要があります。

テンプレートをコンパイルする時、Django は元のテンプレートテキストを「ノード (node)」に分割します。各ノードは django.template.Node のインスタンスで あり、 render() メソッドを持ちます。コンパイル済みのテンプレートは単な る Node オブジェクトの集まりに過ぎません。コンパイル済みのテンプレート オブジェクトに対して render() を呼び出すと、テンプレートは指定されたコ ンテキストを使ってノードリストの各 Node に対して render() を呼び出 します。戻り値は全て連結され、テンプレートのレンダリング結果になります。

従って、カスタムテンプレートタグを定義するには、元のテンプレートタグをどう やって Node (コンパイル関数: compilation function) に変換し、個々のノー ドの render() メソッドが何をするかを指定する必要があります。

コンパイル関数を書く

テンプレートタグに到達するたびに、テンプレートパーザはタグの内容とパーザオ ブジェクト自体を引数にしてある Python 関数を呼び出します。この関数はタグの 内容に応じて Node インスタンスを返す役割を担っています。

例えば、 {% current_time %} というタグを書いてみましょう。このタグは現 在の日付/時刻を表示し、そのフォーマットはタグの引数に指定した strftime() の文法に従うとします。何をおいてもタグの構文をまず決め ておくのがよいでしょう。我々の例では、タグは以下のように使われるものとしましょ う:

<p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>

以下の関数は、パラメタを取り出して、 Node オブジェクトを生成します:

from django import template
def do_current_time(parser, token):
    try:
        # split_contents() knows not to split quoted strings.
        tag_name, format_string = token.split_contents()
    except ValueError:
        raise template.TemplateSyntaxError("%r tag requires a single argument" % token.contents.split()[0])
    if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
        raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % tag_name)
    return CurrentTimeNode(format_string[1:-1])

注意:

  • parser はテンプレートパーザオブジェクトです。上の例では特に必要で はありません。
  • token.contents はタグの中身を表す文字列です。上の例では 'current_time "%Y-%m-%d %I:%M %p"' です。
  • token.split_contents() メソッドは、クオートされた文字列はそのまま にして、引数をスペースで分割します。 token.contents.split() の方 が直接的なように思えますが、クオート中の空白も含め、 全ての スペー スを区切りとみなすので、これは頑健な方法とはいえません。常に token.split_contents() を使った方がよいでしょう。
  • この関数は、何らかの構文エラーが生じた場合、分かりやすいメッセージ付 きで django.template.TemplateSyntaxError を送出せねばなりません。
  • TemplateSyntaxError 例外は tag_name 変数を使っています。 エラーメッセージにタグの名前をハードコードしてはなりません。なぜなら 関数とタグの名前がカップリングしてしまうからです。タグに引数があって もなくても、 token.contents.split()[0] は常にタグの名前と同じです。
  • この関数は、タグの処理に必要な全ての情報を持った CurrentTimeNode を返します。この例の場合、タグには引数 "%Y-%m-%d %I:%M %p" が渡さ れただけです。テンプレートタグの先頭や末尾のクオートは format_string[1:-1] ではぎ取られています。
  • パージング処理は極めて低水準で実現されています。 Django の開発者達は、 EBNF 文法のようなテクニックを使って、このパージングシステムの上に小さ なフレームワークを書く実験を重ねて来ましたが、その結果はテンプレート エンジンをひどく低速にしてしまいました。というわけで、低水準にしてい るのは、それが最も高速だからです。
レンダラを書く

カスタムタグを書く二つめのステップは、 render() メソッドを持つ Node クラスの定義です。

上の例の続きとして話を勧めると、 CurrentTimeNode を定義する必要がありま す:

from django import template
import datetime
class CurrentTimeNode(template.Node):
    def __init__(self, format_string):
        self.format_string = format_string
    def render(self, context):
        return datetime.datetime.now().strftime(self.format_string)

注意:

  • __init__()do_current_time() から format_string を受け 取ります。 Node へのオプション/パラメタ/引数は、常に __init__() を介して渡すようにしてください。
  • 実際の処理を実現するのは render() メソッドです。
  • render()TemplateSyntaxError やその他の例外を送出してはな りません。フィルタと同様、失敗は暗黙のうちに処理されるようにせねばな りません。

一つのテンプレートは、繰り返しパージングされることなく複数のコンテキストを レンダリングすることがあるので、このようなコンパイルとレンダリングの脱カッ プリングは究極的には効率的なテンプレートシステムを実現します。

自動エスケープの注意点

テンプレートタグの出力は、自動エスケープフィルタで自動的に処理 されません 。とはいえ、テンプレートタグを書くときには、二つのことを心に留 めて置く必要があります。

まず、テンプレートタグの render() が結果をコンテキスト変数に保存する場 合 (文字列でそのまま返さない場合) には、必要なら mark_safe() を呼び出し ておく必要があります。その変数を最終的にレンダした時点で、変数は自動エスケー プの設定の影響を受けるので、自動エスケープから保護したい変数はそのようにマー クしておく必要があるのです。

また、テンプレートタグがサブレンダリングのために新たなコンテキストを生成す る場合、そのコンテキスト変数に autoescape 属性を設定してください。 Context クラスの __init__ メソッドは、この目的のために、 autoescape というパラメタをとれるようになっています。例えば:

def render(self, context):
    # ...
    new_context = Context({'var': obj}, autoescape=context.autoescape)
    # ... 新しいコンテキストで何かする ...

このような状況はあまりありませんが、テンプレートタグ内で別のテンプレートを レンダする場合には便利です。例えば:

def render(self, context):
    t = template.loader.get_template('small_fragment.html')
    return t.render(Context({'var': obj}, autoescape=context.autoescape))

上の例で、 context.autoescape の値を渡し忘れると、出力の変数は 全て 自動エスケープされてしまい、その結果、テンプレートタグを {% autoescape off %} ブロック内で使った場合の出力が期待 とは違うものになってしまいます。

スレッドセーフ性を考慮する
リリースノートを参照してください

ノードがパージングされると、そのノードの render メソッドは何度も呼び出され る可能性があります。 Django はマルチスレッド環境で実行されることがあるので、 2 つの別のリクエストに対して 1 つのノードが異なるレスポンスコンテキストで同時に レンダリングされることがありえます。それ故、テンプレートタグをスレッドセーフに しておくことが大切です。

テンプレートタグがスレッドセーフかどうかを確認するには、ノード自身に決して状態 情報を保存してはいけません。例えば、 Django は組込の cycle テンプレー トタグを提供しています。これはレンダされるたびに与えられた文字列のリストを循環 させます:

{% for o in some_list %}
    <tr class="{% cycle 'row1' 'row2' %}>
        ...
    </tr>
{% endfor %}

CycleNode のナイーブな実装はこのような見た目になるかもしれません:

class CycleNode(Node):
    def __init__(self, cyclevars):
        self.cycle_iter = itertools.cycle(cyclevars)
    def render(self, context):
        return self.cycle_iter.next()

しかし上のスニペットが同時に 2 つのテンプレートレンダリングを行うと:

  1. スレッド 1 がループの 1 回目を実行し、 CycleNode.render() が ‘row1’ を 返します。
  2. スレッド 2 がループの 1 回目を実行し、 CycleNode.render() が ‘row2’ を 返します。
  3. スレッド 1 がループの 2 回目を実行し、 CycleNode.render() が ‘row1’ を 返します。
  4. スレッド 2 がループの 2 回目を実行し、 CycleNode.render() が ‘row2’ を 返します。

CycleNode は繰り返し実行されますが、その繰り返しはグローバルなものです。スレッ ド 1 とスレッド 2 に関しては、常に同じ値が返ります。これは明らかに私たちが望ん でいない動作です!

この問題に対応するために Django は、現在レンダされているテンプレートのコンテキ ストに関連づけられた render_context を提供します。 render_context は Python の辞書と同じように振る舞い、 render メソッドの実行ごとに Node の状態を保存するために使われます。

CycleNode の実装を render_context を使うようにリファクタリングしてみま しょう:

class CycleNode(Node):
    def __init__(self, cyclevars):
        self.cyclevars = cyclevars
    def render(self, context):
        if self not in context.render_context:
            context.render_context[self] = itertools.cycle(self.cyclevars)
        cycle_iter = context.render_context[self]
        return cycle_iter.next()

あるノードが存在するあいだに属性として変化しないであろうグローバルな情報の保存 については完全に安全であることに注意してください。 CycleNode の場合、 cyclevars 引数はノードがインスタンス化された後に変化しないので、それを render_context に入れる必要はありません。しかし、 CycleNode の繰り返し 状態のような、現在レンダされているテンプレートに特有の状態情報は、 render_context に保存されるべきです。

Note

render_context のなかで CycleNode 特有の情報を取得するために self を使ったことに注目してください。複数の CycleNodes が同じテン プレートのなかに存在するかもしれないので、別のノードの状態情報をめちゃく ちゃにしないように気をつけなければいけません。そのための最も簡単な方法は、 render_context のキーとして self を使うことです。複数の状態変更を 追跡したければ、 render_context[self] に辞書を格納してください。

タグの登録

最後に、上の「カスタムテンプレートフィルタを書く」の節で説明したように、タ グをモジュールの Library インスタンスに登録します:

register.tag('current_time', do_current_time)

tag() メソッドは二つの引数をとります:

  1. テンプレートタグの名前、文字列です。省略すると、コンパイル関数の名前 を使います。
  2. コンパイル関数。 Python の関数です (関数名を表す文字列ではありません)。

フィルタの登録と同様、この関数をデコレータとして使えます:

@register.tag(name="current_time")
def do_current_time(parser, token):
    ...

@register.tag
def shout(parser, token):
    ...

上の例の下の定義のようにして name 引数を省略すると、 Django は関数名を そのままフィルタ名として使います。

テンプレート変数をタグに渡す

token.split_contents() を使えば、テンプレートタグにいくつでも引数を渡せ ますが、引数はすべて文字列リテラルになってしまいます。そのため、テンプレー トタグの引数に動的なコンテンツ (テンプレート変数) を渡すには、もうひと工夫 必要です。

先に挙げた例では、現在時刻を文字列にフォーマットして文字列で値を返していま したが、今度は以下のように DateTimeField の値を 渡してテンプレートタグに日付と時刻をフォーマットさせたいとしましょう:

<p>この投稿が最後に更新されたのは{% format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %} です。</p>

まず、 token.split_contents() は以下の 3 つの値を返します:

  1. タグ名である format_time
  2. blog_entry.date_updated という 文字列
  3. フォーマット文字列 “%Y-%m-%d %I:%M %p” 。 split_contents() は、 文字列リテラルの先頭と末尾にあるクオート文字を除去しません。

今度は、タグの定義は以下のようになります:

from django import template
def do_format_time(parser, token):
    try:
        # split_contents() はクオート付き文字列を分解しない
        tag_name, date_to_be_formatted, format_string = token.split_contents()
    except ValueError:
        raise template.TemplateSyntaxError("%r tag requires exactly two arguments" % token.contents.split()[0])
    if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
        raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % tag_name)
    return FormatTimeNode(date_to_be_formatted, format_string[1:-1])

レンダラの方も変更して、 blog_entry オブジェクトの date_updated プ ロパティの実際の中身を取り出せるようにせねばなりません。これは django.templateVariable() クラスで実現します。

Variable クラスの使い方は、単に解決されるべき変数名を渡してインスタンスを 作り、それから variable.resolve(context) を呼びます。従って:

class FormatTimeNode(template.Node):
    def __init__(self, date_to_be_formatted, format_string):
        self.date_to_be_formatted = template.Variable(date_to_be_formatted)
        self.format_string = format_string

    def render(self, context):
        try:
            actual_date = self.date_to_be_formatted.resolve(context)
            return actual_date.strftime(self.format_string)
        except template.VariableDoesNotExist:
            return ''

現在のページのコンテキストに、 Variable に渡した名前がなかった場合、 名前解決の際に VariableDoesNotExist 例外が送出されます。

簡単なタグ

多くのテンプレートタグは、文字列やテンプレート変数への参照をいくつか引数と して取り、入力引数や外部の何らかの情報に基づいて処理を行った後、文字列を返 します。例えば、上で書いた current_time タグがその例で、フォーマット文 字列を指定して、時刻を文字列の形で返すようになっています。

この種のタグを簡単に作成できるようにするため、 Django では simple_tag というヘルパー関数を提供しています。この関数は django.template.Library のメソッドで、何らかの関数を引数にとり、その関数を render メソッドにラッ プし、これまでに述べてきたいくつかのお作法を適用した後、テンプレートシステ ムにタグを登録します。

simple_tag を使うと、上の current_time 関数は以下のように書けます:

def current_time(format_string):
    return datetime.datetime.now().strftime(format_string)

register.simple_tag(current_time)

デコレータ構文も使えます:

@register.simple_tag
def current_time(format_string):
    ...

simple_tag ヘルパ関数については、以下の点に注意してください:

  • 引数の個数チェックなどは関数の呼び出しの際に行われるので、わざわざ自 分でチェックしなくてもかまいません。
  • 関数に渡される引数がクオートされている場合、クオートは自動的に取り去 られます。従って、関数は通常の文字列を受け取ることになります。
  • 引数がテンプレート変数なら、関数に渡されるのは変数自体ではなく、 変数の現在値になります。
リリースノートを参照してください

もしテンプレートタグが現在のコンテキストにアクセスする必要があるなら、タグを登 録する時に takes_context 引数を使うことができます:

# ここで最初の引数は "context" と呼ばれなければ *いけません*
def current_time(context, format_string):
    timezone = context['timezone']
    return your_get_current_time_method(timezone, format_string)

register.simple_tag(takes_context=True)(current_time)

あるいはデコレータ構文を使います:

@register.simple_tag(takes_context=True)
def current_time(context, format_string):
    timezone = context['timezone']
    return your_get_current_time_method(timezone, format_string)

takes_context オプションの動きについてもっと詳しく知りたければ 埋込タグ の章を読んでくださ い。

リリースノートを参照してください

タグの名前を変更したければ、カスタムの名前を与えることができます:

register.simple_tag(lambda x: x - 1, name='minusone')

@register.simple_tag(name='minustwo')
def some_function(value):
    return value - 2
リリースノートを参照してください

simple_tag 関数は任意の位置指定引数 (positional arguments) またはキーワー ド引数を受け取ります。例:

@register.simple_tag
def my_tag(a, b, *args, **kwargs):
    warning = kwargs['warning']
    profile = kwargs['profile']
    ...
    return ...

すると、テンプレートでは、任意の数の引数を空白区切りでテンプレートタグに渡すこ とができます。 Python でそうなのと同じく、キーワード引数の値はイコール記号 (“=”) を使って、位置指定引数の後に渡される必要があります。例:

{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
埋め込みタグ

テンプレートタグによくあるもう一つのタイプは、 別の テンプレートをレンダ して表示するものです。例えば、 Django の admin インタフェースではカスタムの テンプレートタグを使って「追加/変更」フォームページのボタンを表示していま す。これらのボタンはいつも同じように表示されていますが、リンクのターゲット は編集対象のオブジェクトによって変わります。従って、こうした処理は、小さな テンプレートを使って現在のオブジェクトに応じた値を埋めるのが最良の方法と言 えます。 (admin の submit_raw がそのタグです)。

こうしたタグのことを 「埋め込みタグ (inclusion tag)」 と呼びます。

埋め込みタグの書き方を説明するには、例を挙げるのがベストでしょう。 チュートリアル で作成した Poll オブジェクトを 例に、ある Poll オブジェクトに対する選択肢のリストを出力するようなタグ を書いてみましょう。タグは以下のようになります:

{% show_results poll %}

出力は以下のようになります:

<ul>
  <li>First choice</li>
  <li>Second choice</li>
  <li>Third choice</li>
</ul>

まず、引数を受け取って、対応するデータの辞書を生成するような関数を定義しま す。ここで重要なのは、辞書を返さねばならず、それ以外の複雑なデータを返して はならないということです。戻り値はテンプレートフラグメントをレンダするとき のテンプレートコンテキストに使われます。例を示します:

def show_results(poll):
    choices = poll.choice_set.all()
    return {'choices': choices}

次に、タグの出力をレンダする際に使うテンプレートを作成します。このテンプレー トはタグ固有のもので、テンプレートデザイナではなくタグの開発者が書くべきも のです。上の例に従えば、テンプレートはとても単純な形になります:

<ul>
{% for choice in choices %}
    <li> {{ choice }} </li>
{% endfor %}
</ul>

さて、 Library オブジェクトの inclusion_tag() メソッドを呼び出して、 埋め込みタグを作成し、登録しましょう。上のテンプレートがテンプレートローダ の検索対象ディレクトリ下にある result.html だとすると、タグの登録は以下 のようにして行います:

# Here, register is a django.template.Library instance, as before
register.inclusion_tag('results.html')(show_results)
リリースノートを参照してください

ここでもデコレータ構文を使えます。従って、関数を定義する時点で下記のようにも書 けます:

@register.inclusion_tag('results.html')
def show_results(poll):
    ...

時として、埋め込みタグが大量の引数を取るようになっていて、テンプレートの作 者が全ての引数やその順番を管理しきれなくなるような場合があります。この問題 を解決するために、 Django では埋め込みタグに対して takes_context オプショ ンを提供しています。テンプレートタグの作成時に takes_context を指定する と、タグは必須の引数を取らなくなり、タグのラップしている Python 関数は単一 の引数を取るようになります。この引数には、タグが呼び出されたときのテンプレー トコンテキストが入ります。

例えば、メインページに戻るためのリンクに使う home_link および home_title という変数の入ったコンテキストの下で使う埋め込みタグを書いて いるとしましょう。タグの Python 関数は以下のようになります:

# 最初の引数は *必ず* "context" と *呼ばねばなりません*
def jump_link(context):
    return {
        'link': context['home_link'],
        'title': context['home_title'],
    }
# 定義したカスタムタグを takes_context=True の埋め込みタグとして登録する
register.inclusion_tag('link.html', takes_context=True)(jump_link)

(関数の最初のパラメタは 必ず context という名前に せねばならない の で注意してください。)

register.inclusion_tag() の行で、 takes_context=True を指定し、テン プレートの名前を指定しています。 link.html テンプレートの中は以下のよう になります:

Jump directly to <a href="{{ link }}">{{ title }}</a>.

このカスタムタグを使う場合は常に、まずライブラリを呼び出しておき、下記のよ うに引数なしでタグを呼び出します:

{% jump_link %}

takes_context=True を使っている場合、テンプレートタグに引数を渡す必要は ありません。タグが自動的にコンテキストにアクセスします。

takes_context パラメタはデフォルトでは False です。この値を True に設定すると、タグの引数にはコンテキストオブジェクトが渡されます。この点だ けは前述の inclusion_tag の例と異なります。

リリースノートを参照してください

inclusion_tag 関数は任意の数の位置指定引数またはキーワード引数を受け取るこ とができます。例:

@register.inclusion_tag('my_template.html')
def my_tag(a, b, *args, **kwargs):
    warning = kwargs['warning']
    profile = kwargs['profile']
    ...
    return ...

すると、テンプレートでは、任意の数の引数を空白区切りでテンプレートタグに渡すこ とができます。 Python でそうなのと同じく、キーワード引数の値はイコール記号 (“=”) を使って、位置指定引数の後に渡される必要があります。例:

{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
コンテキスト中の変数を設定する

上の例は、単に値を出力するという単純なものでした。一般的な話として、テンプ レートタグが値を出力するだけでなく、テンプレート変数の値を設定できたりする ともっと柔軟性が増すでしょう。そうすれば、テンプレートの作者はテンプレート タグのつくり出す変数を再利用できるようになります。

コンテキスト中に変数を設定するには、 render() メソッドで渡されるコンテ キストオブジェクトを辞書として代入するだけです。先程の CurrentTimeNode を変更して、値を出力するのではなく current_time というテンプレート変数 を設定した例を示します:

class CurrentTimeNode2(template.Node):
    def __init__(self, format_string):
        self.format_string = format_string
    def render(self, context):
        context['current_time'] = datetime.datetime.now().strftime(self.format_string)
        return ''

render() は空文字列を返していることに注意して下さい。 render() は常に文字列を出力せねばなりません。全てのテンプレートタグが変数の設定 しかしなければ、 render() は空の文字列を返すだけです。

新しいバージョンのタグの使い方を示します:

{% current_time "%Y-%M-%d %I:%M %p" %}<p>時刻は {{ current_time }} です。</p>

コンテキストにおける変数のスコープ

コンテキストにセットされるいかなる変数も、でそれが定義されたのと同じテンプ レートブロック (block) の中でしか使うことができません。この挙動は意図 的なもので、変数のスコープを提供しています。そのため異なるブロックのコンテ キストが変数が衝突することがありません。

ところで、 CurrentTimeNode2 には問題があります: 変数名 current_time がハードコードされているのです。これはすなわち、テンプレートの他の部分で {{ current_time }} を使わないようにせねばならないことを意味します。とい うのも、 {% current_time %} は変数の値を盲目的に上書きしてしまうからで す。より綺麗な解法は、出力用の変数名を定義させるというものです:

{% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
<p>時刻は {{ my_current_time }} です。</p>

この機能を実現するには、コンパイル関数と Node の両方をリファクタして、 以下のようにせねばなりません:

class CurrentTimeNode3(template.Node):
    def __init__(self, format_string, var_name):
        self.format_string = format_string
        self.var_name = var_name
    def render(self, context):
        context[self.var_name] = datetime.datetime.now().strftime(self.format_string)
        return ''

import re
def do_current_time(parser, token):
    # このバージョンはタグのコンテンツを解析するのに正規表現を使っています
    try:
        # Splitting by None == splitting by spaces.
        tag_name, arg = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError("%r tag requires arguments" % token.contents.split()[0])
    m = re.search(r'(.*?) as (\w+)', arg)
    if not m:
        raise template.TemplateSyntaxError("%r tag had invalid arguments" % tag_name)
    format_string, var_name = m.groups()
    if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
        raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % tag_name)
    return CurrentTimeNode3(format_string[1:-1], var_name)

ここでの違いは、 do_current_tume() がフォーマット文字列と変数名を取り、 CurrentTimeNode3 に渡すという点です。

Finally, if you only need to have a simple syntax for your custom context-updating template tag, you might want to consider using an assignment tag.

Assignment タグ
リリースノートを参照してください

コンテキストに変数をセットするタグを簡単に作れるように、 Django は assignment_tag ヘルパー関数を提供しています。この関数は simple_tag と同じように動作しま す。ただしこちらは指定したコンテキスト変数でのタグの結果を、直接出力する代わり に保存します。

少し前に示した current_time 関数はこのように書くことができます:

def get_current_time(format_string):
    return datetime.datetime.now().strftime(format_string)

register.assignment_tag(get_current_time)

デコレータ構文も使えます:

@register.assignment_tag
def get_current_time(format_string):
    ...

as 引数の後ろに変数名を続けることで、この結果をテンプレート変数に保存し、 ちょうどいい場所で自分で出力することができます:

{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p>

テンプレートタグが現在のコンテキストにアクセスする必要がある場合、 タグを登録する時に takes_context 引数を使うことができます:

# ここで最初の引数は "context" でなければ *いけません*
def get_current_time(context, format_string):
    timezone = context['timezone']
    return your_get_current_time_method(timezone, format_string)

register.assignment_tag(takes_context=True)(get_current_time)

デコレータ構文を使うこともできます:

@register.assignment_tag(takes_context=True)
def get_current_time(context, format_string):
    timezone = context['timezone']
    return your_get_current_time_method(timezone, format_string)

takes_context オプションの動きについてもっと詳しく知りたければ 埋込タグ の章を読んでくださ い。

assignment_tag 関数は任意の数の位置指定引数またはキーワード引数を受け取る ことができます。例:

@register.assignment_tag
def my_tag(a, b, *args, **kwargs):
    warning = kwargs['warning']
    profile = kwargs['profile']
    ...
    return ...

すると、テンプレートでは、任意の数の引数を空白区切りでテンプレートタグに渡すこ とができます。 Python でそうなのと同じく、キーワード引数の値はイコール記号 (“=”) を使って、位置指定引数の後に渡される必要があります。例:

{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile as the_result %}
他のブロックタグに到達するまでパージングする

テンプレートタグは違いに連携させられます。例えば、標準の {% comment %} というタグは、 {% endcomment %} までの全ての内容を出力しない %ようにします。このようなテンプレートタグを作るには、コンパイル関数中で %``parser.parse()`` を使います。

簡単な {% comment %} タグの実装方法を示します:

def do_comment(parser, token):
    nodelist = parser.parse(('endcomment',))
    parser.delete_first_token()
    return CommentNode()

class CommentNode(template.Node):
    def render(self, context):
        return ''

Note

{% comment %} の現実の実装はこれとは少し違っていて、 {% comment %}{% endcomment %} の間に壊れたテンプレートタグが現 れることを許容します。 parser.delete_first_token() の前で parser.parse(('endcomment',)) の代わりに parser.skip_past('endcomment') を呼び、ノードリストの生成を避けること によってそれを行っています。

parser.parse() は「そこまで読み進める」ブロックタグからなるタプルを引数 にとります。 parser.parse()django.template.NodeList のインスタ ンスを返します。このインスタンスは、タプルに指定したブロックタグのいずれか に到達する「より以前」に、パーザが出会った全ての Node オブジェクトから なるリストです。

上の例の "nodelist = parser.parse(('endcomment',))" では、 nodelist{% comment %} から {% endcomment %} までの全てのノードからなる リストになります。ただし、 {% comment %}{% endcomment %} 自体は除きます。

parser.parse() の呼び出し直後では、パーザはまだ {% endcomment %} タグを「消費」していないので、コードから明示的に parser.delete_first_token() を呼び出してやる必要があります。

CommentNode.render() は単に空文字列を返します。その結果、 {% comment %}{% endcomment %} の間の内容は全て無視されます。

次のブロックタグまでパージングして、内容を保存する

前節の例では、 do_comment(){% comment %} から {% endcomment %} までの全ての内容を無視しています。このような処理に代え て、ブロックタグ間のコードを使った処理も行えます。

例えば、 {% upper %} というカスタムのテンプレートタグを定義して、 {% endupper %} までの内容を大文字に変換できるようにします。

使い方はこのようになります:

{% upper %}This will appear in uppercase, {{ your_name }}.{% endupper %}

これまでの例と同様、 parser.parse() を使います。ただし、今回は得られた nodelistNode に渡します:

def do_upper(parser, token):
    nodelist = parser.parse(('endupper',))
    parser.delete_first_token()
    return UpperNode(nodelist)

class UpperNode(template.Node):
    def __init__(self, nodelist):
        self.nodelist = nodelist
    def render(self, context):
        output = self.nodelist.render(context)
        return output.upper()

UpperNode.render()self.nodelist.render(context) が、新たに導入 されたコンセプトを表しています。

複雑なレンダリングについて他にも例を見たければ、 {% if %}{% for %}, {% ifequal %}, {% ifchanged %} のソースを参照してください。ソースは django/template/defaulttags.py にあります。

カスタムのストレージシステムを作成する

revision-up-to:17812 (1.4)

ファイルを遠隔のシステム上に保存したい場合など、カスタムのファイルストレー ジを作成したいときには、カスタムストレージクラスを定義します。カスタムスト レージは、以下のステップに従って作成します:

  1. ストレージシステムは django.core.files.storage.Storage のサブクラス として実装します:

    from django.core.files.storage import Storage
    
    class MyStorage(Storage):
        ...
    
  2. Django はストレージシステムを引数なしでインスタンス化します。従って、 ストレージシステムに関する設定は、全て django.conf.settings から取り 出します:

    from django.conf import settings
    from django.core.files.storage import Storage
    
    class MyStorage(Storage):
        def __init__(self, option=None):
            if not option:
                option = settings.CUSTOM_STORAGE_OPTIONS
            ...
    
  3. ストレージクラスは、 _open() および _save() メソッドを実装せねば なりません。また、実現したいストレージクラスによってはその他にも適切なメ ソッドを実装せねばなりません。これらのメソッドについては下記を参照してく ださい。

    さらに、ローカルのファイルを扱うストレージを提供する場合は、 path() メソッドを提供せねばなりません。

カスタムのストレージシステムでは、以下のストレージメソッドをオーバライドで きます。メソッドの詳細は ファイルストレージ API で解説していますが、少な くとも以下のメソッドは 実装せねばなりません :

  • Storage.delete()
  • Storage.exists()
  • Storage.listdir()
  • Storage.size()
  • Storage.url()

また、ストレージオブジェクトの自作用に用意されている以下のフックをよく使う ことでしょう:

_open(name, mode='rb')

必須のメソッドです.

Storage.open() によって呼び出されます。このメソッドには、ストレージク ラスがファイルをオープンするときの実際のメカニズムを実装します。このメソッ ドは File クラスのオブジェクトを返さねばなりません。たいていのケースで は、バックエンドストレージに固有のロジックを備えた File のサブクラスを 返すことでしょう。

_save(name, content)

Storage.save() から呼び出されます。 nameget_valid_name()get_available_name() で処理済の名前で、 contentFile オブ ジェクトです。

実際に保存されたファイルの名前を返さねばなりません (ファイル名は通常 name と同じになるはずですが、ストレージシステムの都合でファイル名を変更 せねばならないときには、変更後の新しい名前を返してください)。

get_valid_name(name)

背後にあるストレージシステムで扱うのに適したファイル名を生成して返します。 このメソッドに渡す name 引数は、サーバに送信されたもとのファイルパスか ら、パス部分を取り除いたファイルの名前です。標準に従わないファイル名を安全 な形式に変換す仕組みをカスタマイズしたければ、このメソッドをオーバライドし てください。

Storage の実装では、ファイル名から英数文字、ピリオド、アンダースコアを 除く全ての文字を取り去ります。

get_available_name(name)

name に指定された名前をもとに、ストレージ機構で扱えるファイル名を構築し て返します。通常、 name 引数は、上で述べた get_valid_name() メソッ ドによって、ストレージシステムで扱うのに適した名前に変換済みです。

Storage の実装では、対象ディレクトリ下でファイル名が重複しそうな場合、 一意になるまで "_1", "_2" などを付加したファイル名を作成して返しま す。

Django のデプロイ

revision-up-to:17812 (1.4)

Django には、ウェブ開発者の負担を軽くするショートカットがぎっしりつまってい ますが、作ったサイトをデプロイできなければ元も子もありません。 Django プロ ジェクトの開始当時から、簡単なデプロイは大きな目標の一つでした。Django を簡 単にデプロイするいい方法はいくつもあります:

WSGI 環境にデプロイする方法

revision-up-to:17812 (1.4)

Django の主要なデプロイプラットフォームは、 Web サーバと Web アプリケーション に関して Python の標準である WSGI です。

Django の startproject 管理コマンドはシンプルなデフォルトの WSGI 設 定をセットアップします。プロジェクトと WSGI 準拠の Web サーバに合わせて、必要 なら微調整することができます。 Django には以下の WSGI サーバのための手引きとな るドキュメントが用意されています:

Apache と mod_wsgi 環境で Django を使う方法
revision-up-to:17812 (1.4)

Apachemod_wsgi の組み合わせは、推奨の Django の実運用環境です。

mod_wsgi は、 Django を含む WSGI インタフェース をサポートする Python アプリ ケーションを運用するときに使う Apache のモジュールです。 Django は mod_wsgi をサポートするすべてのバージョンの Apache 上で動作します。

mod_wsgi の公式ドキュメント はすばらしい出来で、 mod_wsgi を使う上で必要 なことがすべて書かれています。まずは インストールと設定のガイド から読み 始めるとよいでしょう。

基本的な設定

mod_wsgi をインストールして有効にしたら、 httpd.conf ファイルを編集して、 以下の宣言を追加してください:

WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
WSGIPythonPath /path/to/mysite.com

<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Order deny,allow
Allow from all
</Files>
</Directory>

WSGIScriptAlias の行の最初の引数は、アプリケーションを公開する場所 (/ はルート URL を表しています)、二つ目の引数はシステム上の「WSGI ファイル(後 述)」の場所です。 WSGI は通常、プロジェクトパッケージ (この例では mysite) の中に置きます。これで、 Apache はルート URL 以下のすべてのリクエストを、指定 の WSGI ファイルを使って処理します。

WSGIPythonPath の行は、プロジェクトのパッケージが Python パスでのインポー トで使えることを保証します。

<Directory> の部分は Apache が wsgi.py ファイルにアクセスできるこ とを保証します。

次に wsgi.py に WSGI application オブジェクトが含まれていることを保証 する必要があります。 Django 1.4 では、 startproject がそのファイルを作ってくれるでしょ う。それ以前のバージョンでは、自分で作成する必要があります。 このファイルに書くべき内容と、追加できる内容については WSGI 概要ドキュメ ント を参照してください。

virtualenv を使う

virtualenv の中にプロジェクトが依存する Python モジュールをインストールして いるなら、 virtualenv の site-packages ディレクトリも Python パスに追加す る必要があります。そのためには、 Apache の設定にもう一行追加してください:

WSGIPythonPath /path/to/your/venv/lib/python2.X/site-packages

virtualenv への正しいパスを設定しているか、 python2.X を正しい Python バー ジョン (python2.7 のような) で置き換えているかを確認してください。

mod_wsgi のデーモンモードを使う

「デーモンモード」は mod_wsgi を (Windows 以外のプラットフォームで) 動かすとき にお勧めのモードです。デーモンモードでの設定方法の詳細は mod_wsgi の公式ドキュメント を参照してください。デーモンモードを使う時に唯 一必要になる変更は、上の設定の WSGIPythonPath は使えず、代わりに python-path オプションを WSGIDaemonProcess に渡す必要があることです。 例:

WSGIDaemonProcess example.com python-path=/path/to/mysite.com:/path/to/venv/lib/python2.7/site-packages
メディアファイルの公開

Django 自身には、メディアファイルを自動的に公開する機能はありません。メディ アファイルの公開は Web サーバの仕事です。

メディアファイルの公開には、別個の Web サーバ、つまり Django を動作させてい ない別のサーバを使うよう勧めます。以下のようなサーバが、選択肢としておすす めです:

メディアファイルを Django が稼働しているのと同じ VirtualHost で公開せざ るを得ない場合には、 Apache を設定して、ある URL では静的なメディアを公開し、 別の URL では mod_wsgi インタフェースを介して Django に処理させるよう設定で きます。

以下の例では、 Django にサイトルート以下へのリクエストを処理させながら、 robots.txt, favicon.ico, CSS ファイル、および /media/ URL空間以 下のすべてのファイルは静的ファイルとして mod_wsgi に処理させます:

Alias /robots.txt /path/to/mysite.com/static/robots.txt
Alias /favicon.ico /path/to/mysite.com/static/favicon.ico

AliasMatch ^/([^/]*\.css) /path/to/mysite.com/static/styles/$1

Alias /media/ /path/to/mysite.com/media/
Alias /static/ /path/to/mysite.com/static/

<Directory /path/to/mysite.com/static>
Order deny,allow
Allow from all
</Directory>

<Directory /path/to/mysite.com/media>
Order deny,allow
Allow from all
</Directory>

WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py

<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Order allow,deny
Allow from all
</Files>
</Directory>
admin のファイルを公開する

Django の開発サーバは自動的に admin アプリケーションの静的ファイル (他のインス トールされたアプリケーションも) を公開しますが、他のサーバ編成を使っている時は そうなりません。 Apache や使用しているメディアサーバを設定し、 admin のファイ ルを公開できるようにしなければなりません。

admin ファイルは Django ディストリビューションの (django/contrib/admin/static/admin) にあります。

django.contrib.staticfiles を使って admin ファイルを扱うことを強くお勧 めします。 (前のセクションで概要を説明したように Web サーバを設定します。つま り collectstatic 管理コマンドを使って静的ファイルを STATIC_ROOT に集め、 Web サーバが STATIC_ROOTSTATIC_URL の場所で公開するよう設定します) しかし以下では別の方法を 3 つ挙げましょう:

  1. ドキュメントルートに admin の静的ファイルへのシンボリックを作ります。 (Apache の設定に +FollowSymLinks が必要になるでしょう)
  2. 上で示したように Alias ディレクティブを使って、適切な URL (おそらく STATIC_URL + admin/) から admin ファイルがある実際の場所へのエ イリアスを作ります。
  3. admin の静的ファイルをコピーし、 Apache のドキュメントルートに置きます。
Gunicorn で Django を使う方法
revision-up-to:17812 (1.4)

Gunicorn (Green Unicorn) は UNIX 向けのピュア Python 製 WSGI サーバです。他の ライブラリへの依存関係がなく、簡単にインストールして使うことができます。

Gunicorn で Django を使う方法は 2 通りあります。 1 つは Gunicorn に Django を 単なる 1 つの WSGI アプリケーションとして扱わせる方法です。もう 1 つは Gunicorn に特別に用意された Django インテグレーション機能 を使う方法です。

Gunicorn のインストール

Gunicorn のインストールは sudo pip install gunicorn だけで済みます。もっと 詳しいことが知りたければ Gunicorn ドキュメント を参照してください。

Gunicorn で Django を一般的な WSGI アプリケーションとして動かす

Gunicorn をインストールすると、 gunicorn コマンドで Gunicorn のサーバプロ セスを起動できるようになります。もっともシンプルな方法では、 Gunicorn は WSGI アプリケーションオブジェクトの場所を指定するだけで起動できます:

gunicorn [OPTIONS] APP_MODULE

ここで APP_MODULEモジュール名:変数名 というパターンになります。モ ジュール名はドット区切りのフルパスでなければなりません。変数名はモジュールの中 で探されるべき WSGI 呼び出し可能オブジェクトを指します。

典型的な Django プロジェクトでは、 Gunicorn の起動は次のようになります:

gunicorn myproject.wsgi:application

(このためにはプロジェクトが Python パス上にあることが必要です。それを確実にす るもっとも簡単な方法は、 manage.py ファイルがあるのと同じディレクトリでこ のコマンドを実行することです。)

Gunicorn の Django インテグレーション機能を使う

Gunicorn に組み込まれた Django インテグレーション機能を使うには、まず "gunicorn"INSTALLED_APPS に追加します。そして python manage.py run_gunicorn を実行します。

この方法は Django 向けの素敵な特徴を提供します:

  • Gunicorn のプロセス名にプロジェクト名をセットします
  • インストールされたモデルを検証します
  • admin のメディアファイルの場所を渡す --adminmedia オプションが使えます。 これは runserver の動作をまねします。

Gunicorn の デプロイドキュメント を読むと、 Gunicorn サーバを起動し、維持す るためのさらなるヒントが得られます。

uWSGI で Django を使う方法
revision-up-to:17812 (1.4)

uWSGI は、ピュア C で書かれた、高速で自己回復機能のある、開発者とシステム管理 者に優しいアプリケーションコンテナサーバです。

uWSGI の必要条件

uWSGI の Wiki にはいくつかの インストール条件 が書かれています。 Python の パッケージマネージャである pip を使うと、 uWSGI のどのバージョンのインストール も 1 つのコマンドでインストールできます。例えば:

# 現在の安定バージョンをインストールします
$ sudo pip install uwsgi

# または LTS (long term support) バージョンをインストールします
$ sudo pip install http://projects.unbit.it/downloads/uwsgi-lts.tar.gz
uWSGI の動作モデル

uWSGI はクライアント・サーバモデルで動作します。 Web サーバ (例えば Nginx, Apache など) は、動的なコンテンツを配信する Django-uWSGI の「ワーカー」プロセ スと通信します。もっと詳しく知るには、WSGI の バックグラウンドドキュメント を見てください。

uWSGI サーバに Django 向けの設定をし起動する

uWSGI はプロセスを設定する複数の方法をサポートしています。 uWSGI の 設定ドキュメント設定例 を見てください。

以下は uWSGI サーバを起動するコマンドの例です:

uwsgi --chdir=/path/to/your/project
    --module='mysite.wsgi:application' \
    --env DJANGO_SETTINGS_MODULE=mysite.settings \
    --master --pidfile=/tmp/project-master.pid \
    --socket=127.0.0.1:49152 \      # ソケットファイルも使えます
    --processes=5 \                 # ワーカープロセスの数
    --uid=1000 --gid=2000 \         # もし root で実行する場合、 uwsgi は権限を落とせます
    --harakiri=20 \                 # 20 秒以上かかるプロセスを再生成します
    --limit-as=128 \                # プロジェクトを 128 MB に制限します
    --max-requests=5000 \           # 5000 リクエストに応答したらプロセスを再生成します
    --vacuum \                      # exit する時に環境をクリアします
    --home=/path/to/virtual/env \   # virtualenv への追加パス
    --daemonize=/var/log/uwsgi/yourproject.log      # プロセスをバックグラウンドで実行します

ここでは mysite という名前のトップレベルプロジェクトパッケージがあり、その 中に WSGI の application を含む mysite/wsgi.py があることを仮定し ています。このレイアウトは、 Django の最近のバージョンで django-admin.py startproject mysite (mysite の箇所にはプロジェクト名が入ります) を実行し た時に作られるものです。このファイルがない場合、自分で作る必要があります。この ファイルに書くべきデフォルトの内容と、追加できる内容については WSGI 環境にデプロイする方法 ドキュメントを参照してください。

この例で Django 用のオプションは以下の通りです:

  • chdir: Python の import パスに必要なディレクトリのパスです。 – 例では mysite パッケージを含むディレクトリです。
  • module: 使われる WSGI モジュール – おそらく startproject が 作った mysite.wsgi モジュールです。
  • env: 少なくとも DJANGO_SETTINGS_MODULE を含める必要があります。
  • home: プロジェクトの virtualenv への追加パスです。

以下は ini ファイルでの設定例です:

[uwsgi]
chdir=/path/to/your/project
module='mysite.wsgi:application'
master=True
pidfile=/tmp/project-master.pid
vacuum=True
max-requests=5000
daemonize=/var/log/uwsgi/yourproject.log

以下は設定ファイルの使い方の例です:

uwsgi --ini uwsgi.ini

uWSGI ワーカーの起動、停止、リロードについて情報を得るには、 uWSGI プロセスの管理 ドキュメントを参照してください。

application オブジェクト

WSGI デプロイでのキー概念の一つは、中心となる application という呼び出し可 能オブジェクトを設定することです。 Web サーバはこれをあなたのコードとの連絡の ために使います。これはサーバにアクセスできる Python モジュールのなかで一般に application という名前のオブジェクトとして設定されるものです。

リリースノートを参照してください

startproject コマンドは、そのような application オブジェクトを含む projectname/wsgi.py ファイルを作ります。

Note

以前のバージョンの Django からのアップデートして、 wsgi.py ファイル がプロジェクト内にない場合は、単にプロジェクトのトップレベルパッケージに (おそらく settings.pyurls.py の次に) 下記の内容を含む ファイルを追加できます。 runserver がこの WSGI ファイルを使うようにしたければ、 WSGI_APPLICATION = "mysite.wsgi.application" を settings に追加します。 (mysite をプロジェクト名に置き換えてください)

最初の状態ではこのファイルは次のようになっています:

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")

# This application object is used by the development server
# as well as any WSGI server configured to use this file.
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

os.environ.setdefault の行は、明示的に DJANGO_SETTINGS_MODULE 環 境変数が設定されていなければ、デフォルトの設定を使うようにセットします。 settings モジュールへのパスが正しくなるように、この行の mysite をプロジェ クトのパッケージ名で置き換える必要があるでしょう。

WSGI middleware を適用するために、同じファイルの中で application オブジェク トを単純にラップすることができます:

from helloworld.wsgi import HelloWorldApplication
application = HelloWorldApplication(application)

また、Django アプリケーションと他のフレームワークの WSGI アプリケーションと を組み合わせたければ、あとで Django の WSGI application に処理を委譲するような カスタムの WSGI application を用意して Django の WSGI application を置き換える こともできます。

FastCGI, SCGI, AJP で Django を使う

revision-up-to:17812 (1.4)

Django を動作させるプラットフォームとして現在推奨しているのは WSGI ですが、多くの 人々が使っている共有ホスティングサービスには、 FastCGI や SCGI, AJP といっ たプロトコルしか選択肢がありません。

Note

このドキュメントでは、 FastCGI に重点をおいて説明しています。 SCGI や AJP といったプロトコルも、Python パッケージ flup 経由でサポートして います。 SCGI や AJP 固有の設定は、後述の 「 プロトコル 」の節を参照し てください。

FastCGI は、いわば外部アプリケーションによって Web サーバにページを提供させ る方法の一つです。Web サーバは (socket を介して) 受け取った Web リクエスト の処理を FastCGI に肩代りさせます。 FastCGI はコードを実行して、その応答を Web サーバに返します。 Web サーバはその内容をクライアントのWeb ブラウザに返 すというわけです。

WSGI と同様、 FastCGI はコードをメモリ上に残すので、リクエストはスクリプトの起 動時間を伴わずに処理されます。 ただし、例えば mod_wsgi が Apache Web サーバプロセスの 中に組み込まれるか、別のデーモンプロセスとして実行されるかを設定できるのに対 し、 FastCGI プロセスは Web サーバプロセスの中ではなく、別の永続的プロセスの中 で実行されます。

なぜ別のプロセスでコードを実行するのですか?

Apache における伝統的な mod_* の構成では、 Web サーバのプロセス空間 内に様々なスクリプト言語 (有名なのは PHP, Python, Perl です) を埋め込ん で実行します。この構成は、リクエストのたびにプログラムコードをディスク から読み出さなくてもよくなるため、起動時間を減らせるという利点がありま す — その反面、メモリの消費は莫大になります。

FastCGI の性質上、Web サーバプロセスと別のユーザアカウントでプロセスを 実行できます。この特徴は、自分のコードを他のユーザから守れるという点で、 共有ホストにおいてセキュリティ上の利点になります。

必要なもの: flup

Django で FastCGI を使うには、まず flup をインストールせねばなりません。 flup は FastCGI を使えるようにするための Python ライブラリです。 Django は バージョン0.5 以降の flup で動作します。

FastCGI サーバを起動する

FastCGI はクライアントサーバモデルで動作します。ほとんどの場合、 FastCGI プ ロセスを自分で起動することになるでしょう。 Web サーバ (Apache、 lighttpd な ど) が Djagno の FastCGI プロセスにアクセスするのは、サーバが動的ページをロー ドするときだけです。デーモンは常にコードをメモリ上にロードしたまま動作して いるので、非常に高速に応答を返せるのです。

Note

共有ホスティングサービスを使っているなら、Web サーバで管理された FastCGI プロセスを使わざるを得ないかもしれません。 Django を Web サーバ で管理された FastCGI プロセスで使うには、後に出て来る節の説明を参照して ください。

Web サーバが FastCGI サーバにアクセスするには二つの方法があります。一つは Unix ドメインソケット (Win32 システムにおける「名前付きパイプ」) で、もう一 つは TCP ソケットです。どちらを選ぶかは好みの問題です。パーミッションの問題 から、通常は TCP ソケットの方が簡単です。

サーバを起動するには、プロジェクトのあるディレクトリ (manage.py のある 場所) に移動して、 manage.pyrunfcgi コマンドを実行します:

./manage.py runfcgi [options]

runfcgihelp オプションだけを指定すると、利用可能な全ての オプションを表示します。

引数として、 socket, protocol, または、 host および port を指定せねばなりません。さらに、 Web サーバをセットアップする際に、FastCGI サーバを起動するときに使ったソケット 名か、ホスト/ポート番号の組合せを指定せねばなりません。後述の 実行例 を参照 してください。

プロトコル

Django は flup のサポートしている全てのプロトコル、すなわち fastcgi, SCGI, AJP1.3 (Apache JServ プロトコルバージョン 1.3) をサポートしていま す。使いたいプロトコルを指定するには、 protocol=./manage.py runfcgi のオプションに指定します。 <protocol_name>fcgi (デフォルト)、 scgi または ajp のいずれかです。例を以下に 示します:

./manage.py runfcgi protocol=scgi
実行例

TCP ポートを使い、スレッドモードでサーバを起動する場合:

./manage.py runfcgi method=threaded host=127.0.0.1 port=3033

Unix ドメインソケットを使い、 prefork モードでサーバを起動する場合:

./manage.py runfcgi method=prefork socket=/home/user/mysite.sock pidfile=django.pid

ソケットのセキュリティ

Django のデフォルトの umask では Web サーバと Django の fastcgi が同じグ ループ かつ 同じユーザで実行されることが必要です。セキュリティを強固に するには同じグループの別のユーザで実行させることができます。こうする場合は runfcgiumask 引数を使って umask に 0002 をセットします。

デーモン化 (バックグラウンド化) させずにプロセスを起動する場合 (デバッグ時 に便利です):

./manage.py runfcgi daemonize=false socket=/tmp/mysite.sock maxrequests=1
FastCGI デーモンを止める

フォアグラウンドでプロセスを走らせているのなら、止めるのは簡単で、 Ctrl-C を押して FastCGI サーバを止めるだけですみます。バックグラウンド プロセスを使っているのなら、 Unix の kill コマンドを使わねばなりません。

pidfile オプションを指定して runfcgi を起動しているの なら、以下のようにして起動中の FastCGI デーモンを殺せます:

kill `cat $PIDFILE`

$PIDFILE は起動時に指定した pidfile の値です。

Unix 上で FastCGI デーモンを簡単に再起動させたいなら、以下のようなシェルス クリプトを試してみましょう:

#!/bin/bash

# 以下の 3 つの設定は自分の環境に合わせて置き換える
PROJDIR="/home/user/myproject"
PIDFILE="$PROJDIR/mysite.pid"
SOCKET="$PROJDIR/mysite.sock"

cd $PROJDIR
if [ -f $PIDFILE ]; then
    kill `cat -- $PIDFILE`
    rm -f -- $PIDFILE
fi

exec /usr/bin/env - \
  PYTHONPATH="../python:.." \
  ./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE
Apache の設定

Django を Apache と FastCGI の構成で使うには、 Apache をインストールし、さ らに mod_fastcgi をインストールして有効にせねばなりません。詳しい手順は Apache のドキュメントを参照してください。

mod_fastcgi の構成が終ったら、 httpd.conf ファイルを編集して、 Apache に Django の FastCGI インスタンスを教えます。以下の二つの設定を行わねばなり ません:

  • FastCGIExternalServer ディレクティブを使って、 FastCGI サーバの場 所を指定します。
  • mod_rewrite を使って、リクエストが適切な FastCGI に向くようにしま す。
FastCGI サーバの場所を指定する

FastCGIExternalServer ディレクティブは、 Apache に FastCGI サーバの探し 方を教えます。 FastCGIExternalServer のドキュメント にもある通り、 socket または host のいずれかを指定せねばなりません。それぞれの例を 以下に示します:

# ソケットや名前付きパイプを経由して FastCGI に接続する場合
FastCGIExternalServer /home/user/public_html/mysite.fcgi -socket /home/user/mysite.sock

# TCP でホスト名とポート番号を指定して接続する場合
FastCGIExternalServer /home/user/public_html/mysite.fcgi -host 127.0.0.1:3033

いずれのケースでも、 /home/user/public_html/mysite.fcgi は実際に存在し なくてもかまいません。このパスは Web サーバが内部的に使う URL に過ぎず、 FastCGI で処理すべきリクエストを URL で区別するための単なるフックです。(次 節で詳しく説明します)

mod_rewrite を使って URL が FastCGI を指すようにする

第二ステップでは、特定のパターンに一致する URL では FastCGI を使うよう Apache に指示します。前節で述べたように、 mod_rewrite モジュールを使って、 URL を mysite.fcgi (または FastCGIExternalServer ディレクティブに指 定した名前) に書き換えます。

下記の例では、ファイルシステム上に存在せず、かつパスが /media/ で始まら ないファイルに対するリクエストに対して FastCGI を使うよう Apache に指示して います。Django の admin サイトを使っているなら、これはよくある状況でしょう:

<VirtualHost 12.34.56.78>
  ServerName example.com
  DocumentRoot /home/user/public_html
  Alias /media /home/user/python/django/contrib/admin/media
  RewriteEngine On
  RewriteRule ^/(media.*)$ /$1 [QSA,L,PT]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L]
</VirtualHost>

Django は、 {% url %} テンプレートタグ (や、同様のメソッド) で URL を構築する際、自動的にリライト前の URL を使います。

mod_fastcgi の代わりに mod_fcgid を使う

FastCGI 経由でアプリケーションを提供する別の方法が、 Apache の mod_fcgid モ ジュールを使うことです。 mod_fastcgi と比べると、 mod_fcgid の FastCGI アプリ ケーションの扱い方は、ワーカープロセスを自分自身で生成し、 FastCGIExternalServer のような何かを提供するのではないところが異なります。 このため設定が少し違った外見になります。

実際には、後ほど 共有ホスティング環境 での Django の動作について説明するのと同じように、スクリプトハンドラを追加すること になります。もっと詳しく知るには、どうぞ mod_fcgid リファレンス を参照して ください。

lighttpd での FastCGI 構成

lighttpd は静的ファイルのサービスによく使われている軽量な Web サーバです。 lighttpd はネイティブの FastCGI サポートを持っているので、 Apache の縛りが なくて、動的ページと静的ページの両方をサービスしたい場合には良い選択肢とい えます。

mod_fastcgi がモジュールリストに入っているか確かめてください。このとき、 mod_rewritemod_access よりも後ろにして、 mod_accesslog より も前にします。 admin メディアファイルを提供するなら、 mod_alias も必要 になるでしょう。

lighttpd 設定ファイルに以下の設定を追加してください:

server.document-root = "/home/user/public_html"
fastcgi.server = (
    "/mysite.fcgi" => (
        "main" => (
            # TCP で fastcgi に接続する場合は host / port を指定する
            # "host" => "127.0.0.1",
            # "port" => 3033,
            "socket" => "/home/user/mysite.sock",
            "check-local" => "disable",
        )
    ),
)
alias.url = (
    "/media/" => "/home/user/django/contrib/admin/media/",
)

url.rewrite-once = (
    "^(/media.*)$" => "$1",
    "^/favicon\.ico$" => "/media/favicon.ico",
    "^(/.*)$" => "/mysite.fcgi$1",
)
lighttpd を使って複数の Django サイトを駆動する

lighttpd には、ホストごとに設定をカスタマイズするための「条件付き設定 (conditional configuration)」があります。複数の FastCGI サイトを指定するに は、各サイトごとに FastCGI 設定を条件分岐のブロックにします:

# If the hostname is 'www.example1.com'...
$HTTP["host"] == "www.example1.com" {
    server.document-root = "/foo/site1"
    fastcgi.server = (
       ...
    )
    ...
}

# If the hostname is 'www.example2.com'...
$HTTP["host"] == "www.example2.com" {
    server.document-root = "/foo/site2"
    fastcgi.server = (
       ...
    )
    ...
}

fastcgi.server ディレクティブに複数のエントリを追加すれば、複数の Django を同じサイトでも駆動できます。各エントリごとに FastCGI ホストを追加 してください。

Cherokee を使う場合

Cherokee はとても高速で柔軟性があり、簡単に設定できる Web サーバです。 Cherokee は、FastCGI, SCGI, PHP, CGI, SSI, TLS や SSL による暗号化、バーチャ ルホスト、認証、動的エンコーディング、ロードバランシング、Apache 互換のログ ファイル、データベースのバランサ、リバース HTTP プロキシなどなど、最近の Webサーバがサポートしている様々な技術をサポートしています。

Cherokee プロジェクトのページには、 Cherokee で Django を運用する ための ドキュメントがあります。

Apache を使っている共有ホスティングプロバイダ上で Django を使う

共有ホスティングプロバイダの多くでは、独自のサーバデーモンを起動できなかっ たり、 httpd.conf ファイルを編集できなかったりします。このような場合で も、サーバ起動プロセスを使えば Django を駆動できます。

Note

この章で説明するような方法で Web サーバ起動プロセスを使う場合、 FastCGI サーバを自分で起動する必要はありません。Apache が必要に応じて複数のプロ セスを起動してくれます。

Web コンテンツのルートディレクトリ下に、以下のような内容のファイルを .htaccess という名前で保存します:

AddHandler fastcgi-script .fcgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ /mysite.fcgi/$1 [QSA,L]

次に、 Apache に FastCGI プログラムの起動方法を教える小さなスクリプトを作成 します。 mysite.fcgi というファイルを作成して Web コンテンツディレクト リに置き、実行可能にします:

#!/usr/bin/python
import sys, os

# Python のモジュール検索パスをカスタマイズする
sys.path.insert(0, "/home/user/python")

# カレントディレクトリをプロジェクトのディレクトリに移す (必要なら)
# os.chdir("/home/user/myproject")

# 環境変数 DJANGO_SETTINGS_MODULE を設定する
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"

from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")

これはサーバが mod_fastcgi を使っている場合に動作します。一方、 mod_fcgid を 使っている場合、 .htaccess ファイルでの少しの変更を除けば、セットアップは ほとんど同じです。 fastcgi-script ハンドラを追加する代わりに、 fcgi-handler を 追加する必要があります:

AddHandler fcgid-script .fcgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ mysite.fcgi/$1 [QSA,L]
起動中のサーバを再起動する

サイトを構成する Python コードを変更した場合、 FastCGI にコードが変更された ことを教えねばなりません。しかし、 FastCGI の場合には Apache を再起動する必 要はありません。その代わり、 mysite.fcgi を再度アップロードするか、ファ イルを編集して、タイムスタンプを更新してください。 Apache は、ファイルのタ イムスタンプが更新されていることを発見すると、Django アプリケーションを再起 動してくれます。

Unix システムでコマンドラインシェルへのアクセスが許されているなら、 touch コマンドを使えば簡単にタイムスタンプを更新できます:

touch mysite.fcgi
Admin メディアファイルの提供

サーバやその設定がどうあれ、何らかの形で admin メディアファイルを提供する方 法を考えておかねばなりません。 modwsgi のドキュメントには、上記の構成でも使えるアドバイスがあります。

URL のプレフィクス部分を特定の値にする

FastCGI を使った設置方法は、ほとんどが URL をリライトしてウェブサーバ内部の 別の場所を指すようにしています。このとき、 Django から見えるパス情報には、 もともとの URL が反映されません。そのため、 Django アプリケーションを特定の プレフィクスの下で動かしていて、 {% url %} タグで表示される URL を、 mysite.fcgi のようなリライト後のものでなく、プレフィクスのついた URL にしたいときに問題が生じます。

Django は実際のスクリプト名プレフィクスが何だったかをそれなりにうまく調べよ うとします。特に、ウェブサーバが SCRIPT_URL を設定する場合(Apache の modo_rewrite 特有の機能です) や、 REDIRECT_URL を設定する場合 (Apache と mod_rewrite をある構成で使ったとき) には、もとのプレフィクスを自動的に 見つけ出します。

Django がプレフィクスを正しく見付けられない場合や、リライト前の値を URL に 使いたい場合には、設定ファイル中で FORCE_SCRIPT_NAME を設定して ください。この変数には、全ての URL に共通なスクリプト名を指定します。したがっ て、別々のスクリプト名を持った URL に対応するには個別に設定ファイルを用意せ ねばなりませんが、そのようなケースは稀でしょう。

例えば、全てのコンテンツを '/' 以下の URL で提供するように Django を構 成しているなら、設定ファイルには FORCE_SCRIPT_NAME = '' と指定してくだ さい。

Apache と mod_python で Django を動かす

revision-up-to:17812 (1.4)

Warning

mod_python のサポートは非推奨となっており Django 1.5 で取り除かれる予定 です。新しいデプロイ設定をするなら mod_wsgi または他の サポートされている サーバ を使うことを強くお勧めします。

Apachemod_python モジュールを使えば、本番環境で Django をデプロイで きます。ただし、この方法は、よりシンプルな mod_wsgi による運用 を使う方法に取 って代わられつつあります。

mod_python は mod_perl とよく似ていて (影響を受けていて)、 Apache の中に Python を埋め込み、サーバ起動時に Python のコードをメモリ上に読み込みます。 読み込まれたコードは Apache のプロセスが生きている間ずっと残るので、他のや りかたに比べて明確なパフォーマンスの向上につながります。

Django を mod_python で動かす場合、 Apache 2.x と mod_python 3.x が必要です。 また、 Apache を使う場合、 worker MPM ではなく prefork MPM を使うよう 勧めます。

See also

基本的な設定

Django を mod_python で動かすようにするには、まず Apache がインストールされ、 mod_python モジュールが有効になっていることを確かめます。

次に、 httpd.conf ファイルを編集し、以下のような設定を追加します:

<Location "/mysite/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
    PythonOption django.root /mysite
    PythonDebug On
</Location>

mysite.settings は、 Django プロジェクトの設定ファイルを指す Python import パスになるよう、自分の環境に合わせて置き換えて下さい。

この設定は、 Apache に 「/mysite/ の下の全ての URL は mod_python で処理し、 処理には Django mod_python ハンドラを使うように」命令します。また、 DJANGO_SETTINGS_MODULE を渡して、 mod_python にどこに設定ファイルがあるのか教えます。

mod_python は、サイトを /mysite/ プレフィクスの下で提供していることを自 動的に検出できないので、 PythonOption django.root ... を使ってハンドラ に通知してやる必要があります。この行に設定する値は、 <Location ...> の引数と一致していなければなりません。 django.root を設定すると、 Django はリクエストの URL から django.root に設定されたプレフィクスを除 去した上で URLConf のパターンマッチングを行います。このため、後でサイト を /mysite2 に動かした際に、 djnago.root だけを変更すればよくなりま す。

django.root を使う場合、必ず、プレフィクスを除去した後の URL がスラッシュ で開始するようにしてください。 そうでないと、先頭にスラッシュの入る URLConf の設定があった場合、パターンマッチングがうまくいきません。上の例では、 /mysite/admin//admin/ に変えたいので、先頭から除去すべきなのは /mysite です。従って、 django.root の値を /mysite にしているの です。この場合、 /mysite/ (末尾にスラッシュがついている) にしてしまうと、 エラーをひき起こすでしょう。

上の例では <Directory> ではなく <Location> ディレクティブを使って います。前者はファイルシステム上の場所を指定するのに使い、後者はウェブサイ トのURL 構造上の場所を指定するのに使います。従って、 <Directory> を使っ た指定は意味をなさないのです。

また、 Django プロジェクトがデフォルトの PYTHONPATH 上になければ、以下 のような設定を mod_python に教えておく必要があります:

<Location "/mysite/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
    PythonOption django.root /mysite
    PythonDebug On
    PythonPath "['/path/to/project'] + sys.path"
</Location>

PythonPath には、アプリケーションから import したいモジュールの各々の 親ディレクトリを入れなければなりません。また、 DJANGO_SETTINGS_MODULE の親ディレクトリも入れねばなりません。対話シェル を使う場合に Python パスを設定するのと同じです。何かモジュールを import す る際には、Python は必ず sys.path の各ディレクトリを順に調べ、その下から 該当モジュールを import しようと試み、 import に成功するまで探索を続けます。

ところで、Python のソースファイルのパーミッションが、 Apache のプロセスを駆 動しているユーザ (たいていのシステムでは apache とか httpd というユー ザ名がついている) から読み出せるように設定されているか確かめておいてください。

さて、分かりやすくするために例を挙げましょう。アプリケーションを /usr/local/django-apps/ の下に配置しているとします (例えば、 /usr/local/django-apps/weblog/ のようにです) 。そして、設定ファイルが /var/www/mysite/settings.py だったとします。上の例のように DJANGO_SETTINGS_MODULE を設定しているなら、 PythonPath は以下のように書かねばなりません:

PythonPath "['/usr/local/django-apps/', '/var/www'] + sys.path"

これで、 import weblogimport mysite.settings は両方とも正しく実 行できます。コード中で import blogroll していて、 blogrollweblog/ ディレクトリの下にあるのなら、 /usr/local/django-apps/weblog/PythonPath に加えねばなりません。 import したいモジュールの 親ディレクトリ を Python パスに入れねばならな いことに注意してください。

Note

Windows を使っているなら、パスの表記に注意してください。 Windows は通常 バックスラッシュをネイティブのパス区切り文字に使いますが、それでもスラッ シュを使ってパスを表記するよう進めます。 Apache はスラッシュをプラット フォームネイティブのパス区切り文字に変換する方法を知っているので、スラッ シュを使った方が、可搬性や視認性を持たせられるのです。 (それに、バックス ラッシュの二重エスケープのようなトリッキーな問題を回避できます)。

Windows システムでも、以下のパス表記を利用できます:

PythonPath "['c:/path/to/project'] + sys.path"

また、 PythonAutoReload Off のようなディレクティブを設定して、パフォー マンスを向上させられます。使えるオプションのリストは mod_python のドキュメント を参照してください。

注意しなければならないのは、実運用のためのサーバでは、 PythonDebug Off を設定すべきであるということです。 PythonDebugOn に設定されたま まだと、 mod_python に不具合が生じたときに、恰好の悪い (そして赤裸々な) Python トレースバックを表示してしまいます。

Apache を再起動しましょう。 /mysite/ やその下の URL へのリクエストが Django によって提供されているはずです。 Django の URLconf は /mysite/ を切り取りらず、完全な URL を渡すことに注意して下さい。

Django で作られたサイトを mod_python 上で運営している場合、 Python コードに 対して変更を加える度に Apache を再起動する必要があります。

ひとつの Apache に複数の Django をインストールする

ひとつの Apache に複数の Django をインストールするのは簡単です。 VirtualHost を使って、以下のようにするだけです:

NameVirtualHost *

<VirtualHost *>
    ServerName www.example.com
    # ...
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</VirtualHost>

<VirtualHost *>
    ServerName www2.example.com
    # ...
    SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
</VirtualHost>

一つの VirtualHost 設定の中に複数の Django をインストールしたい場合、 mod_python のキャッシュが Django の動作を台無しにしないように特に気を配る必 要があります。 PythonInterpreter ディレクティブで、 <Location> ディ レクティブごとに別のインタプリタが使われるよう設定してください:

<VirtualHost *>
    ServerName www.example.com
    # ...
    <Location "/something">
        SetEnv DJANGO_SETTINGS_MODULE mysite.settings
        PythonInterpreter mysite
    </Location>

    <Location "/otherthing">
        SetEnv DJANGO_SETTINGS_MODULE mysite.other_settings
        PythonInterpreter othersite
    </Location>
</VirtualHost>

PythonInterpreter の値は、二つの Location ブロックの間で違う値にさ えなっていれば何でもかまいません。

mod_python 上で開発用サーバを動かす

開発用サーバに mod_python をえば、コードを変更する度にサーバを再起動するよ うなやんちゃは避けられます。 MaxRequestsPerChild 1 を Apache の httpd.conf ファイルに指定し、Apache にリクエストごとに全てをリロードさ せてください。とはいえ、これを実運用のサーバでやらないでください。さもない と、 Django ならではの恩恵が失われてしまいます。

あなたが print 文を散りばめてデバッグするタイプのプログラマなら、 stdout への出力は Apache のログには何も出力されず、 レスポンスエラーの原因になる ことさえある点に注意しましょう。

mod_python のセットアップでデバッグ情報を出力する必要があるなら、いくつかの方 法があります。次のように stderr に明示的に print することができます:

print >> sys.stderr, 'debug text'
sys.stderr.flush()

(stderr はバッファされるので、即座にデバッグ情報を表示されたいなら flush の呼び出しが必要なことに注意してください)

もっと簡潔なアプローチはアサーション (assertion) を使うことです:

assert False, 'debug text'

もう一つの方法は、ページのテンプレートにデバッグ情報を追加することです。

メディアファイルの提供

Django は、自分ではメディアファイルの提供を行わず、ユーザの選んだ Web サー バにその仕事を任せます。

メディアの提供には、別のウェブサーバ、すなわち Django を動かしていないサー バを使うよう勧めます。お勧めはいくつかあります:

とはいえ、Django を動作させているのと同じ Apache の VirtualHost でメディ アファイルや静的ファイルを提供せざるを得ない場合には、以下のようにして特定の 場所でだけ mod_python を切ります:

<Location "/media">
    SetHandler None
</Location>

Location ディレクティブの引数を、メディアファイルを置いている場所のルー ト URL に置き換えて下さい。 <LocationMatch> を使って、正規表現に一致さ せるようにもできます。

以下の例では、 Django をサイトのルートで設定し、 mediastatic サ ブディレクトリの下と、 .jpg.gif 、および .png で終わる URL だけでは明示的に Django を無効にしています:

<Location "/">
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</Location>

<Location "/media">
    SetHandler None
</Location>

<Location "/static">
    SetHandler None
</Location>

<LocationMatch "\.(jpg|gif|png)$">
    SetHandler None
</LocationMatch>
管理サイト用メディアファイルの提供

Django の開発サーバは自動的に管理サイトの静的ファイルを提供しますが、他 の構成では提供しません。管理サイトのメディアファイルを提供するには、 Apache なりその他のメディアサーバなりで設定を行う必要があります。

管理サイトのメディアファイルは Django 配布物の (django/contrib/admin/static/admin) ディレクトリ下に入っています。

django.contrib.staticfiles を使って admin のファイルを扱うことを 強く お勧めします。 (これは collectstatic 管理コマンドで STATIC_ROOT にファイルを集め、 STATIC_ROOT を Web サーバに STATIC_URL で提供させるよう に設定するということです) しかし、ここでは別の方法を 2 つ述べておきます:

  1. ドキュメントルートから admin メディアファイルへのシンボリックリンク を作ります。
  2. または、 admin メディアファイルをコピーして Apache のドキュメントルー トに入れます。
mod_python 上で “egg” パッケージを使う

Django を Python egg でインストールしたり、 Django から egg 化されたモジュー ルを使っている場合、いくつか追加の設定が必要です。プロジェクト中 (か、どこ か import できる場所) にファイルを作り、以下の内容を入れておきます:

import os
os.environ['PYTHON_EGG_CACHE'] = '/some/directory'

/some/directory は Apache httpd を動作させているプロセスが読み書き可能 なディレクトリにします。このディレクトリは、 egg のコードを展開する必要があ るときに使われます。

次に、 mod_python の PythonImport ディレクティブを使って、 mod_python が一 番最初にこのファイルを import するよう指定します。まず、前述の 上の節 で説明した PythonInterpreter ディレクティブを設定しておきます (複数の Django をイ ンストールしない場合でも必要です)。 次に、メインのサーバ設定 (LocationVirtualHost セクションの外) に、以下のように PythonImport 行を追加します:

PythonInterpreter my_django
PythonImport /path/to/my/project/file.py my_django

mod_python マニュアル で定義されている通り、モジュールの指定は絶対パス (またはドット区切りの import パス表記) で行えます。ここでは絶対パスを使って いますが、これは、 PythonImport を処理する時点では、プロジェクトへの Python パスを変更する操作がまだ完了していないからです。

エラー処理

Apache/mod_python を使っている場合、エラーは Django によって捕捉されます。 別の言い方をすれば、 エラーは Apache レベルまで伝播せず、 Apache の error_log には出力されないということです。

例外は Django のセットアップが全くうまくいっていない場合で、この場合には “Internal Server Error” がブラウザに表示され、 error_log ファイルには完 全な Python のトレースバックが出力されます。 (error_log トレースバック は複数のログエントリ行に展開されます (これは見苦しくて読みづらいのですが、 mod_python のやり方なので仕方ありません)。

セグメンテーション違反を起こす場合

Apache がセグメンテーション違反 (segumentation fault) を引き起こす場合、 2 種類の原因が考えられます。いずれも Django 自体とは関係のない原因です。

  1. Python コードが “pyexpat” モジュールを import している場合。 “pyexpat” は Apache に埋め込まれているバージョンと衝突する場合があり ます。詳しくは、 Expat Causing Apache Crash を参照してください。
  2. mod_python と mod_php を同じ Apache のインスタンスで動作させ、バック エンドに MySQL を使っている場合。PHP と Python MySQL バックエンドと のバージョン衝突で引き起こされる既知の問題かもしれません。これについ ては mod_python FAQ entry に詳しく書かれています。

mod_python を使った設定で問題を解決できない場合、まずは Django フレームワー クなしの素の mod_python サイトを動かすようにしてみるとよいでしょう。そうす れば、mod_python 固有の問題を簡単に切り分けられます。この手順については Getting mod_python Working で詳しく説明しています。

次のステップでは、テストコードを編集して、自分が使っている全ての Django 関 係のコード – ビュー、モデル、 URLconf, RSS の設定など – を import してみ ます。これらのモジュールを import する文をテストハンドラ関数に入れ、ブラウ ザでテストハンドラの URL にアクセスしてください。クラッシュするようなら、 Django コードの import が問題の原因だということになります。クラッシュしなく なるまで段階的に import するモジュールを減らしてゆき、原因のモジュールを特 定してください。原因のモジュールを調べて、中で import しているモジュールを 必要に応じて調べて下さい。

UnicodeEncodeError が出る場合

Django の国際化機能 (国際化とローカライズ 参照) を使っていて、ユーザにファイ ルアップロードをさせたいなら、 Apache が非 ASCII のファイルを受け入れるよ うに、 Apache を起動する環境変数をしかるべく設定してください。環境変数が正 しく設定されていないと、非 ASCII のファイル名を os.path() に渡したとき に UnicodeEncodeError 例外を引き起こすからです。

UnicodeEncodeError の問題を回避するには、 Apache を起動するときの環境変 数に、以下のような設定を入れておきます:

export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'

正しい環境変数の設定方法や設定場所は、オペレーティングシステムごとのドキュ メントを参照してください。 Unix プラットフォームでは、 /etc/apache2/envvars を使うのが一般的です。設定を行ったら、 Apache を再 起動してください。

はじめて Django や Python で作った Web アプリケーションをデプロイするのなら、 まずは mod_wsgi を使う方法 をお勧めしま す。 mod_wsgi を使えば、ほとんどの場合もっとも簡単で、高速で、安定したデプ ロイを実現できます。

See also

  • Django Book (2nd エディション) の 12 章 では、デプロイ方法と、とりわ けスケールアウトについて詳しく解説しています。しかしながら、このエディ ションは Django バージョン 1.1 に対して書かれていて、 mod_python が非推奨とされてからは更 新されていないことに気をつけてください。

エラー通知

revision-up-to:17812 (1.4)

サイトを公開しているときには、 DEBUG を常に切りましょう。 DEBUG を切ると、サーバの動作は軽くなり、エラーページを介して悪意 あるユーザにアプリケーションの詳細が漏れてしまうのを防げます。

その代わり、 DEBUGFalse にすると、サイト上で発生したエラー を一切表示できません。ユーザはみな、公開用に作られたエラーページを見るだけ です。実運用のサイトで発生したエラーを追跡したい場合のために、 Django はエ ラーの詳細について通知するように設定できます。

メールでの通知

サーバのエラー

DEBUGFalse にすると、コード内で例外が送出され、その例外 が捕捉されず、結果的に 500 エラーになった場合に、 Django は ADMINS 設定にリストされている全てのユーザにメールを送信します。 これは、管理者が何らかのエラーにすぐに気づけるようにするためで す。 ADMINS はエラーの説明文と、 Python トレースバックと、エラー を引き起こした HTTP リクエストの詳細情報を受け取ります。

Note

メールを送るためにはメールサーバへの接続方法についていくつかの設定をする ことが必要です。最低限、 EMAIL_HOST とおそらく EMAIL_HOST_USEREMAIL_HOST_PASSWORD が必要でし ょう。他の設定もメールサーバの設定によっては必要になるかもしれません。 メール関連の全ての設定のリストは Django 設定ドキュメント をあたってください。

デフォルトの設定では、 Django はメールの送信元に root@localhost を使います。 メールを処理するプロバイダの中には、 root@localhost から送信されたメールを 全て拒否するよう設定しているものがあります。送信者アドレスを変更したければ、 SERVER_EMAIL を変更してください。

メール通知機能を無効にするには、 ADMINS 設定から全てのユーザを削 除してください。

See also

リリースノートを参照してください

サーバエラーのメール通知はロギングフレームワークを使っているので、 ロギング設定のカスタマイズ によって動作を変更でき ます。

404 エラー

Django は、サイトのリンクが切れている (404 “page not found” エラーが発生す る) 時にメールを送信するよう設定できます。 404 エラーメールは、以下の条件下 で送信されます:

これらの条件が揃っていると、コード中で 404 例外が生じ、かつリクエストにリファ ラが設定されているときに、 Django は MANAGERS 設定に登録された全 てのユーザにメールを送信します (リファラ付きが条件なのは、リファラのないリ クエストに対する404 エラーで管理者を煩わせないためです)。

IGNORABLE_404_URLS を使えば、特定の 404 に対するレポート送信を抑 制できます。例えば:

import re
IGNORABLE_404_URLS = (
    re.compile(r'\.(php|cgi)$'),
    re.compile(r'^/phpmyadmin/'),
)

のようにすると、 URL が .php.cgi で終わるような URL や /phpmyadmin/ で始まる URL に対する 404 は報告 されません

以下は、ブラウザやクローラがよくリクエストする慣習的な URL を除外する例です:

import re
IGNORABLE_404_URLS = (
    re.compile(r'^/apple-touch-icon.*\.png$'),
    re.compile(r'^/favicon\.ico$'),
    re.compile(r'^/robots\.txt$'),
)

(正規表現のため、ピリオドの前にエスケープのためのバックスラッシュを置いている ことに注意してください)

この機能を無効にしたければ、 SEND_BROKEN_LINK_EMAILSFalse に設定してください。

See also

リリースノートを参照してください

404 エラーはロギングフレームワークを使って記録されます。デフォルトではこれ らのログレコードは無視されますが、ハンドラを書き、 ロギングの設定 を適切に行うことで、エラーレポート に使うことができます。

See also

リリースノートを参照してください

URL を通知対象外にするために、以前は 2 つの設定 IGNORABLE_404_STARTSIGNORABLE_404_ENDS が使われて いました。これらは IGNORABLE_404_URLS に置き換えられました。

エラー通知のフィルタリング

リリースノートを参照してください
センシティブ(機微)な情報をフィルタリングする

エラー通知はエラーをデバッグするのに実に役立ちます。一般的に、エラーに関係する 情報は可能な限り多く記録しておくと便利です。例えば、例外が起こった時、 Django はデフォルトで フルトレースバック と、それぞれの トレースバックフレーム のローカル変数、 HttpRequest属性 を記録します。

しかし、時にはある種の情報はセンシティブすぎて、追跡するのが適切ではないことが あります。例えば、ユーザーのパスワードやクレジットカードナンバーがそうです。そ のため Django は一揃いの関数デコレータ sensitive_variables()sensitive_post_parameters().を提供しています。 これらは運用環境 (つまり DEBUGFalse にセットされた環境) でど の情報をエラーレポートから除外すべきかを制御するのに役立ちます。

sensitive_variables(*variables)

もしあなたのコードの関数 (ビューや他の通常のコールバック) がセンシティブな 情報を含みうる変数を使っているなら、 sensitive_variables デコレータを 使うことで、それらの変数の値がエラーレポートに含まれることを避けることがで きます:

from django.views.decorators.debug import sensitive_variables

@sensitive_variables('user', 'pw', 'cc')
def process_info(user):
    pw = user.pass_word
    cc = user.credit_card_number
    name = user.name
    ...

上の例で、 user, pw, cc 変数はエラーレポートでは隠され、アスタ リスク (**********) に置き換えられます。一方、 name 変数の値は表示さ れます。

ある関数の全てのローカル変数を、一律にエラーログから隠すには、 sensitive_variables デコレータに何も引数を渡さないようにします:

@sensitive_variables()
def my_function():
    ...
sensitive_post_parameters(*parameters)

もしあなたのビューがセンシティブな情報を含みうる POST パラメータ を持つ HttpRequest オブ ジェクトを受け取るなら、 sensitive_post_parameters デコレータを使うこ とでそういったパラメータの値がエラーレポートに含まれることを防ぐことができ ます:

from django.views.decorators.debug import sensitive_post_parameters

@sensitive_post_parameters('pass_word', 'credit_card_number')
def record_user_profile(request):
    UserProfile.create(user=request.user,
                       password=request.POST['pass_word'],
                       credit_card=request.POST['credit_card_number'],
                       name=request.POST['name'])
    ...

上の例では、 POST パラメータの pass_wordcredit_card_number の 値がエラーレポート内のリクエストの表現では隠され、アスタリスク (**********) で置き換えられます。一方、 name パラメータの値は開示さ れます。

あるリクエストの全ての POST パラメータを、一律にエラーレポートから隠すに は、 sensitive_post_variables デコレータに何も引数を渡さないようにしま す:

@sensitive_post_parameters()
def my_view(request):
    ...

Note

リリースノートを参照してください

バージョン 1.4 以降、ユーザーパスワードのようなセンシティブな情報が漏れる のを防ぐために、特定の contrib.views.auth のビュー (login, password_reset_confirm, password_change および auth admin の add_viewuser_change_password) のエラーレポートから、全ての POST パラメータが一律に除外されるようになりました。

カスタムエラー通知

sensitive_variables()sensitive_post_parameters() が行っている のは、それぞれ、エラーが起こった時のレポートからセンシティブな情報が除外される ように、デコレートした関数をセンシティブな変数名で注釈づけておくことと、 HttpRequest オブジェクトをセンシティブな POST パラメータの名前で注釈づける ことです。実際のフィルタリングは Django のデフォルトのエラー通知フィルタ django.views.debug.SafeExceptionReporterFilter で行われます。このフィ ルタは、エラーレポートが生成される時、デコレータによる注釈に対応する値をアスタ リスク (**********) で置換します。もし、このデフォルトの動作をサイト全体で上 書きしたい、またはカスタマイズしたいなら、自分自身のフィルタクラスを定義し、 DEFAULT_EXCEPTION_REPORTER_FILTER 設定を通じて Django にそれを使う よう指示しなければなりません:

DEFAULT_EXCEPTION_REPORTER_FILTER = 'path.to.your.CustomExceptionReporterFilter'

あるいは HttpRequestexception_reporter_filter 属性にフィルタを設定 することで、任意のビューで使うフィルタをもっと細かく制御できます:

def my_view(request):
    if request.user.is_authenticated():
        request.exception_reporter_filter = CustomExceptionReporterFilter()
    ...

カスタムフィルタは django.views.debug.SafeExceptionReporterFilter を 継承しなければならず、以下のメソッドをオーバーライドできます。

class django.views.debug.SafeExceptionReporterFilter
SafeExceptionReporterFilter.is_active(self, request)

他のメソッドで実行されるフィルタリングを有効化するなら True を返しま す。デフォルトでは、 DEBUGFalse の時にフィルタが有効に なります。

SafeExceptionReporterFilter.get_request_repr(self, request)

リクエストオブジェクトの文字列表現を返します。つまり、その値は repr(request) によって返される値になるでしょう。ただし、 SafeExceptionReporterFilter.get_post_parameters() メソッドによって取 得される POST パラメータのフィルタされた辞書を使います。

SafeExceptionReporterFilter.get_post_parameters(self, request)

POST パラメータのフィルタされた辞書を返します。デフォルトでは、センシティ ブなパラメータの値をアスタリスク (**********) によって置き換えます。

SafeExceptionReporterFilter.get_traceback_frame_variables(self, request, tb_frame)

トレースバックフレームによって与えられたローカル変数の、フィルタされた辞書 を返します。デフォルトでは、センシティブなパラメータの値をアスタリスク (**********) によって置き換えます。

See also

自作の 例外ミドルウェア を書けば、エラー レポートを自作できます。エラー処理をカスタマイズしたければ、 Django 組 み込みのエラー処理をエミュレートして、 DEBUGFalse の ときだけ、レポートやログ記録を行うとよいでしょう。

モデルに初期データを投入する

revision-up-to:17812 (1.4)

アプリケーションを最初にセットアップするときに、データベースにハードコード されたデータを投入できると便利なことがあります。 Django に自動的に初期デー タを投入させる方法は二つあります: ひとつは フィクスチャによる初期データの 投入 で、もう一つは SQL による初 期データの投入 です。

フィクスチャによる初期データの投入

フィクスチャ (fixture) とは、 Django のデータベースに投入できるよう準備済み のデータの集まりです。すでにデータの入ったデータベースを持っているなら、フィ クスチャの生成には manage.py dumpdata コマンドを使うのが 一番簡単です。フィクスチャは手でも書けます。フィクスチャは XML, YAML または JSON ドキュメント形式で書けます。サポートされている シリアライゼーション フォーマット の詳細は シリアライゼーションのド キュメント を参照してください。

とはいえ、一例として、 JSON で書かれた Person モデルのフィクスチャを示 しておきます:

[
  {
    "model": "myapp.person",
    "pk": 1,
    "fields": {
      "first_name": "John",
      "last_name": "Lennon",
    }
  },
  {
    "model": "myapp.person",
    "pk": 2,
    "fields": {
      "first_name": "Paul",
      "last_name": "McCartney",
    }
  },
]

YAML で書くと以下のようになります:

- model: myapp.person
  pk: 1
  fields:
    first_name: John
    last_name: Lennon
- model: myapp.person
  pk: 2
  fields:
    first_name: Paul
    last_name: McCartney

フィクスチャデータはアプリケーションの fixture ディレクトリに保存します。

データのロードは簡単で、単に manage.py loaddata を実行するだけです。 <fixturename> はフィクスチャファイルの名 前です。 loaddata を実行するたびに、フィクスチャデータが読み出さ れ、データベースにリロードされます。つまり、フィクスチャによって生成されたレ コード行を変更して loaddata を再度実行すると、変更後のデータは消去 されてしまうのです。注意してください。

初期データフィクスチャの自動ロード

initial_data.[xml/yml/json] という名前のフィクスチャを作成しておくと、 syncdb を実行するたびに自動的にロードされます。この機能はとても 便利なのですが、一つだけ注意が必要です。というのも、 syncdb を実行するたびに 毎回 データがリフレッシュされるからです。ですから、 変更する予定のデータに initial_data を使ってはなりません。

Django がフィクスチャファイルを探す場所

デフォルトでは Django は各アプリケーション内の fixtures ディレクトリから フィクスチャを探します。 FIXTURE_DIRS に Django が調べるべき追加 ディレクトリのリストを設定することができます。

manage.py loaddata を実行する時にフィクスチャの絶対パス を指定することもできます。これは通常のディレクトリからの探索を上書きします。

See also

フィクスチャは テストフレームワーク で 一貫したテスト環境を構築するためにも使われています。

SQL による初期データの投入

Django には、データベースに任意の SQL を渡すためのフックがあります。 この SQL は、 syncdb を実行した時に CREATE TABLE 文の直後に実行されま す。このフックを使えば、自動的にデフォルトのレコードをテーブルに追加したり、 SQL関数やビュー、トリガなどを作成したりできます。

フックのからくりは単純です: Django はアプリケーション内の sql/<modelname>.sql という名前のファイルを探し、実行するだけです。 <modelname> は、モデル名を小文字にした文字列です。

このドキュメントの冒頭にある Person の例で、モデルが myapp の下に置 かれていたとすると、 myapp/sql/person.sql というファイルに任意の SQL 文 を指定できます。例えば以下のような命令を入れられます:

INSERT INTO myapp_person (first_name, last_name) VALUES ('John', 'Lennon');
INSERT INTO myapp_person (first_name, last_name) VALUES ('Paul', 'McCartney');

各 SQL ファイルには、必要なデータを INSERT するための有効な SQL 文を (すなわち、正しくフォーマットされた INSERT 文をセミコロンで区切って) 入 れておかねばなりません。

SQL ファイルは manage.pysqlcustom sqlreset, sqlall および reset コマンドの実 行時に参照されます。詳しくは manage.py のドキュメント を参照してください。

複数の SQL データファイルがある場合、個々のファイルを実行する順番は保証され ていないので注意して下さい。仮定していてよいのは、カスタムの SQL データファ イルを実行する前に、必ずデータベーステーブルは作成されているということだけ です。

初期 SQL データとテスト

テスト用の初期データを提供するためにこのテクニックを使うことは できません 。 Django のテストフレームワークは、全てのテストの後ごとにテ ストデータベースの内容をクリアします。結果として、カスタム SQL フックを 使って追加した全てのデータが失われることになります。

テストケースのためにデータが必要なら、 テストフィクスチャ を使って追加するか、 テストケースの setUp() でプログラム的に追加する必要があります。

データベースバックエンド特有の SQL データ

バックエンド特有の SQL データに対するフックもあります。例えば、 PostgreSQL と MySQL 向けに別々の初期データを用意できます。各アプリケーションごとに Django は <appname>/sql/<modelname>.<backend>.sql というファイルを探し ます。 <appname> はアプリケーションディレクトリの名前、 <modelname> はモデル名を小文字にした文字列、 <backend> は設定ファイルの ENGINE に指定するモジュール名の最後の部分です。 (ENGINE の値に django.db.backends.sqlite3 に定義したなら Django は <appname>/sql/<modelname>.sqlite3.sql を探します)

バックエンド固有の SQL データは、バックエンド非固有の SQL データよりも前に 実行されます。例えば、アプリケーション中に sql/person.sql および sql/person.sqlite3.sql が入っていて、 SQLite をバックエンドにしてインス トールを行った場合、 Django はまず sql/person.sqlite.sql の内容を実行して から sql/person.sql を実行します。

Jython 上で Django を動かす

revision-up-to:17812 (1.4)

Jython は Java プラットフォーム (JVM) 上で動作する Python 実装です。 Django は バージョン 2.5 以降の Jython で問題なく動作します。つまり、 Java プラットフォームで Django をデプロイできるのです。

このドキュメントでは、 Jython 上で Django をセットアップして動作させる方法 を説明します。

Jython のインストール

Django を動かすにはバージョン 2.5b3 以降の Jython が必要です。 Jython は http://jython.org/ からダウンロードします。

サーブレットコンテナを作成する

Django を試してみたいだけなら、この節は飛ばして次の節に進んでください。 Django にはテスト用の軽量なウェブサーバが付属しているので、実運用環境でデプ ロイするまで、特にセットアップ作業は必要ないからです。

Django を実運用環境で使いたければ、 Apache Tomcat のような Java のサーブ レットコンテナを使ってください。 GlassFishJBoss のようなフル JavaEE アプリケーションサーバも OK で、組み込みの機能を使えます。

Django のインストール

次は Django 自体をインストールしましょう。このステップは、 Python 環境への Django のインストールと全く同じなので、 旧バージョンの Django の除去Django コードのインストール を参 照してください。

Jython プラットフォームのサポートライブラリをインストールする

django-jython プロジェクトには、データベースバックエンドと、 Django/Jython 開発用の管理コマンドが入っています。 Django 組み込みのデータ ベースバックエンドは Jython では動かないので注意してください。

プロジェクトのウェブサイトに書かれている インストールの解説 を読んでインストー ルしてください。また、 データベースバックエンド の説明も参 照してください。

CPython で動かすときとの違い

今のところ、 Jython で動かした Django は標準の Python で動かした Django と ほとんど同じようにふるまいます。ただし、いくつか違いがあるので注意してくだ さい:

  • python コマンドの代わりに jython を使ってください。 Django の ドキュメントでは、一貫性のために python と表記していますが、実際 にコマンドラインを入力するときには jython に読み変えてください。
  • 同様に、環境変数 PYTHONPATH の代わりに JYTHONPATH を使う必要 があります。

古いデータベースを Django に組み込む

revision-up-to:17812 (1.4)

Django が最も得意とするのは新たなアプリケーションですが、古いデータベースの 組み込みも可能です。 Django には組み込み作業を可能な限り自動化するための二 つのユーティリティが付属しています。

このドキュメントでは、読者は 公式チュートリアル のカバーしている Django の基礎を良く知っているものと仮定しています。

Django にデータベースパラメタを指定する

まず、データベースへの接続パラメタとデータベース名を Django に指示する必要 があります。 DATABASES 設定を編集し、 'default' コネクション に次をキーとして値を設定してください:

  • NAME
  • ENGINE
  • USER
  • PASSWORD
  • HOST
  • PORT

モデルの自動生成

Django には、既存のデータベースにイントロスペクションを行ってモデルを生成で きるコマンド、 inspectdb が付属しています。出力を見るには以下の コマンドを実行します:

python manage.py inspectdb

標準の Unix 出力リダイレクションを使って、この内容をファイルに保存しておき ます:

python manage.py inspectdb > appname.py

この機能はショートカット目的で、正しいモデル生成を行うためのものではありま せん。詳しくは django-admin.py のドキュメント を参照 してください。

モデルを整理し終えたら、モジュールをアプリケーションの models.py に入れ、 アプリケーションを収めているパッケージ内に配置して、 INSTALLED_APPS 設定にアプリケーションを追加しておきます。

Django のコアデータテーブルのインストール

次に、 syncdb コマンドを実行して、 Django のコアデータテーブルを データベースにインストールします:

python manage.py syncdb

テストと確認

ここまでで解説したのは基本です。この後は、生成したモデルが正しく動作するま で変更してゆく必要があるでしょう。 Django データベース API を使ってアプリケー ションのデータにアクセスしたり、 Django admin サイトでオブジェクトを編集し てみたりしてください。

Django で CSV を出力する

revision-up-to:17812 (1.4)

このドキュメントでは、 Django のビューを使って動的に CSV (Comma Separated Values: カンマ区切りのフィールドデータ) ファイルを生成する方法について説明 します。 CSV の生成には Python CSV ライブラリ、または Django テンプレートシス テムが使えます。

CSV ライブラリを使う方法

Python には CSV ライブラリモジュール csv がついてきます。Django で csv を使う上での鍵は、モジュールの CSV 生成機能がファイルライクオ ブジェクトを扱えることと、 Django の HttpResponse オ ブジェクトがファイルライクオブジェクトであることです。

一例を示します:

import csv
from django.http import HttpResponse

def some_view(request):
    # 適切な CSV 用ヘッダとともに HttpResponse オブジェクトを生成します。
    response = HttpResponse(mimetype='text/csv')
    response['Content-Disposition'] = 'attachment; filename=somefilename.csv'

    writer = csv.writer(response)
    writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
    writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])

    return response

コードとコメントを読めば一目瞭然ですが、いくつか注意しておいたほうがよいで しょう:

  • レスポンスの MIME タイプを text/csv にしておき、ブラウザにド キュメントが CSV であると伝えます。 MIME タイプを指定しないと、出力をHTML と して解釈するので、ブラウザウィンドウに見苦しいごみのような出力が表示されてし まいます。
  • さらに、レスポンスオブジェクトには Content-Disposition ヘッダを指 定しています。このヘッダは CSV ファイルの名前にします。ファイル名には 何を指定しても構いません。この名前は、ブラウザが「名前を付けて保存」 ダイアログなどで使います。
  • CSV 生成 API のフックは簡単です: responsecsv.writer の第 一引数に指定します。 csv.writer クラスはファイルライクオブジェク トを扱うようになっているので、 HttpResponse オ ブジェクトを使えます。
  • CSV ファイルの各行ごとにリストやタプルのようなイテレーション可能オブ ジェクトを渡して writer.writerow を呼び出します。
  • CSV モジュールはクオート処理を行ってくれるので、文字列中にクオートや カンマがあっても心配することはありません。出力したい値を writerow() に渡せば、モジュールが正しく処理してくれます。
Unicode を扱うには

Python の csv モジュールは Unicode の入力をサポートしていません。 Django は内部的に Unicode を使うので HttpRequest のよう なソースから文字列を読み込むことは潜在的に問題を抱えていることになります。この 問題の対処方法はいくつかあります:

  • 全ての Unicode オブジェクトを互換性のあるエンコーディングに手動でエンコード します。
  • python-unicodecsv モジュール を使う。これは Unicode を上品に扱うモジュー ルで、 csv モジュールを容易に置き換えることを目的にしています。

もっと情報が必要なら csv モジュールのドキュメントを参照してください。

テンプレートシステムを使う方法

csv を使う代りに Django テンプレートシステム を使っても CSV を生成できます。この方法よりも csv` モジュールを使った方 がより高水準で実現できますが、完全さのために紹介しておきます。

基本的な考え方は、テンプレートに要素リストを渡し、テンプレート上の for ループの中でコンマとともに出力するというものです。

上と同じ CSV ファイルを生成する例を示します:

from django.http import HttpResponse
from django.core.template import loader, Context

def some_view(request):
    # 適切な CSV 用応答ヘッダを持った HttpResponse オブジェクトを
    # 作成します。
    response = HttpResponse(mimetype='text/csv')
    response['Content-Disposition'] = 'attachment; filename=somefilename.csv'

    # ここではデータをハードコードしていますが、実際にはデータベースな
    # のデータソースから取り出せます。
    csv_data = (
        ('First row', 'Foo', 'Bar', 'Baz'),
        ('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
    )

    t = loader.get_template('my_template_name.html')
    c = Context({
        'data': csv_data,
    })
    response.write(t.render(c))
    return response

前節の例との違いは、 CSV モジュールの代りにテンプレートをロードしている点だ けです。それ以外のコード、例えば mimetype='text/csv' のような部分はまっ たく同じです。

次に、 my_template_name.txt というテンプレートを以下のように書きます:

{% for row in data %}"{{ row.0|addslashes }}", "{{ row.1|addslashes }}", "{{ row.2|addslashes }}", "{{ row.3|addslashes }}", "{{ row.4|addslashes }}"
{% endfor %}

このテンプレートはきわめて基本的なものです。テンプレートは指定されたデータ に渡って繰り返し CSV の各行を表示してゆきます。クオートで問題が生じないよう、 addslashes テンプレートフィルタを使っています。データに引用符 (一重と二重の両方) が入っていないと保証できる場合は addslashes フィルタを外してもかまいません。

他のテキストベース形式のデータを出力するには

ここで示した例の大部分は、 CSV 固有の内容ではないことに注意してください。 CSV に関する部分といえば、出力形式くらいのものです。同じようなテクニックを 使えば、 どんなテキスト形式のデータでも生成できるのです。バイナリデータを生 成するときにも、同じようなテクニックを使えます。 Django で PDF を出力する を参照してください。

Django で PDF を出力する

revision-up-to:17812 (1.4)

このドキュメントでは、 Django のビューを使って動的に PDF ファイルを生成する 方法について説明します。 PDF を生成するには、優れたオープンソースの Python 用 PDF ライブラリである ReportLab を使います。

動的に PDF ファイルを生成できると、ユーザごとに違ったコンテンツの PDF を生 成するといった具合に、目的ごとに PDF 生成をカスタマイズできます。

例えば、 kusports.com では、March Madness contest の参加者向けに、 Django を使ってカスタマイズ可能な印刷むきの NCAA トーナメント試合表を PDF で生成し ていました。

ReportLab のインストール

ReportLab ライブラリは http://www.reportlab.org/oss/rl-toolkit/downlods/ から ダウンロードしてインストールします。

インストール方法は ユーザガイド (はからずも PDF ファイルですが) に書かれ ています。

インストールがうまく行っているか、 Python 対話シェルで import してみて確か めます:

>>> import reportlab

エラーを送出しなければ、インストールはうまくいっています。

ビューを書く

Django を使った PDF 動的生成の鍵は、ファイル ReportLab の API がファイルラ イクオブジェクトのように動作し、 Django の HttpResponse オブジェクトもまた、ファイルライクオブジェ クトのように振舞うところにあります。

いわゆる “Hello World” サンプルを示します:

from reportlab.pdfgen import canvas
from django.http import HttpResponse

def some_view(request):
    # 適切な PDF 用応答ヘッダを持った HttpResponse オブジェクトを
    # 作成します。
    response = HttpResponse(mimetype='application/pdf')
    response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'

    # レスポンスオブジェクトを出力「ファイル」にして、 PDF オブジェクト
    # を作成します。
    p = canvas.Canvas(response)

    # PDF に描画します。 PDF 生成のキモの部分です。
    # ReportLab の詳しい機能は ReportLab ドキュメントを参照してください。
    p.drawString(100, 100, "Hello world.")

    # PDF オブジェクトをきちんと閉じて終わり。
    p.showPage()
    p.save()
    return response

コードとコメントを読めば一目瞭然ですが、いくつか注意しておいたほうがよいで しょう:

  • レスポンスの MIME タイプは application/pdf にします。これによ り、ブラウザにドキュメントが PDF であると指示します。 MIME タイプを指定しな いと、出力を HTML として解釈するので、ブラウザウィンドウに見苦しいごみのよう な出力が表示されてしまいます。

  • さらに、レスポンスオブジェクトには Content-Disposition ヘッダを指 定しています。このヘッダは PDF ファイルの名前にします。ファイル名には 何を指定しても構いません。この名前は、ブラウザが「名前を付けて保存」 ダイアログなどで使います。

  • 上の例では、 Content-Disposition ヘッダは 'attachment; ' から 始まっています。ヘッダを 'attachment; ' で始めると、ウェブブラウ ザは application/pdf に対するデフォルトの操作を指定していても、 ダイアログパネルを出して、ドキュメントの処理方法を選択するようユーザ に促します。以下のように 'attachment;' を入れない場合、ブラウザは デフォルトの設定を使って PDF を処理します:

    response['Content-Disposition'] = 'filename=somefilename.pdf'
    
  • ReportLab API のフックは簡単です: responsecanvas.Canvas の第一引数に指定します。 Canvas クラスはファイルライクオブジェク トを扱うようになっているので、 django.http.HttpResponse オブ ジェクトを使えます。

  • PDF オブジェクト (ここでは p) を生成した後は、 response では なく p を使って PDF 生成メソッドを呼び出していることに注意して下 さい。

  • 最後に必ず showPage() を呼び出し、 PDF ファイルを save() して ください。

複雑な PDF の生成

ReportLab を使って複雑な PDF を作成したければ、一時的なファイルの保存に cStringIO ライブラリを使ってください。 cStringIO ライブラリはこ のような目的に対してとても効率的なファイルライクオブジェクトを提供します。 cStringIO で書き直した上の “Hello World” の例を示します:

# cStringIO が使えない環境では StringIO にフォールバックします
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO
from reportlab.pdfgen import canvas
from django.http import HttpResponse

def some_view(request):
    # 適切な PDF 用応答ヘッダを持った HttpResponse オブジェクトを
    # 作成します。
    response = HttpResponse(mimetype='application/pdf')
    response['Content-Disposition'] = 'attachment; filename=somefilename.pdf'

    buffer = String()

    # StringIO オブジェクトを出力「ファイル」にして、 PDF オブジェクト
    # を作成します。
    p = canvas.Canvas(buffer)

    # PDF に描画します。 PDF 生成のキモの部分です。
    # ReportLab の詳しい機能は ReportLab ドキュメントを参照してください。
    p.drawString(100, 100, "Hello world.")

    # PDF オブジェクトをきちんと閉じます。
    p.showPage()
    p.save()

    # StringIO バッファの値を取り出して、レスポンスオブジェクトに
    # 書き込みます。
    pdf = buffer.getvalue()
    buffer.close()
    response.write(pdf)
    return response

その他のリソース

  • Python バインディングを持つ別の PDF 生成ライブラリに PDFlib がありま す。 Django から使うには、このドキュメントで述べたのと同じ方法を使い ます。
  • Pisa XHTML2PDF もまた、 PDF 生成のためのライブラリです。 Pisa には、 Django と Pisa を組み合わせ方の例が付属しています。
  • HTMLdoc は HTML を PDF に変換できるコマンドラインスクリプトです。 HTMLdoc に Python インタフェースはありませんが、 systempopen のようなシェルを実行して、出力を Python から取り出せます。

その他のフォーマット

ここで示した例の大部分は、 PDF 固有の内容ではないことに注意してください。 PDF に関する部分といえば reportlab くらいのものです。同じようなテクニッ クを使えば、 Python のライブラリが扱えるどんなフォーマットのデータでも生成 できるのです。もう一つの例として、テキストベースの出力をしている Django で CSV を出力する も参照してください。

静的ファイルの公開方法

revision-up-to:17812 (1.4)
リリースノートを参照してください

Django の開発者は、ビューや、リクエストごとに新しくレンダリングされるテンプ レートといった、 Web アプリケーションの動的な部分にもっぱら関心を持っていま す。しかし、 Web アプリケーションには静的なファイル ( 画像、CSS、JavaScriptな ど ) も含まれています。完全な Web ページをレンダリングするためにはこういった ファイルが必要です。

小さなプロジェクトではこのことは大きな問題になりません。 Web サーバが見つけら れる場所で静的ファイルを単に管理することができるからです。しかし、もっと大きな プロジェクトで、特に複数のアプリケーションからなる場合は、各アプリケーションが 持っている静的ファイルの集まりを複数扱うことになり、ややこしくなってきます。

django.contrib.staticfiles はまさにそのためにあります。これは静的なファイ ルを各アプリケーションから (さらに指定した別の場所からも) 一つの場所に集め、運 用環境で公開しやすくするものです。

Note

もし django-staticfiles アプリケーションを使ったことがあるなら、 django.contrib.staticfiles はよく似たものに見えるでしょう。それはこの 2 つが本質的に同じコードだからです。 django.contrib.staticfilesdjango-staticfiles として生まれ、 Django 1.3 に取り込まれました。

django.contrib.staticfiles を使う

基本的な使い方
  1. staticfiles が見つけられる場所に静的ファイルを置いてください。

    デフォルトでは、 INSTALLED_APPS に入っているアプリケーションの static/ サブディレクトリです。

    おそらく、あなたのプロジェクトには特定のアプリケーションに結びついていない 静的なファイルもあるでしょう。 STATICFILES_DIRS には、静的ファイ ルをロードする時にチェックすべきファイルシステム上のディレクトリを、タプル で記述します。

    staticfiles がファイルを探す方法の詳細について知るには STATICFILES_FINDERS 設定のドキュメントを参照してください。

  2. INSTALLED_APPSdjango.contrib.staticfiles が入っているこ とを確認してください。

    ローカル環境での開発runserver を使っているか、 staticfiles_urlpatterns を URLconf に追加し てあるなら、これでセットアップは終わりです。 自動的に STATIC_URL で静的ファイルが公開されます。 ( newly created プロジェクトでは ) デフォルト設定が /static/ です。

  3. きっとこれらのファイルをテンプレートで使いたいでしょう。一番簡単な方法は コンテキストプロセッサを使うことです。次のようなテンプレートを書けます:

    <img src="{{ STATIC_URL }}images/hi.jpg" />
    

    もっと詳しいことは staticfiles-in-templates に書いてあります。テンプ レートタグを使う別の方法も 書かれています

ごく簡単に、静的ファイルのデプロイについて

ローカル環境での開発が終わり、プロジェクトをデプロイする準備ができたら:

  1. STATIC_URL を静的なファイルを指すパブリックな URL に設定してくだ さい。 ( ほとんどの場合、デフォルト値である /static/ でうまく行きます )

  2. STATIC_ROOT に、 collectstatic コマンドを使って静的な ファイルを集めたいファイルシステム上のパスを設定してください。例えば:

    STATIC_ROOT = "/home/jacob/projects/mysite.com/sitestatic"
    
  3. collectstatic コマンドを実行してください:

    ./manage.py collectstatic
    

    このコマンドは静的ファイルのストレージを漁って、見つけたファイルを STATIC_ROOT で与えられたディレクトリにコピーします。

  4. STATIC_ROOT に含まれるファイルが STATIC_URL の場所で 公開されるように Web サーバを設定しデプロイしてください。

    staticfiles-production はいくつかのよくある静的ファイルのデプロイ手 法に言及しています。

これらは 基本 です。設定オプションについてもっと深く知るには、さらに読むべ きものがあります。設定やコマンド、またフレームワークに含まれる他のちょっとした ことを知るために、 staticfiles リファレンス を参照してください。

Note

Django の以前のバージョンでは、ユーザがアップロードしたファイルを置くための MEDIA_ROOT に静的なファイルも一緒に置かれ、どちらも MEDIA_URL で公開されていました。 staticfiles アプリケーショ ンを使う目的の 1 つは、静的ファイルとユーザがアップロードしたファイルとを分 けて管理することを簡単にするためです。

この理由から、 MEDIA_ROOT および MEDIA_URLSTATIC_ROOT および STATIC_URL とは別の値にしなければ なりません。 MEDIA_ROOT に含まれるファイルを公開するには、自分で 整理する必要があります。 staticfiles はユーザがアップロードしたファイル を全く扱わないのです。ただし、 MEDIA_ROOT のファイルを公開するた めに django.views.static.serve() ビューを使うことはできます。 staticfiles-other-directories を参照してください。

テンプレートから静的なファイルを参照する

テンプレートではいくつかの箇所で静的なファイルをリンクする必要があるでしょう。 もちろん、テンプレートで静的ファイルを単にハードコードすることは可能です:

<img src="http://static.example.com/static/myimage.jpg" />

当然ながら、これでは深刻な問題がいくつかあります。開発環境ではうごきませんし、 静的ファイルを公開する場所を変更するのが 非常に 困難です。例えばもし、 コン テンツデリバリーネットワーク (CDN) を使うように切り替えたい場合、テンプレート 全てを一つ一つ変更することになってしまいます。

もっと良い方法は STATIC_URL の値を直接テンプレートで使うことです。 こうすると、一つの値を変更するだけで静的ファイルのサーバを切り替えることができ ます。ずっと良いですね!

Django にはこの設定値をテンプレートで使うための複数の方法があります。コンテキ ストプロセッサとテンプレートタグです。

コンテキストプロセッサを使う

組み込みのコンテキストプロセッサは簡単に使えます。 TEMPLATE_CONTEXT_PROCESSORS 設定に 'django.core.context_processors.static' が含まれていれば良いだけです。そし てデフォルトではそのようになっています。自ら設定を編集する場合は、こんな風にな るでしょう:

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'django.core.context_processors.static',
    'django.contrib.auth.context_processors.auth',
    'django.contrib.messages.context_processors.messages',
)

これができれば STATIC_URL をテンプレートで参照できます:

<img src="{{ STATIC_URL }}images/hi.jpg" />

{{ STATIC_URL }} がテンプレートが使えなければ、おそらくテンプレートのレン ダリングに RequestContext を使っていないためです。

手短に復習すると、コンテキストプロセッサは全てのテンプレートのコンテキストに変 数を追加します。しかし、コンテキストプロセッサはテンプレートのレンダリングに RequestContext を使うことを要求します。 generic view を使えば自動的にそうなりますが、 自作のビューでは明示的に RequestContext を使わなければなりません。 これがどのように動くか知りたければ、 コンテキストのサブクラス: RequestContext をチェックしてください。

別の方法は Django 本体に含まれる get_static_prefix テンプレートタグを 使うことです。

テンプレートタグを使う

よりパワフルなツールが static テンプレートタグで す。このタグは与えられた相対パスに対して、 STATICFILES_STORAGE スト レージの設定を使って URL を組み立てます。

{% load staticfiles %}
<img src="{% static "images/hi.jpg" %}" />

通常のコンテキスト変数を受け取ることもできます。例えば user_stylesheet 変 数がテンプレートに渡されたとすると:

{% load staticfiles %}
<link rel="stylesheet" href="{% static user_stylesheet %}" type="text/css" media="screen" />

Note

Django コアセットの ビルトインテンプレートタグ に含まれる static テンプレートタグもあります。これは同じ引数を持ちますが、 STATIC_URL 設定と与えられたパスを単に urlparse.urljoin() に 渡します。これはテンプレートを変更することなく簡単にストレージバックエンド を切り替えることができないという不利な点があります。ですので注意して staticfilesstatic テンプレートタグを使 いましょう。

開発中の静的ファイルの扱い方

このツールは基本的に、運用環境にうまく静的ファイルをデプロイするのを補助するた めに設計されています。これは普通、別途専用で用意された静的ファイルサーバのこと ですが、ローカルでの開発時に使うには大きなオーバーヘッドがかかります。そこで staticfiles アプリは 手軽でダーティなヘルパービュー を導入します。これ によって開発中にローカルのファイルを使えるようになります。

ヘルパービューは自動で有効になっています。 runserver コマンドを使った時に STATIC_URL で静的ファイルを公開できます。

ローカル開発で他のサーバを使っている場合、このビューを有効にするには URLconf に 2 行追加する必要があります。 1 つめの行はファイルの先頭に、 2 つめ の行は末尾に書きます:

from django.contrib.staticfiles.urls import staticfiles_urlpatterns

# ... URLconf の他の行がここに入ります

urlpatterns += staticfiles_urlpatterns()

この関数は STATIC_URL 設定を調べ、静的ファイルを適切に公開できるよ うにビューを設定します。アプリケーションディレクトリの中でどこを探せばいいかを django.contrib.staticfiles に教えるために、 STATICFILES_DIRS を 設定するのを忘れないでください。

Warning

ローカル環境でのファイル公開は DEBUGTrue の時にだけ動作 します。

それはこのビューが ひどく非効率 で、おそらく セキュアでない ためで す。このビューはローカル環境での開発だけを意図しており、 決して運用環境 で使うべきではありません

加えて、 staticfiles_urlpatterns を使うと、 STATIC_URL 設定は空であったり http://static.example.com/ 完 全な URL であったりできなくなります。

開発中の staticfiles の使い方についてもっと詳しく知るには staticfiles-development-view を参照してください。

他のディレクトリを公開する
serve(request, path, document_root, show_indexes=False)

プロジェクト内に含まれているものとは別のファイルもあるかもしれません。利便性の ため、ローカル環境での開発で Django に公開させたいのではないでしょうか。 serve() ビューは指定したどんなディレクトリも公開で きます。 (繰り返しますが、このビューは運用には耐えません。開発の補助としてだけ 使ってください。運用環境ではこれらのファイルは実際のフロントエンドサーバで公開 すべきです)

よくある例は MEDIA_ROOT にユーザがアップロードしたコンテンツです。 staticfiles は静的アセットを意図していて、ユーザがアップロードしたファイル のハンドリングは含まれていませんが、 URLconf に以下のような記述を追加すること で MEDIA_ROOT を Django に公開させることができます:

from django.conf import settings

# ... URLconf の他の部分がここに入ります ...

if settings.DEBUG:
    urlpatterns += patterns('',
        url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
            'document_root': settings.MEDIA_ROOT,
        }),
   )

このスニペットは MEDIA_URL'/media/' という値になっているこ とを仮定しています。 serve() を呼び出し、 URLconf と ( 必須の ) document_root パラメータをパスに渡します。

static(prefix, view='django.views.static.serve', **kwargs)

この URL パターンを定義するのはいささか大変になってくるので、 Django は小さな URL ヘルパー関数 static() を持っています。 これは MEDIA_URL のようなプレフィックスと、 'django.views.static.serve' のようなドット区切りのビューへのパスをパラメー タにとります。他の関数パラメータは透過的にビューに渡されます。

開発中に MEDIA_URL ('/media/') を公開する例です:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = patterns('',
    # ... the rest of your URLconf goes here ...
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Note

このヘルパー関数は、デバッグモードの中で、与えられたプレフィックスが ( 例 /static/) ローカルであって URL ( 例 http://static.example.com/) ではない時にだけ操作できます。

運用環境での静的ファイル公開

運用環境に静的ファイルを置くための基本原則はシンプルです。静的ファイルが変 更された時には collectstatic コマンドを実行し、集められた静的ファイ ルのディレクトリ (STATIC_ROOT) を静的ファイルサーバに移動し、公開す るために整理します。

もちろん、あらゆるデプロイタスクと同様、細部には悪魔がいます。運用環境ごとに セットアップには小さな違いがあり、基本原則を必要に合うように変えなければならな いでしょう。以下はその助けになるかもしれないいくつかの共通パターンです。

一つのサーバでアプリケーションと静的ファイルを扱う

既にサイトを公開しているのと同じサーバで静的ファイルを公開したい場合、基本原則 は以下のように変更されます:

  • デプロイサーバにコードを展開します。
  • そのサーバ上で collectstatic を実行し、全ての静的ファイルを STATIC_ROOT 内にコピーします。
  • Web サーバに STATIC_ROOT を教えます。例えば Apache と mod_wsgi での方法 があります。

このプロセスはきっと自動化したくなるでしょう。特に複数の Web サーバを管理して いる時はそうです。この自動化を行う方法には色々ありますが、 Django を使う開発者 には嬉しいであろう一つの方法が Fabric です。

以下とそれに続くセクションでは、いくつかの fabfiles (Fabric scripts のこと ) を示します。それらはファイルのデプロイ方法を自動化してくれます。 fabfile の文 法はかなり直感的ですが、ここで網羅することはできません。 Fabric ドキュメント を読めば、文法の完全な説明が得られます。

静的ファイルを 2 つの Web サーバにデプロイする fabfile はこのようになるでしょ う:

from fabric.api import *

# デプロイ先のホスト
env.hosts = ['www1.example.com', 'www2.example.com']

# プロジェクトコードが格納される場所
env.project_root = '/home/www/myproject'

def deploy_static():
    with cd(env.project_root):
        run('./manage.py collectstatic -v0 --noinput')
専用のサーバで静的ファイルを公開する

大きな Django アプリケーションはたいてい別の Web サーバを静的ファイルの公開に 使っているでしょう。そのサーバでは Django は動いていません。 このサーバは別の種類の Web サーバ、速いがフル機能ではないものを使っていること が多いです。いくつか良い選択肢を挙げると:

これらのサーバの設定方法はこのドキュメントの範囲を超えますので、説明はそれぞれ のサーバの相当するドキュメントを調べてください。

静的ファイルサーバでは Django を動かせないでしょうから、デプロイ戦略を次のよう に変更する必要があります:

  • 静的ファイルが変更された時、 collectstatic をローカルで実行しま す。
  • ローカルの STATIC_ROOT を静的ファイルサーバの公開ディレクトリに アップロードします。 rsync は変更されたファイルのビットだけを転送するだ けで済むので、この手順の良い選択肢です。

fabfile はこのようになるでしょう:

from fabric.api import *
from fabric.contrib import project

# 静的ファイルがローカル環境で集められる場所
env.local_static_root = '/tmp/static'

# 静的ファイルがリモートで置かれる場所
env.remote_static_root = '/home/www/static.example.com'

@roles('static')
def deploy_static():
    local('./manage.py collectstatic')
    project.rysnc_project(
        remote_dir = env.remote_static_root,
        local_dir = env.local_static_root,
        delete = True
    )
クラウドサービスや CDN での静的ファイル公開

もう一つの一般的な手法は、静的ファイルを Amazon S3 のようなクラウドストレー ジプロバイダや、 CDN (content delivery network) で公開することです。これにより 静的ファイル公開の問題を気にせずにすみ、またしばしば (CDN を使う場合は特に ) Web ページを高速にロードさせることができます。

これらのサービスを使う場合、基本的なワークフローは上の話と少し似ていますが、 rsync を使ってファイルをサーバに転送する代わりに、ストレージプロバイダや CDN に送らなければならないところが違います。

これを行う方法は様々ですが、プロバイダに API がある場合、 カスタムファイルストレージバックエンド を 使えば、手順が信じられないほどシンプルになります。 STATICFILES_STORAGE に、自分が書いた、あるいはサードパーティ製のカ スタムストレージバックエンドを設定することにより、 collectstatic に そのバックエンドを使うように教えることができます。

例えば、 S3 ストレージバックエンドを myproject.storage.S3Storage に書いた とすると、このように使うことができます:

STATICFILES_STORAGE = 'myproject.storage.S3Storage'

こうすれば、 collectstatic をするだけで、静的ファイルはあなたのスト レージパッケージを経て S3 にアップロードされます。もし後で別のストレージプロバ イダに変更しなければならなくなっても、単に STATICFILES_STORAGE 設定 を変更するだけで済みます。

カスタムファイルストレージバックエンドを書く方法の詳細は カスタムのストレージシステムを作成する にあります。

See also

django-storages はサードパーティーアプリケーションで、 S3 を含む多 くな一般的なストレージ API のために、数多くのストレージバックエンドを提供 しています。

django-staticfiles からアップグレードする

django.contrib.staticfiles は元々 django-staticfiles として生まれまし た。もし django-staticfiles 1.0 以前 (0.3.4 など) から django.contrib.staticfiles にアップグレードしようとすると、いくつかの変更 をしなければなりません:

  • アプリケーションの静的ファイルはそれぞれのアプリケーションの static ディ レクトリになければなりません。 (django-staticfilesmedia という 少々混乱させる名前を使っていました)
  • コマンド build_staticresolve_static は今では collectstaticfindstatic という名前になっています。
  • 設定 STATICFILES_PREPEND_LABEL_APPS, STATICFILES_MEDIA_DIRNAMES, STATICFILES_EXCLUDED_APPS は削除されまし た。
  • 設定 STATICFILES_RESOLVERS は削除され、新しい STATICFILES_FINDERS に置き換えられました。
  • STATICFILES_STORAGE のデフォルトは staticfiles.storage.StaticFileStorage から staticfiles.storage.StaticFilesStorage にリネームされました。
  • ローカル環境で runserver を使う時 (DEBUG 設定が True の時) 、開発中の静的ファイル公開のために URLconf に何も追加する必要がなくなりました。

さらに学ぶためには

このドキュメントでは基本といくつかのよくある使用パターンについて説明しました。 django.contrib.staticfiles に含まれる全ての設定、コマンド、テンプレートタ グ、その他について、完全な詳細を知るには staticfiles リファレンス を参照してください。

See also

Django のコミュニティアグリゲータ には、 世界中の Django コミュニティから寄せられたコンテンツが収集されています。 アグリゲータに登録されている著者の多くが、この手の HOWTO 文書を書いてい ます。

よくある質問

revision-up-to:17812 (1.4)

全般的な FAQ

revision-up-to:17812 (1.4)

なぜこんなプロジェクトがあるのですか?

Django は極めて実践的な要請のもとで成長してきました。 Web 新聞を発行している WorldOnline では、効果的な Web アプリケーションを、ジャーナリズムとして成立 する締め切りに間に合うように構築せねばなりません。刻一刻と状況が変化するニュー スルームにあって、WorldOnline には、複雑な Web アプリケーションをコンセプト から立ち上げ公開にもっていくまで数時間の猶予しかないのです。

同時に、 WorldOnline の Web 開発者たちは、こと Web 開発の王道に関しては一貫 して完璧主義者です。

こうした理由から Django は Web アプリケーションをただ素早く作れるだけではな く、Web 開発の 王道 に従って作成できるように設計されているのです。 2003 年、WorldOnline の開発者 (Adrian Holovaty と Simon Willison) は PHP に 見切りをつけ、 Python による Web 開発に取り組みはじめました。集約的で高い双 方向性を備えた Lawrence.com のようなサイト開発の中で、彼らは Web アプリケー ションをより迅速に開発できるように、サイトのコードから汎用の Web 開発フレー ムワークを切り出し、 2 年近くの間ずっと改良を加えながら使い込んできました。

2005 年の夏、 World Online はこれまでの開発の成果を Django としてオープンソー ス化する決定を下しました。 Django は Apache, Python, そして PostgreSQL をはじめとする様々なオープンソースプロジェクトなしでは実現し ませんでした。そして今、私達はオープンソースコミュニティに多少なりともお返 しできることにワクワクしているのです。

“Django” とはどういう意味で、どのように発音するのですか?

Django は 1930 年代から 1950 年代初期にかけて活躍したジプシージャズのギタリ スト、 ジャンゴ・ラインハルト (Django Reinhardt) にちなんで名付けられ ました。今日では、ジャンゴは歴史上最も優れたギタリストの一人に数えられてい ます。

彼の曲を聞いてみてください。きっと気に入ることでしょう。

Django は JANG-oh (‘a’ は伸ばす) と発音します。韻は FANG-oh と 同じです。 “D” は発音しません。

正しい発音の音声ファイル を作成してあるので参考にしてください。

Django は安定していますか?

はい。 World Online は 3 年以上にわたって Django を使ってきました。 Django で構築したサイトは、これまでに 100 万ヒット/時を超えるトラフィック スパイクに見舞われたことがあり、何度もスラッシュドット効果を喰らっています。 そうですね。きわめて安定です。

Django はスケールしますか?

はい。ハードウェアというものは、開発時間に比べて安いものですし、それゆえ Django はユーザが投入可能なハードウェアをできるだけ活用するべく設計されてい ます。

Django は「レイヤ間で何も共有しない (shared-nothing)」アーキテクチャなので、 データベースサーバ、キャッシュサーバ、 Web/アプリケーションサーバのどのレベ ルにハードウェアを追加してもかまいません。

Django はアプリケーションレイヤからのデータベースレイヤを分離し、シンプルな がら強力な キャッシュフレームワーク を備えています。

Django の舞台裏には誰がいるのですか?

Django はもともと、World Online という、米国カンザス州ローレンス (Lawrence, Kansas, USA) のとある新聞の Web 部門で開発されました。今では、 Django は国 際的なボランティアのチームによって開発されています。 開発者たちの人となりは コミッタ一覧 で読めます。

どんなサイトが Django を使っているのですか?

DjangoSites.org には Django で作られたサイト一覧という特集ページがあり、 日々内容が増えています。

Django は MVC フレームワークのようですが、コントローラ (Controller) を「ビュー (view)」と呼び、ビュー (View) を「テンプレート (template)」と呼んでいます。どうして標準的な呼び方をしないのですか?

そうですね、呼び名には議論の余地があるでしょう。

我々の MVC の解釈では、「ビュー」とはユーザに提示されるデータのことをいいま す。つまり、データが どのように見えるか ということではなく、むしろ どの データを提示するか です。ビューには データがどのように見えるか ではなく どのデータが表示されるか が定義されています。この二つは明らかに違います。

というわけで、我々のケースでは、「ビュー」は特定の URL に対する Python コー ルバック関数になります。なぜなら、コールバック関数はどのデータを提示するか を決めているからです。

さらに、テンプレートによってコンテンツとプレゼンテーションの分離がはっきり しています。Django では、ビューはどのデータを提示するかを決めていますが、 ビューは通常、 どのように データを提示するかをテンプレートに委ねます。

では、「コントローラ」はどこに入るのでしょうか。 Django の場合、おそらくフ レームワーク、すなわち URL 設定にしたがってリクエストを適切なビューに送信す る機構自体がコントローラにあたるといえるでしょう。

略語がお好みなら、 Django を “MTV” フレームワークと呼んでもよいでしょう。つ まり、モデル (Model)、テンプレート (Template)、そしてビュー (View) です。 こっちの方がよりしっくりきます。

最後に、結局重要なのは問題を解決することです。そして、呼び方は何であれ、 Django はわれわれにとって最も理にかなった方法で問題を解決しているのです。

<フレームワーク X> には <機能 Y> がありますが、なぜ Django にはないのですか?

世の中には他にも素晴らしい Web フレームワークがあるのは良く知っていますし、 必要であればそこからアイデアを借りるのにやぶさかではありません。とはいえ、 私たちが Django を開発した動機は、旧態然たる Web フレームワークに不満だった からこそなので、「<Framework X> でできるから」といって、同じ機能を Django に機能を追加する理由にはならないのです。

なぜ既存の Python ライブラリを使わずスクラッチで Django を作ったのですか?

Django を書き始めた数年前、 Adrian と Simon は少し時間を取って、当時利用 できた様々な Python ウェブフレームワークを試してみました。

その結果、十分な出来具合のものは一つもないという結論に達したのです。

私達は好みにうるさいのです。(締め切りに追われる) 完璧主義者と呼んでもいいで しょう。

これまでずっと、私達は自分たちがすでに実装済みの機能を実現するオープンソー スライブラリに出会ってきました。そうしたライブラリに、他の人達が同じ問題を 同じ方法で解決しようとしているのを見ては元気づけられる思いでしたが、自分た ちのコードの外側に組み込むにはもう遅すぎました。私達はすでにいくつもの運用 環境で独自のフレームワークを書き上げ、テストし、実装してきており、できたコー ドは快適なまでに要求を満たしていたのです。

一方、ほとんどの場合、既存のフレームワークやツールは明らかにある主の根本的、 致命的な欠陥があり、私達を神経質にさせました。結局、私達の哲学に 100% 合う ものはなかったのです。

繰り返していいますが、私達は好みにうるさいのです。

私達の設計哲学は 設計哲学のページ に詳し く書いてあります。

Django はコンテンツ管理システム (CMS) なのでしょうか?

いいえ。 Django は CMS ではありませんし、いわゆる「ターンキーシステム」のよ うなものでもありません。 Django は Web フレームワークであり、 Web サイトを 構築する際に使えるプログラミングツールにすぎません。

例えば、 Django を Drupal のようなシステムと比較するのは無意味です。という のも、 Django はまさに Drupal のようなシステムを 作る ためのものだからで す。

もちろん、 Django の自動 admin サイトはすばらしく、開発時間の節約になります。 しかし、 admin サイトは Django というフレームワークのいちモジュールに過ぎま せん。もっと言うなら、 Django が「 CMS 的な」アプリケーションを作成する上で とりわけ便利な点を持ってはいますが、そのことが「 CMS 的でない」アプリケーショ ンの開発に向いていない、なんてことにつながったりはしないのです。

どうやれば Django のドキュメントをダウンロードしてオフラインで読めますか?

Django のドキュメントは Django tarball リリースの docs ディレクトリに あります。これらのドキュメントは reST (reStructuredText) 形式で書かれており、 各テキストファイルが Django 公式サイトのページに対応しています。

ドキュメントは バージョン管理システム下にある ので、コードの変更状況を閲 覧するのと同じようにしてドキュメントの変更状況を閲覧できます。

技術的には、 Django サイトのドキュメントは最新の開発版の reST ドキュメント から生成されます、従って、 Django サイトにあるドキュメントの方が、最新の Django リリースのドキュメントよりも多くの情報を提供していることがあります。

Django 開発者はどこで雇えますか?

求職中の開発者リスト には、喜んであなたの力になってくれる Django 開発者 のリストがあります。

また、求人を http://djangogigs.com/ に出してみるのもよいでしょう。 地元で Django を扱える人を探しているなら、 http://djangopeople.net/ を調べ てみてください。

インストールに関する FAQ

revision-up-to:17812 (1.4)

まずは何をすればよいですか?

  1. コードをダウンロード してください。
  2. Django をインストールしてください ( インストールガイド を読みましょう)。
  3. チュートリアル を一通りやってみてください。
  4. 他の ドキュメント にも目を通して下さい。何か問題が起きたら、 質問 してみましょう。

Django を動かすには何が必要ですか?

Django を動かすには、バージョン 2.5 以上 2.7 以下の Python が必要です。 Django の基本的な機能を使う限り、他の Python ライブラリは不要です。

開発環境を使う場合、つまり Django を試したいだけの場合は、 Web サーバを別に インストールしておく必要はありません。 Django には簡単な開発用サーバが付属 しています。 Django は WSGI 仕様 (PEP 3333) に準拠しています。 従って、様々なサーバプラットフォームで運用環境を構築できます。 いくつか選択肢を紹介しているので、 Django のデプロイ方法 を参照してください。 また、 サーバの構成方法をまとめた wiki ページ には、詳しい運用戦略が書か れています。

Django をデータベースと合わせて使うならデータベースエンジンも必要です。 我々は PostgreSQL ファンなので PostgreSQL をお勧めしますが、 MySQLSQLite 3, Oracle もサポートしています。

Python 2.5 を使うのは、 2.6 や 2.7 のような新しいバージョンを使うよりも不利ですか?

フレームワークのコアの機能を使う限りは、特に不利はありません。 Django 自体 は、2.5 から 2.7 まで間の全てのバージョンの Python をサポートしています。 ただし、新しいバージョンの Python の方が早いですし、より多くの機能があり、 またよりよいサポートがなされています。もし新しいバージョンの Python を使っ ていれば、古いバージョンでは使用できないような API も使用できるでしょう。 例えば、 Python 2.6 からは、 PEP 3101 で定義されている進化した文字列 フォーマットが使用できます。

Django を使っているサードパーティ製のアプリケーションには、もちろん、 各自で必要な Django のバージョンを設定してもらって構いません。

ここ数年の間に、 Django は Python 3.0 で動作するよう移行を勧め、その過程 で古いバージョンの Python での動作をサポートしなくなる予定です (詳しくは この下の質問を読んでください)。

これらをふまえ、最新の 2.x リリース (今なら 2.7) を使うことを勧めます。 最新版を使えば、バージョン 2.5 以降に登場した様々な改良や最適化の恩恵を 受けられますし、 3.0 への移行に伴って撤廃される機能の影響も受けにくいか らです。

どのバージョンの Python でどのバージョンの Django が使えますか?

Django バージョン Python バージョン
1.0 2.3, 2.4, 2.5, 2.6
1.1 2.3, 2.4, 2.5, 2.6
1.2 2.4, 2.5, 2.6, 2.7
1.3 2.4, 2.5, 2.6, 2.7
1.4 2.5, 2.6, 2.7
1.5 (予定) 2.6, 2.7, 3.x (試験的)

Django を Python 3 で使えますか?

今のところ、使えません。 Python 3.0 では、過去のバージョンと互換性のない 変更がたくさん行われました。この変更は総じて Python の未来のために必要なよ い変更なのですが、Python を使ったほとんどのソフトウェアが変更に追従し、 3.0 でも問題なく動作するには、しばし時間が必要なのです。 Django のような大規模 な Python ベースのソフトウェアの場合、移行は 1, 2 年はかかるでしょう (古い バージョンの Python のサポートもやめなければならないので、段階的に進める必 要があるのです)。

Python の開発チームは 2.x のリリースを当面継続して、バグフィクスやセキュリ ティアップデートを行うので、 Python 2.x を使い続けるリスクは全くないはずで す。

Django は共有ホスティングサービス (TextDrive や Dreamhost) で動きますか?

Django を使える Web ホスト のページをごらん下さい。

安定版と開発版のどちらを使うべきなのでしょうか?

一般的に、もしあなたがコードを製品で使っているのなら、安定版を使うべきで しょう。 Django はおよそ 9 ヶ月ごとに、バグフィックスを含めた安定版をリ リースしています。これらの安定版は後方互換を保証した API も提供しています ので、もし次の新しい安定版では使用できないコードを書いていても、アップ グレードにおいて問題は無いはずです。

FAQ: Django を使う

revision-up-to:17812 (1.4)

DJANGO_SETTINGS_MODULE の import にまつわるエラーが出るのですが、なぜですか?

以下の点を確認してください:

  • 環境変数 DJANGO_SETTINGS_MODULE が完全指定の Python モジュール名になっ ていますか (たとえば “mysite.settings”)。
  • 設定モジュールは sys.path の上にありますか (import mysite.settings はうまくいきますか)。
  • (言うまでもなく) モジュールに構文エラーはありませんか。
  • mod_python を使っていて、Django リクエストハンドラは 使っていない のなら、 SetEnv に関わる mod_python のバグを回避する必要がありま す。 Django から何らかのモジュールを import する前に、以下のコードを 実行してください:

    os.environ.update(req.subprocess_env)
    

    (req は mod_python のリクエストオブジェクトです)。

テンプレート言語を好きになれません。どうしても使わないとだめですか?

私達はこのテンプレートエンジンをchunky bacon 以来の傑作だと思っているんで すが、テンプレート言語の選択というものは宗教に近いものがあるということは認 識しています。 Django では、テンプレート言語に対する制限はなんらありません。 ですから、 ZPT や Cheetah などを使いたいのなら、それは自由です。

付属のモデル/データベースレイヤを使わねばならないのですか?

いいえ、テンプレートシステムと同様、モデル/データベースレイヤはフレームワー クの他の部分と脱カップリングしています。

唯一の例外: 別のデータベースライブラリを使った場合には、 Django の自動生成 admin サイトを利用できなくなります。 admin だけは Django のデータベースレイ ヤとカップリングしています。

画像やファイルのフィールドはどう使うのですか?

モデルで FileFieldImageField を使うには、いくつかのステップを踏む 必要があります:

  1. 設定ファイル内で MEDIA_ROOT を指定します。この値は、 Django がアップロードされたファイルを置く場所にします (パフォーマン ス上の理由から、ファイルをデータベースに置くことはありません)。 MEDIA_URL をそのディレクトリの公開 URL にします。ディレク トリは Web サーバのユーザアカウントに対して書き込み可能にしておかね ばなりません。
  1. モデルに FileFieldImageField を追加し、 upload_to オプションを定義して、 MEDIA_ROOT のどのサブディレクトリにファイルをアップロード させるのかを Django に教えます。
  1. データベースに保存されるのは、ファイルの (MEDIA_ROOT か らの相対で表した) パスだけです。 URL を調べるには、 Django の提供し ている属性 url を使うことになるでしょ う。例えば、 mug_shot という名前の ImageField を作ったなら、テンプレートで画 像の URL を指定するには {{ object.mug_shot.url }} と書きます。

どうやったら、全てのテンプレートで使えるような変数を定義できますか?

どのテンプレートでも同じデータを扱うことがたまにあります。よくあるのは、メ ニューを動的に生成して出す場合です。この手の例では、どのテンプレートでも使 データの入った辞書をテンプレートコンテキストに入れておくのが合理的ですね。

RequestContext を使うのが正解です。詳しくは コンテキストのサブクラス: RequestContext を参照してください。

FAQ: 助けを求める

revision-up-to:17812 (1.4)

何かをしたいとき、うまくいかないときは、どこで助けを求めればよいですか?

疑問の答えが FAQ に書かれていないのなら、 django-users メーリングリスト で質問するとよいでしょう。インストール方法、使い方、デバッグ方法に関する質 問は遠慮なくどうぞ。

IRC の方がよいなら、 freenode IRC ネットワークの #django IRC チャネル をお勧めします。便りになるメンバのいる活発なコミュニティで、あなたの問題を 解決してくれるでしょう。

メッセージを django-users に送ったのに表示されないのはなぜですか?

django-users にはたくさんの読者がいます。質問に答えてくれる人が沢山いると いう点ではいいことですが、残念ながら、それは同時に django-users がスパム屋 の格好の標的たりえることも意味しています。

スパムに対抗するため、私たちは新たに参加したメンバの送信した最初のメッセー ジを手動で検査しています。これにより、スパム屋は排除できますが、同時にあな たの最初の質問に回答するには少し時間がかかるのです。このポリシによって不便 な思いをさせてごめんなさい。

django-users で質問したのに誰も答えてくれません。どうすればよいですか?

質問をもっと具体的に説明するか、もっと分かりやすい例を示しましょう。

たいていのオープンソースプロジェクトのメーリングリストと同様、 django-users の中の人はボランティアです。誰も質問に答えないときは、だれも 答えを知らないか、質問の意図を理解できないか、答えを知っている人が忙しくて 答えられないのでしょう。そんなときは、 IRC で質問してみてもよいでしょう。 freenode IRC ネットワークの #django IRC チャネル に行ってみてください。

参考までに、 django-developers というメーリングリストもあります。ただ、こ のメーリングリストにはサポート質問のメールを送信しないでください。 django-developers は Django 自体の開発に関する議論のためのメーリングリスト で、ここで技術的なサポートの質問をすると、とても不躾な発言とみなされてしま うからです。

バグを見つけたように思います。どうすればよいですか?

明らかなバグを発見したときの手順は、 Django プロジェクトに貢献するためのガイドライン で詳しく解説しています。

セキュリティホールを見つけたように思います。どうすればよいですか?

Django のセキュリティ上の問題を発見したと思ったら、 security@djangoproject.com にメッセージを送信してください。このアドレスは、 長い間 Django に関わっている信頼の篤い開発者だけに公開されているメーリング リストで、アーカイブも一般の人には読めません。

セキュリティ問題は極めてデリケートなので、セキュリティ上の問題を発見したと きは 決して 公開のメーリングリストにメッセージを送信しないでください。 Django プロジェクトでは セキュリティ上の問題に関するポリシ を定 め、欠陥が解決されないうちは、その欠陥が公知になることを防ぐことでダメージ を最小限にとどめたいと考えています。

FAQ: データベースとモデル

revision-up-to:17812 (1.4)

Django が実行している生の SQL クエリを見られますか?

まず、 DEBUG 設定を True にして Django を動かしているか確認してく ださい。次に、以下のコードを実行します:

>>> from django.db import connection
>>> connection.queries
[{'sql': 'SELECT polls_polls.id,polls_polls.question,polls_polls.pub_date FROM polls_polls',
'time': '0.002'}]

connection.queries を使えるのは DEBUGTrue の時だけです。 この値は、クエリの実行順に辞書を並べたものです。各辞書には以下の値が入ってい ます:

.. ``sql`` -- The raw SQL statement
   ``time`` -- How long the statement took to execute, in seconds.

``sql`` -- 生の SQL 文
``time`` -- SQL 文の実行にかかった時間を秒で表したもの

connection.queries には、 INSERT, UPDATE, SELECT といった全ての SQL 文 が記録されています。アプリケーションがデータベースを操作する度に、クエリが 記録されてゆきます。ここで記録されている SQL は SQLite 上では正しく ないクオート処理 がされているかもしれないことに 注意してください。

リリースノートを参照してください

もし 複数のデータベース を使用している場合は、 connections 辞書内の各エイリアスに対し、同じコードを実行できます:

>>> from django.db import connections
>>> connections['my_db_alias'].queries

既存のデータベースで Django を使えますか?

使えます。 古いデータベースの組み込み方 を 参照してください。

モデルを変更したとき、どうやってデータベースを更新すればよいですか?

データが消えてもかまわないのなら、 manage.py ユーティリティを使って、特 定のアプリケーションをリセットする SQL を発行してください:

manage.py reset appname

この操作で、 appname に関係したテーブルが削除され、再度作成されます。

もしデータを削除したくないのなら、手作業で ALTER TABLE 文を実行せねば なりません。

スキーマのアップデートを扱う外部プロジェクト のデファクトスタンダードは south です。

Django のモデルは複数カラムにわたる主キーをサポートしていますか?

いいえ。サポートしているのは単カラムの主キーだけです。

しかし、実際には問題はありません。というのも、(unique_together モデルオ プションを指定したり、直接データベースに制約をかけたりして) 複数カラムにわ たる一意性が保たれるようモデルレベルで制約をかけられるからです。単カラムの 主キーは admin インタフェースをうまく稼働させるため、例えば編集や削除対象の オブジェクトを指定する簡潔な手段として必要であるにすぎません。

テーブル形式を MyISAM に指定するなど、データベース固有のオプションを CREATE TABLE 文に追加したいのですが、どうすればよいですか?

私達は、テーブルの形式のようなデータベース固有のオプションに対応するために Django のコードに特殊なケースを追加しないよう心がけています。データベース固 有のオプションを使いたければ、 SQL の初期データファイル を作成して、その中で ALTER TABLE 文を使うなどして自分の目的を実現してください。初期データ ファイルはデータベースの中で CREATE TABLE 文の後に実行されます。

例えば、 MySQL を使っていて、 MyISAM テーブルタイプを使いたい場合には、初期 データファイルを作成して、以下のような行を挿入します:

ALTER TABLE myapp_mytable ENGINE=MyISAM;

SQL の初期データファイル <initial-sql> でも説明していますが、 SQL ファイ ルには任意の SQL コードを入れられるので、SQL で行なえる変更なら何でも実現で きます。

Django がメモリリークを起こしているのですが、なぜですか?

Django に既知のメモリリークはありません。 Django プロセスがメモリをどんどん 消費して、一向に開放する気配がない場合、 DEBUGTrue にな っていないか調べてみてください。 DEBUGTrue にすると、 Django は実行した SQL 文の全てのコピーを保存するからです。

(クエリは django.db.connection.queries で保存されます。 Django が実行している生の SQL クエリを見られますか? を参照してください。)

問題を解決するには、 DEBUGFalse にしてください。

クエリリストを手動で消去するには、以下のように reset_queries() を呼び出 してください:

from django import db
db.reset_queries()

管理サイトの FAQ

revision-up-to:17812 (1.4)

ログインできません。正しいユーザ名とパスワードを入力したのに、再度ログインページが表示されます。エラーメッセージも出ません。

Django の発行するクッキーのドメインと、ブラウザに格納されたドメインが一致し ていないために、ログインクッキーが正しく設定されていない場合に起きる症状で す。以下の二つの対策を試してみて下さい:

  • 設定ファイルの SESSION_COOKIE_DOMAIN に正しいドメインを設定してく ださい。例えば、Django のサイトにアクセスするときに、ブラウザで “http://www.example.com/admin/” と入力しているのなら、 “myproject.settings” には SESSION_COOKIE_DOMAIN = 'www.example.com' と設定せねばなりません。
  • ブラウザの中には (Firefox かな?) ドットの入っていないドメインからのクッ キーを受け取りたがらないものがあります。管理サイトを “localhost” など のようなドットを含まないドメインで立てているのなら、 “localhost.localdomain” や “127.0.0.1” を試してください。また、 SESSION_COOKIE_DOMAIN もドメイン名に合わせて変更してください。

ログインできません。正しいユーザ名とパスワードを入力したところ、「正しいユーザ名とパスワードを入力してください」というエラーメッセージつきでログインページを表示します。

ユーザネームとパスワードが本当に正しいのなら、ユーザアカウントが is_active で、かつ is_staffTrue であるか確かめて下さい。 管理サイトにアクセスできるのは、 is_activeis_staff が共に True のユーザだけです。

キャッシュミドルウェアに管理サイトをキャッシュさせたくないのですが?

CACHE_MIDDLEWARE_ANONYMOUS_ONLY 設定を True にしてください。 詳しくは キャッシュのドキュメント を参照してください。

管理サイト上でオブジェクトを編集するときに、あるフィールドに、そのオブジェクトを最後に編集したユーザの情報を自動的に入れる方法はないですか?

ModelAdmin クラスの用意しているカスタマイズ用 のフックを使えば、オブジェクトを保存するときに、リクエストから取り出した情報 に基づいてフィールドの値を変更できます。具体的には、 save_model() フックをカスタマイズして、 オブジェクトのフィールド値にリクエストから取り出した現在のユーザを反映させま す。 ModelAdmin メソッドのドキュメント にサン プルがあります。

管理サイト上でオブジェクトを編集するときに、オブジェクトを最初に作成したユーザだけが編集できるよう制限するにはどうすればよいですか?

ModelAdmin の用意しているフックには、オブ ジェクトを管理サイト上に表示するかどうかと編集可能かどうかを制御できるもの があります。 queryset() および has_change_permission() フックをカスタマイズすれば、上の質問の答えと同様、リクエストから取り出した 現在のユーザの情報に基づいて、オブジェクトの表示や編集を制御できます。

開発サーバでは管理サイトの CSS や画像がうまく表示されるのに、 mod_wsgi を使うと表示されません。

「mod_wsgi で Django を使う」というドキュメントの 管理サイト用のファイルを公開する方法 を参照してください。

“list_filter” に ManyToManyField を入れたのに、管理サイトがフィルタを表示しません。

Django が ManyToManyField に対してフィルタを表示するのは、リレーション 先のオブジェクトが複数のときだけです。

例えば、 list_filtersites が入っており、データベースにたった一 つしかサイトが登録されていなければ、 “Site” フィルタは表示されません。この 状況では、サイトによるフィルタは無意味だからです。

管理サイトの機能をカスタマイズするにはどうすればよいですか?

方法はいくつかあります。Django が自動生成する add/change フォームを利用して 楽をしたければ、モデルの class Adminjs パラメタを使ってページに 任意の JavaScript モジュールを貼り付けてください。パラメタには、 JavaScript モジュールの URL をリストにして指定します。管理画面は、指定した JavaScript を <script> タグでフォームと一緒に出力します。

単に自動生成されるフォームをいじる以上の柔軟さが必要な場合には、管理サイト 用のカスタムビューを書いて下さい。管理サイトはそれ自体 Django で作られてい るので、認証システムやパーミッションのチェックなどを行うビューを自作できま す。

管理サイトのルック & フィールをカスタマイズしたいのなら、次の項目を読んで下 さい。

管理サイトのデザインが気に入りません!どうすれば変更できますか?

私達は好きなんですが、そうは思わないのなら、 CSS スタイルシートや画像ファイ ルを編集して、管理サイトのプレゼンテーションを変更できます。サイトはセマ ンティックな HTML を使って書かれているので、やりたい変更は全て CSS スタイル シートの編集で実現できます。てほどきに 管理サイトの CSS ガイド を用意してあります。

管理サイトはどのブラウザでサポートされていますか?

管理サイトは IE6 以外 (サポート対象外) のすべての YUI’s A-grade ブラウザで、 完全な機能を提供しており、問題なく表示されます。

角丸表示をサポートしていないなど、各々のブラウザで多少の違いはあるかもし れません。これらは、許容範囲であると考えられています。

コードの寄贈に関する FAQ

revision-up-to:17812 (1.4)

Django プロジェクトにコードを寄贈したいんですが、どうすればよいですか?

よくぞ聞いてくれました!まさにこの質問に答えるためのドキュメントを用意して あります。 Django プロジェクトへの貢献 という文書です。

何週間も前にチケットシステムにバグフィクスを提出したんですが。何で私のパッチを無視するんですか?

心配しないでください。無視しているわけではないんですよ!

まずは「チケットを無視する」ことと「まだチケットを検討していない」ことの違 いを理解してください。 Django のチケットシステムにはオープン状態のチケット が何百もあり、個々のチケットがエンドユーザの使い勝手に与えるインパクトも様々 です。そのため、Django の開発者達はチケットをレビューして、優先順位を決めね ばならないのです。

なにより、 Django プロジェクトに関わっている人たちは全てボランティアです。 ですから、彼らがプロジェクトにかけられる労力には限界があるし、彼らがプロジェ クトに割ける時間もその時々で変化します。忙しいときには、十分な時間をかけら れず、なかなか要望に応えられない場合もあるのです。

チケットを速やかにチェックインさせたいなら、チケットの内容をできるだけ簡単 にして、分野の違う人であっても問題を理解でき、修正内容を検証できるようにし ましょう。そのために、以下のことをチェックしてください:

  • バグを再現するための明快な手順が書かれていますか? (PIL のような) 外 部ライブラリや contrib のモジュール、特定のデータベースに依存する問題 の場合、そうした依存物に関する説明が、詳しくない人にとってもわかりや すいでしょうか?
  • パッチを複数チケットに添付している場合、どのチケットが何で、本当に大 事なパッチとそうでないものが区別されていますか?
  • パッチにはユニットテストが入っていますか?そうでないなら、ユニットテ ストを含めない明確な理由の説明がありますか?テストがあれば、何が問題 なのか、そしてパッチが実際にその問題を解決することを効果的に説明でき ます。

また、あなたのリクエストを Django に取り込まないとはっきりした場合でも、チ ケットを無視せず、必ずクローズします。従って、チケットがまだオープンの状態 なら、リクエストは無視されているのではなく、いま一時的にリクエストに目を通 す時間を取れないという状態なのです。

私の大事なパッチのことを、いつ、どのようにコアチームに促せばよいですか?

丁寧に書かれたメッセージを、メーリングリストにタイミングよくポストするのが コツです。タイミングをはかるには、開発のスケジュールを追いかける必要がある でしょう。コアチームの開発者が開発スケジュールの締め切りを目指しているとき やプランニングを行っているときには、思ったように注意を引けないでしょう。 逆に、コアチームの開発者がバグフィクスに注意を払っているとき、たとえばバグ フィクスのためのスプリントを控えているときや、ベータリリースの最中には、建 設的なレスポンスをもらえることでしょう。

IRC で適度にリマインダを送るのもそこそこ効果があるでしょう。もちろん、可能 なら戦略的にやりましょう。たとえば、バグフィクススプリントの最中などは、と てもよいタイミングのはずです。

注意を引くもう一つの方法は、関連のある複数のチケットを一つにまとめるという ものです。コアの開発者がしばらくいじっていない分野のコードのバグフィクスに 取りかかるときには、コードがどのように動くかを細かく思い出すまで時間がかか るものです。同じ分野の小さなバグフィクスを複数まとめて、共通のテーマをもっ た一つのグループとして提示すれば、特定の分野のコードに慣れるまでのコストを 複数のチケットに分散させられるので、開発者にとっては魅力的なターゲットにな り得ます。

コアチームの開発者に直接メールを送るのは避けてください。また、同じ問題を何 度も何度も繰り返すのもよくありません。その手の行動は、あなたの大切なバグの 解決につながるような注意を全く引きません。

でも、何度も催促しているのに、私のパッチは無視されたままなんですが!

本当に、本当に無視はしていません。トラッカにあるパッチを Django に組み込ま ないと決めたなら、チケットは閉じられます。それ以外のチケットに対しては、優 順位付けをして取り組んでいます。従って、チケットによっては先にポストされた 他のチケットよりも前に解決されることがあります。

バグフィクスの優先順位を決める基準の一つは、そのバグによって影響を受けると 考えられるユーザの規模です。多くのユーザに重大な影響を与えるようなバグは、 極端なケースでのみ発生するバグよりも優先されます。

もう一つ、バグが無視されたかのように扱われる状況があります。それは、バグが より大きな問題の一症状である場合です。時として、たくさんの小さなパッチを書 いてテストし、適用していけば解決できる問題の中に、いっそ再構築してしまうの が正しいようなケースがあります。あるコンポーネントの再構築やリファクタが提 案されていたり、作業中だったりする場合には、そのコンポーネントに関するバグ には注意が払われないことがあるのです。再構築に集中すれば、小さなバグをまと めて一気に閉じられるし、将来にわたって似たような小さなバグが現れるのを防げ ます。

理由はどうあれ、あなたの環境では常に問題化するバグが、他のすべての Django ユーザの環境で問題化するとは限らない、ということを覚えておいてください。 Django のユーザはそれぞれに違う方法で Django を使っていて、コードに負荷をか ける場所も違えば条件も違います。全般的に、バグフィクスの優先順位を相対的に 決めるときには、私たちは特定のユーザにとっての深刻さより、コミュニティ全体 にとっての必要性を考慮します。だからといって、あなたの環境で起きている問題 が重要でないと考えているわけではありません – 限られた時間を使うときには、 1 人のユーザを救うことより、10 人のユーザを救う側に立たざるを得ないのです。

API リファレンス

revision-up-to:11321 (1.1)

Built-in authentication backends reference

revision-up-to:11321 (1.1) unfinished

This document details the authentication backends that come with Django. For information on how how to use them and how to write your own authentication backends, see the Other authentication sources section of the User authentication guide.

Available authentication backends

The following backends are available in django.contrib.auth.backends:

class ModelBackend

This is the default authentication backend used by Django. It authenticates using usernames and passwords stored in the User model.

class RemoteUserBackend

Use this backend to take advantage of external-to-Django-handled authentication. It authenticates using usernames passed in request.META['REMOTE_USER']. See the Authenticating against REMOTE_USER documentation.

“contrib” パッケージ

revision-up-to:17812 (1.4)

Django は Python の “batteries included” 哲学 を目指しています。 Django には Web 開発における課題を解くための様々な外部オプションツールがついてきま す。

これらのコードは Django 配布物中の django/contrib にあります。このドキュ メントでは、 contrib 下のパッケージをざっと解説し、パッケージを利用する ときに必要な依存関係について説明します。

Note

これらのアドオンの大半、特にモデルやテンプレートタグの定義が入っている アドオンを使うには、パッケージ名 (例えば 'django.contrib.admin') を INSTALLED_APPS 設定に追加して、 manage.py syncdb を 再度実行する必要があります。

Django admin サイト

revision-up-to:11321 (1.1) unfinished

Django の最も強力な機能の一つに、自動生成される admin インタフェースがあり ます。 admin はモデルのメタデータを読み込んで、強力で実運用に耐えるインタ フェースを生成し、コンテンツの製作者がすぐにサイトにコンテンツを投入できる ようにします。このドキュメントでは、 Django の admin インタフェースを有効に したり、カスタマイズしたりする方法を解説します。

注意

admin サイトは Django 0.96 から大幅にリファクタされました。このドキュメ ントでは、よりカスタマイズ機能の充実した新しい admin サイトについて解説 しています。この admin サイトの仕様は、 Django の開発をよく追いかけてい る人なら、一度は “newforms-admin” という名前で耳にしたことがあるはずで す。

概要

Django admin サイトは、以下の 5 つのステップを通して有効化します:

  1. django.contrib.adminINSTALLED_APPS に追加します。
  2. admin インタフェースでの編集を可能にするモデルを決めます。
  3. 2 で決めたモデルに対して、必要なら ModelAdmin クラスを定義します。 ModelAdmin はモデルごとにカスタマイズした admin の機能やオプショ ンをカプセル化しています。
  4. AdminSite をインスタンス化して、モデルや ModelAdmin クラスを 指定します。
  5. AdminSite インスタンスを URLconf にフックします。
Other topics
Admin actions
revision-up-to:11321 (1.1) unfinished

The basic workflow of Django’s admin is, in a nutshell, “select an object, then change it.” This works well for a majority of use cases. However, if you need to make the same change to many objects at once, this workflow can be quite tedious.

In these cases, Django’s admin lets you write and register “actions” – simple functions that get called with a list of objects selected on the change list page.

If you look at any change list in the admin, you’ll see this feature in action; Django ships with a “delete selected objects” action available to all models. For example, here’s the user module from Django’s built-in django.contrib.auth app:

_images/user_actions.png

Warning

The “delete selected objects” action uses QuerySet.delete() for efficiency reasons, which has an important caveat: your model’s delete() method will not be called.

If you wish to override this behavior, simply write a custom action which accomplishes deletion in your preferred manner – for example, by calling Model.delete() for each of the selected items.

For more background on bulk deletion, see the documentation on object deletion.

Read on to find out how to add your own actions to this list.

Writing actions

The easiest way to explain actions is by example, so let’s dive in.

A common use case for admin actions is the bulk updating of a model. Imagine a simple news application with an Article model:

from django.db import models

STATUS_CHOICES = (
    ('d', 'Draft'),
    ('p', 'Published'),
    ('w', 'Withdrawn'),
)

class Article(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField()
    status = models.CharField(max_length=1, choices=STATUS_CHOICES)

    def __unicode__(self):
        return self.title

A common task we might perform with a model like this is to update an article’s status from “draft” to “published”. We could easily do this in the admin one article at a time, but if we wanted to bulk-publish a group of articles, it’d be tedious. So, let’s write an action that lets us change an article’s status to “published.”

Writing action functions

First, we’ll need to write a function that gets called when the action is trigged from the admin. Action functions are just regular functions that take three arguments:

  • The current ModelAdmin
  • An HttpRequest representing the current request,
  • A QuerySet containing the set of objects selected by the user.

Our publish-these-articles function won’t need the ModelAdmin or the request object, but we will use the queryset:

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')

Note

For the best performance, we’re using the queryset’s update method. Other types of actions might need to deal with each object individually; in these cases we’d just iterate over the queryset:

for obj in queryset:
    do_something_with(obj)

That’s actually all there is to writing an action! However, we’ll take one more optional-but-useful step and give the action a “nice” title in the admin. By default, this action would appear in the action list as “Make published” – the function name, with underscores replaced by spaces. That’s fine, but we can provide a better, more human-friendly name by giving the make_published function a short_description attribute:

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')
make_published.short_description = "Mark selected stories as published"

Note

This might look familiar; the admin’s list_display option uses the same technique to provide human-readable descriptions for callback functions registered there, too.

Adding actions to the ModelAdmin

Next, we’ll need to inform our ModelAdmin of the action. This works just like any other configuration option. So, the complete admin.py with the action and its registration would look like:

from django.contrib import admin
from myapp.models import Article

def make_published(modeladmin, request, queryset):
    queryset.update(status='p')
make_published.short_description = "Mark selected stories as published"

class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'status']
    ordering = ['title']
    actions = [make_published]

admin.site.register(Article, ArticleAdmin)

That code will give us an admin change list that looks something like this:

_images/article_actions.png

That’s really all there is to it! If you’re itching to write your own actions, you now know enough to get started. The rest of this document just covers more advanced techniques.

Advanced action techniques

There’s a couple of extra options and possibilities you can exploit for more advanced options.

Actions as ModelAdmin methods

The example above shows the make_published action defined as a simple function. That’s perfectly fine, but it’s not perfect from a code design point of view: since the action is tightly coupled to the Article object, it makes sense to hook the action to the ArticleAdmin object itself.

That’s easy enough to do:

class ArticleAdmin(admin.ModelAdmin):
    ...

    actions = ['make_published']

    def make_published(self, request, queryset):
        queryset.update(status='p')
    make_published.short_description = "Mark selected stories as published"

Notice first that we’ve moved make_published into a method and renamed the modeladmin parameter to self, and second that we’ve now put the string 'make_published' in actions instead of a direct function reference. This tells the ModelAdmin to look up the action as a method.

Defining actions as methods gives the action more straightforward, idiomatic access to the ModelAdmin itself, allowing the action to call any of the methods provided by the admin.

For example, we can use self to flash a message to the user informing her that the action was successful:

class ArticleAdmin(admin.ModelAdmin):
    ...

    def make_published(self, request, queryset):
        rows_updated = queryset.update(status='p')
        if rows_updated == 1:
            message_bit = "1 story was"
        else:
            message_bit = "%s stories were" % rows_updated
        self.message_user(request, "%s successfully marked as published." % message_bit)

This make the action match what the admin itself does after successfully performing an action:

_images/article_actions_message.png
Actions that provide intermediate pages

By default, after an action is performed the user is simply redirected back to the original change list page. However, some actions, especially more complex ones, will need to return intermediate pages. For example, the built-in delete action asks for confirmation before deleting the selected objects.

To provide an intermediary page, simply return an HttpResponse (or subclass) from your action. For example, you might write a simple export function that uses Django’s serialization functions to dump some selected objects as JSON:

from django.http import HttpResponse
from django.core import serializers

def export_as_json(modeladmin, request, queryset):
    response = HttpResponse(mimetype="text/javascript")
    serializers.serialize("json", queryset, stream=response)
    return response

Generally, something like the above isn’t considered a great idea. Most of the time, the best practice will be to return an HttpResponseRedirect and redirect the user to a view you’ve written, passing the list of selected objects in the GET query string. This allows you to provide complex interaction logic on the intermediary pages. For example, if you wanted to provide a more complete export function, you’d want to let the user choose a format, and possibly a list of fields to include in the export. The best thing to do would be to write a small action that simply redirects to your custom export view:

from django.contrib import admin
from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponseRedirect

def export_selected_objects(modeladmin, request, queryset):
    selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME)
    ct = ContentType.objects.get_for_model(queryset.model)
    return HttpResponseRedirect("/export/?ct=%s&ids=%s" % (ct.pk, ",".join(selected)))

As you can see, the action is the simple part; all the complex logic would belong in your export view. This would need to deal with objects of any type, hence the business with the ContentType.

Writing this view is left as an exercise to the reader.

Making actions available site-wide
AdminSite.add_action(action[, name])

Some actions are best if they’re made available to any object in the admin site – the export action defined above would be a good candidate. You can make an action globally available using AdminSite.add_action(). For example:

from django.contrib import admin

admin.site.add_action(export_selected_objects)

This makes the export_selected_objects action globally available as an action named “export_selected_objects”. You can explicitly give the action a name – good if you later want to programatically remove the action – by passing a second argument to AdminSite.add_action():

admin.site.add_action(export_selected_objects, 'export_selected')
Disabling actions

Sometimes you need to disable certain actions – especially those registered site-wide – for particular objects. There’s a few ways you can disable actions:

Disabling a site-wide action
AdminSite.disable_action(name)

If you need to disable a site-wide action you can call AdminSite.disable_action().

For example, you can use this method to remove the built-in “delete selected objects” action:

admin.site.disable_action('delete_selected')

Once you’ve done the above, that action will no longer be available site-wide.

If, however, you need to re-enable a globally-disabled action for one particular model, simply list it explicitally in your ModelAdmin.actions list:

# Globally disable delete selected
admin.site.disable_action('delete_selected')

# This ModelAdmin will not have delete_selected available
class SomeModelAdmin(admin.ModelAdmin):
    actions = ['some_other_action']
    ...

# This one will
class AnotherModelAdmin(admin.ModelAdmin):
    actions = ['delete_selected', 'a_third_action']
    ...
Disabling all actions for a particular ModelAdmin

If you want no bulk actions available for a given ModelAdmin, simply set ModelAdmin.actions to None:

class MyModelAdmin(admin.ModelAdmin):
    actions = None

This tells the ModelAdmin to not display or allow any actions, including any site-wide actions.

Conditionally enabling or disabling actions
ModelAdmin.get_actions(request)

Finally, you can conditionally enable or disable actions on a per-request (and hence per-user basis) by overriding ModelAdmin.get_actions().

This returns a dictionary of actions allowed. The keys are action names, and the values are (function, name, short_description) tuples.

Most of the time you’ll use this method to conditionally remove actions from the list gathered by the superclass. For example, if I only wanted users whose names begin with ‘J’ to be able to delete objects in bulk, I could do the following:

class MyModelAdmin(admin.ModelAdmin):
    ...

    def get_actions(self, request):
        actions = super(MyModelAdmin, self).get_actions(request)
        if request.user.username[0].upper() != 'J':
            del actions['delete_selected']
        return actions

See also

For information about serving the media files (images, JavaScript, and CSS) associated with the admin in production, see serving-media-files.

ModelAdmin オブジェクト
class ModelAdmin

ModelAdmin クラスは、 admin インタフェース上のモデルを表現しています。 このクラスは、アプリケーションの admin.py という名前のファイルに保存し ます。 ModelAdmin の簡単な例を以下に示します:

from django.contrib import admin
from myproject.myapp.models import Author

class AuthorAdmin(admin.ModelAdmin):
    pass
admin.site.register(Author, AuthorAdmin)

Do you need a ModelAdmin object at all?

In the preceding example, the ModelAdmin class doesn’t define any custom values (yet). As a result, the default admin interface will be provided. If you are happy with the default admin interface, you don’t need to define a ModelAdmin object at all – you can register the model class without providing a ModelAdmin description. The preceding example could be simplified to:

from django.contrib import admin
from myproject.myapp.models import Author

admin.site.register(Author)
ModelAdmin のオプション

ModelAdmin はとてもフレキシブルなクラスです。このクラスには、 admin イ ンタフェースをカスタマイズするためのオプションがいくつもあります。オプショ ンは、全て、 ModelAdmin のサブクラスで以下のように指定します:

class AuthorAdmin(admin.ModelAdmin):
    date_hierarchy = 'pub_date'
ModelAdmin.date_hierarchy

date_hierarchy をモデルの DateFieldDateTimeField に指定する と、変更リストのページに、指定フィールドの日付を使って日付ベースで絞り込み できるナビゲーションが組み込まれます。

例:

date_hierarchy = 'pub_date'
ModelAdmin.form

デフォルトの設定では、モデルに対して ModelForm が動的に生成され、追加/ 変更ページでフォームを生成するときに使われます。 form を独自の ModelForm と置き換えれば、追加/変更ページのふるまいを変更できます。

詳しくは、 admin にカスタムのバリデーションを追加する を参照してください。

ModelAdmin.fieldsets

admin の「追加 (add)」および「変更 (change)」ページのレイアウトを制御するに は、 fieldsets を使います。

fieldsets は 2 要素のタプルのリストです。各タプルは admin フォームペー ジ上の <fieldset> を表します (<fieldset> はいわばフォームの「セクショ ン」です)。

フィールドセットは (name, field_options) の形式をとります。 name はフィールドセットの名前を表す文字列で、 field_options はフィールドセッ ト内で表示したいフィールドの情報を入れた辞書です。この情報の中に、表示した いフィールドのリストも指定します。

django.contrib.flatpages.FlatPage モデルから抜き出した例を示します:

class FlatPageAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {
            'fields': ('url', 'title', 'content', 'sites')
        }),
        ('Advanced options', {
            'classes': ('collapse',),
            'fields': ('enable_comments', 'registration_required', 'template_name')
        }),
    )

このフィールドセットによって、 admin のページは以下のようになります:

_images/flatfiles_admin.png

fieldsets を指定しない場合、 Django は AutoField でなく、かつ editable=True であるようなフィールドを、モデルに定義した順番に個別のフィー ルドセットとして表示します。

field_options 辞書には以下のようなキーを指定できます:

  • fields フィールドセット内に表示するフィールド名からなるタプルです。 必須のキーです。

    使い方:

    {
    'fields': ('first_name', 'last_name', 'address', 'city', 'state'),
    }
    

    同じ行に複数のフィールドを表示したい場合、それらのフィールドをタプ ルでラップして入れます。下の例では、 first_namelast_name が同じ行に表示されます:

    {
    'fields': (('first_name', 'last_name'), 'address', 'city', 'state'),
    }
    
  • classes

    フィールドセットに適用される追加の CSS クラス名です。

    使い方:

    {
    'classes': ['wide', 'extrapretty'],
    }
    

    admin サイトのデフォルトのスタイルシートで定義されている便利なクラ スとして collapsewide があります。 collapse スタイ ルのフィールドセットは、 admin ページでは最初折り畳まれ (collapse) ており、小さな”クリックして展開 (click to expand)” リンクに置き換わっ ています。 wide スタイルのフィールドセットには水平方向に追加のス ペースが加わります。

  • description

    各フィールドセットの先頭の、ヘッダのすぐ下に表示する追加の文字列で、 オプションです。

    この文字列は admin 上で HTML エスケープ されません 。そのため、必 要ならそのまま HTML を入れられます。また、 HTML 固有の文字をエスケー プしたければ、 django.utils.html.escape() を使ってください。

ModelAdmin.fields

レイアウトを気にせず、単にモデルの一部のフィールドだけをフォームに表示した いだけの場合に、 fieldsets の代わりに使ってください。例えば、 django.contrib.flatpages.FlatPage モデルの admin フォームの簡単なバージョ ンを以下のように定義できます:

class FlatPageAdmin(admin.ModelAdmin):
    fields = ('url', 'title', 'content')

上の例では、 ‘url’, ‘title’, ‘content’ フィールドだけが順番にフォームに表示 されます。

Note

この fields オプションと fieldsets オプションの中の fields キーとを混同しないでくださいね。

ModelAdmin.exclude

この属性にフィールドの名前のリストを指定すると、指定したフィールドがフォー ムから除去されます。

例えば、以下のようなモデルがあったとします:

class Author(models.Model):
    name = models.CharField(max_length=100)
    title = models.CharField(max_length=3)
    birth_date = models.DateField(blank=True, null=True)

nametitle フィールドだけを含む Author モデルのフォームを 表示したければ、 fieldsexclude を使って、それぞれ以下のように 定義できます:

class AuthorAdmin(admin.ModelAdmin):
    fields = ('name', 'title')

class AuthorAdmin(admin.ModelAdmin):
    exclude = ('birth_date',)

Author モデルは 3 つのフィールド name, title, birth_date しか持たないので、上の 2 つの例は全く同じフィールドを含むフォームを生成しま す。

ModelAdmin.filter_horizontal

ユーザビリティが紙一重の <select multiple> の代わりに、気の利いた控えめ な Javascript の「フィルタ」インタフェースを使います。フィルタインタフェー スを横並びにして表示させたいフィールドのリストを指定してください。フィルタ インタフェースを縦並びにしたい場合は filter_vertical を使ってください。

ModelAdmin.filter_vertical

filter_horizontal とほぼ同じですが、フィルタインタフェースを縦並びで表 示します。

ModelAdmin.list_display

admin の変更リストページに表示するフィールドを制御するには list_display を使います。

使い方:

list_display = ('first_name', 'last_name')

list_display を指定しなければ、 admin サイトは各オブジェクトの __unicode__() 表現を表示するカラムを一つだけ表示します。

list_display には 4 通りの設定方法があります:

  • モデルのフィールド名:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name')
    
  • モデルインスタンスを引数にとる呼び出し可能オブジェクト:

    def upper_case_name(obj):
        return "%s %s" % (obj.first_name, obj.last_name).upper()
    upper_case_name.short_description = 'Name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = (upper_case_name,)
    
  • ModelAdmin の属性名を表す文字列。呼び出し可能オブジェクトと同じよ うに動作します:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('upper_case_name',)
    
        def upper_case_name(self, obj):
          return "%s %s" % (obj.first_name, obj.last_name).upper()
        upper_case_name.short_description = 'Name'
    
  • モデルの属性名を表す文字列。ただし、 self はモデルインスタンスを 表します:

    class Person(models.Model):
        name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def decade_born_in(self):
            return self.birthday.strftime('%Y')[:3] + "0's"
        decade_born_in.short_description = 'Birth decade'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'decade_born_in')
    

list_display にはいくつか特殊なケースがあります:

  • フィールドが ForeignKey の場合、関連づけられているオブジェクトの __unicode__() を表示します。

  • ManyToManyField フィールドの表示は、テーブルの各行に対して個別に SQL 文を実行することになってしまうのでサポートしていません。どうして も表示させたいなら、カスタムメソッドをモデルに実装して、メソッドの名 前を list_display に追加してください (list_display へのカスタ ムメソッドの追加については、後で詳しく説明しています)。

  • フィールドが BooleanFieldNullBooleanField の場合、 TrueFalse の代りに “オン” や “オフ” を示すアイコンを表示 します。

  • モデルや ModelAdmin のメソッド、呼び出し可能オブジェクトの名前を 指定した場合、 Django はデフォルトでメソッドの出力を HTML エスケープ します。メソッドの出力をエスケープしたくない場合には、メソッドの allow_tags 属性の値を True にしてください。

    以下に例を示します:

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        color_code = models.CharField(max_length=6)
    
        def colored_name(self):
            return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name)
        colored_name.allow_tags = True
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name', 'colored_name')
    
  • TrueFalse を返すようなモデルの ModelAdmin のメソッド、 呼び出し可能オブジェクトの名前を指定した返す場合、メソッドの boolean 属性を True に設定しておくと、Django は「オン」や「オ フ」のアイコンを表示します。

    以下に例を示します:

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def born_in_fifties(self):
            return self.birthday.strftime('%Y')[:3] == '195'
        born_in_fifties.boolean = True
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'born_in_fifties')
    
  • __str__() および __unicode__() メソッドは他のモデルメソッドと 同じように list_display に入れられるので、以下のように書いても全 く問題ありません:

    list_display = ('__unicode__', 'some_other_field')
    
  • 通常、 list_display の要素のうち、実際のデータベースのフィールド に対応していないものは、変更リストページで並び順を変えるときのカラム には使えません。 Django はソートをすべてデータベースレベルで行うから です。

    ただし、 list_display のいずれかの要素が実際にデータベース上のあ るフィールドを指している場合、 admin_order_field という属性を使っ て、 Django にそのことを教えられます。

    例を示しましょう:

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        color_code = models.CharField(max_length=6)
    
        def colored_first_name(self):
            return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name)
        colored_first_name.allow_tags = True
        colored_first_name.admin_order_field = 'first_name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'colored_first_name')
    

    この例では、 Django は Admin 上で colored_first_name を並べ変える 際に first_name フィールドを使います。

list_display_links を設定すると、 list_display のどのフィールドを オブジェクトの「変更」ページにリンクするかを制御できます。

デフォルトでは、変更リストページはオブジェクトの変更ページ中の第一カラム、 すなわち list_display の先頭に指定したフィールドにリンクを張ります。 list_display_links を使うと、リンク先のカラムを変更できます。 list_display_links には、フィールド名のリストまたはタプルを (list_display と同じ形式で) 指定します。

list_display_links に指定するフィールド名は、一つでも複数でも構いません。 フィールド名が list_display に列挙されている限り、 Django はどんなに多 くの (あるいはどんなにわずかな) フィールドがリンクされていても問題にしませ ん。必要なのは、 list_display_links を使うには list_display を定義 しておかねばならない、ということだけです。

以下の例では、 first_name および last_name フィールドが変更リス トページにリンクされます:

class PersonAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'birthday')
    list_display_links = ('first_name', 'last_name')
ModelAdmin.list_editable

Set list_editable to a list of field names on the model which will allow editing on the change list page. That is, fields listed in list_editable will be displayed as form widgets on the change list page, allowing users to edit and save multiple rows at once.

Note

list_editable interacts with a couple of other options in particular ways; you should note the following rules:

  • Any field in list_editable must also be in list_display. You can’t edit a field that’s not displayed!
  • The same field can’t be listed in both list_editable and list_display_links – a field can’t be both a form and a link.

You’ll get a validation error if either of these rules are broken.

ModelAdmin.list_filter

admin の変更リストページの右側のサイドバーにあるフィルタを有効にするには、 list_filter を設定します。この値はフィールド名のリストにします。 各フィールド名は BooleanField, CharField, DateField, DateTimeField, IntegerField, ForeignKey のいずれかでなければ なりません。

以下の例は django.contrib.auth.models.User モデルからとったもので、 list_displaylist_filter の仕組みを示しています:

class UserAdmin(admin.ModelAdmin):
    list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
    list_filter = ('is_staff', 'is_superuser')

上のコードによって、 admin の変更リストは以下のようになります:

_images/users_changelist.png

(この例では、後述の search_fields も定義しています。)

ModelAdmin.list_per_page

admin 変更リストをページ分割 (paginate) で表示するときに、各ページに何個の アイテムを表示するかを決めます。デフォルト値は 100 です。

list_select_related を設定すると、 admin の変更リストページに表示するオ ブジェクトリストを取得する際に select_related() を使うよう Django に指 示できます。これにより、データベースクエリの発行数を抑えられます。

値は True または False にします。デフォルトは False です。

list_display のいずれかのフィールドが ForeignKey の場合、 Django は この設定に関わらず select_related() を使います。

select_related() の詳細は select_related() のドキュメント を参照してください。

ModelAdmin.inlines

後述の InlineModelAdmin を参照してください。

ModelAdmin.ordering

ordering を設定すると、 admin の変更リストにおける整列順を指定できます。 値はタプルからなるリストで、モデルの ordering パラメタと同じ形式で指定 します。

この値を指定しない場合、 Django はモデルのデフォルトの整列順を使います。

Note

Django はリストやタプルの最初の要素だけを考慮して、後の要素は無視します。

ModelAdmin.prepopulated_fields

フィールドの値を別のフィールドの値からセットさせたい場合は、以下のように、 prepopulated_fields にフィールド名を対応付けた辞書を設定してください:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

prepopulated_fields をセットすると、フィールドに小さな JavaScript のア クションが設定され、引数に指定したフィールドから値を自動的に取り込みます。 prepopulated_fields は、主に他の複数のフィールドから SlugField フィー ルドの値を生成するときに使います。値は、まず各ソースフィールドの値を結合し て、その結果が有効なスラグになるよう変換 (スペースをダッシュに置換するなど) して生成します。

DateTimeField, ForeignKey および ManyToManyFieldprepopulated_fields に指定できません。

ModelAdmin.radio_fields

デフォルトでは、Django の admin は ForeignKey のフィールドや choices の設定されたフィールドに対してセレクタボックス (<select>) イン タフェースを使います。 radio_fields にフィールド名を指定しておくと、 Django はセレクタボックスの代りにラジオボタンのインタフェースを使います。 例えば、 groupPerson モデル上の ForeignKey フィールド であれば、以下のように書けます:

class PersonAdmin(admin.ModelAdmin):
    radio_fields = {"group": admin.VERTICAL}

ラジオボタンの並び方を指定するシンボル、 HORIZONTAL または VERTICALdjango.contrib.admin モジュールにあります。

ForeignKeychoices パラメタのセットされたフィールド以外に radio_fields を使ってはなりません。

ModelAdmin.raw_id_fields

デフォルトでは、Django の admin サイトは ForeignKey フィールドに対して セレクタボックス (<select>) インタフェースを使います。しかし、時にはリレー ション先の全てのオブジェクトの入ったセレクタボックスが生成され、ドロップダ ウン表示されるのを避けたい場合もあります。

raw_id_fields には、ウィジェットを Input に変更したいフィールドのリ ストを指定します。 ForeignKey または ManyToManyField を指定できます:

class ArticleAdmin(admin.ModelAdmin):
    raw_id_fields = ("newspaper",)
ModelAdmin.save_as

save_as を指定すると、 admin の編集フォームで「別名で保存 (save as)」機 能を使えるようになります。

通常、編集フォームには三つの保存オプション、すなわち「保存 (Save)」、「保存 して編集を続ける (Save and continue editing)」、「保存してもう一つ追加 (Save and add another)」があります。 save_asTrue にすると「保存 してもう一つ追加」は「別名で保存 (Save as)」に置き換わります。

「別名で保存」は、現在のオブジェクトをそのまま保存するのではなく、(新たな ID を持った) 別のオブジェクトとして保存することです。

デフォルトでは、 save_asFalse に設定されています。

ModelAdmin.save_on_top

save_on_top を指定すると、 admin の変更フォームの最上部に保存ボタンを追 加できます。

通常、保存ボタンはフォームの最下部だけに表示されます。 save_on_top を指 定すると、ボタンは最下部だけでなく最上部にも表示されます。

デフォルトでは、 save_on_topFalse です。

ModelAdmin.search_fields

search_fields を指定すると、 admin の変更リストページで検索ボックスを使 えるようになります。この値は、ユーザが検索クエリをテキストボックスに入力し たときに検索の対象に含めるフィールド名のリストです。

フィールドは CharFieldTextField のような何らかのテキストフィー ルドでなければなりません。 DB API の「リレーションを追跡する」表記を使えば、 ForeignKey を介したフィールドの指定も行えます:

search_fields = ['foreign_key__related_fieldname']

admin の検索ボックスで検索を実行すると、 Django は検索クエリを単語に分解し て、各単語を含むような全てのオブジェクトを返します。検索は大小文字を区別せ ず、 search_fields に指定したフィールドのうち少なくとも一つに単語が入っ ていればヒットします。例えば、 search_fields['first_name', 'last_name'] に設定されている場合、ユーザが john lennon を検索すると、 Django は以下のような WHERE 節を持った SQL と等価な検索を実行します:

WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%')
AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')

より高速な、あるいはより制約の厳しい検索を行うには、フィールド名の前に以下 のような演算子を置きます:

^

フィールドの先頭にマッチします。例えば、 search_fields['^first_name', '^last_name'] にして、ユーザが john lennon を検 索した場合、Django は以下のような WHERE 節の SQL に等価な検索を実行 します:

WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%')
AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%')

このクエリを使うと、データベースはカラムの先頭部分だけをチェックすれば よく、カラム中のデータ全体を調べなくてもよくなるため、通常の '%john%' クエリよりも効率的に検索を実行できます。加えて、カラムにイ ンデクスが設定されていれば、データベースによっては LIKE クエリであっ てもインデクスを使ったクエリを実行できるという利点があります。

=

大小文字を区別しない厳密一致です。例えば、 search_fields['=first_name', '=last_name'] にして、ユーザが john lennon を検 索した場合、 Django は以下のような WHERE 節の SQL に等価な検索を実行 します:

WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john')
AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')

クエリ入力はスペース区切りなので、この例に従うと、 first_name'john winston' である (スペースを含む) ようなレコードは検索でき ないので注意してください。

@
全文検索マッチを実行します。デフォルトの search メソッドに似ていますが、 インデクスを使います。現在のところ MySQL でしか使えません。
ModelAdmin.formfield_overrides

This provides a quick-and-dirty way to override some of the Field options for use in the admin. formfield_overrides is a dictionary mapping a field class to a dict of arguments to pass to the field at construction time.

Since that’s a bit abstract, let’s look at a concrete example. The most common use of formfield_overrides is to add a custom widget for a certain type of field. So, imagine we’ve written a RichTextEditorWidget that we’d like to use for large text fields instead of the default <textarea>. Here’s how we’d do that:

from django.db import models
from django.contrib import admin

# Import our custom widget and our model from where they're defined
from myapp.widgets import RichTextEditorWidget
from myapp.models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.TextField: {'widget': RichTextEditorWidget},
    }

Note that the key in the dictionary is the actual field class, not a string. The value is another dictionary; these arguments will be passed to __init__(). See フォーム API for details.

Warning

If you want to use a custom widget with a relation field (i.e. ForeignKey or ManyToManyField), make sure you haven’t included that field’s name in raw_id_fields or radio_fields.

formfield_overrides won’t let you change the widget on relation fields that have raw_id_fields or radio_fields set. That’s because raw_id_fields and radio_fields imply custom widgets of their own.

ModelAdmin.actions

A list of actions to make available on the change list page. See Admin actions for details.

ModelAdmin.actions_on_top
ModelAdmin.actions_on_bottom

Controls where on the page the actions bar appears. By default, the admin changelist displays actions at the top of the page (actions_on_top = True; actions_on_bottom = False).

ModelAdmin.change_list_template

Path to a custom template that will be used by the model objects “change list” view. Templates can override or extend base admin templates as described in Overriding Admin Templates.

If you don’t specify this attribute, a default template shipped with Django that provides the standard appearance is used.

ModelAdmin.change_form_template

Path to a custom template that will be used by both the model object creation and change views. Templates can override or extend base admin templates as described in Overriding Admin Templates.

If you don’t specify this attribute, a default template shipped with Django that provides the standard appearance is used.

ModelAdmin.object_history_template

Path to a custom template that will be used by the model object change history display view. Templates can override or extend base admin templates as described in Overriding Admin Templates.

If you don’t specify this attribute, a default template shipped with Django that provides the standard appearance is used.

ModelAdmin.delete_confirmation_template

Path to a custom template that will be used by the view responsible of showing the confirmation page when the user decides to delete one or more model objects. Templates can override or extend base admin templates as described in Overriding Admin Templates.

If you don’t specify this attribute, a default template shipped with Django that provides the standard appearance is used.

ModelAdmin のメソッド
ModelAdmin.save_model(self, request, obj, form, change)

save_model メソッドは HttpRequest, モデルインスタンス、 ModelForm インスタンス、オブジェクトの追加か変更かを表すブール値 (変更 の場合には True) を引数にとります。このメソッドを使えば、オブジェクトの 保存前 (pre-save) および保存後 (post-save) 処理を実行できます。

保存前に request.user をオブジェクトに保存するには、以下のようにします:

class ArticleAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        obj.save()
ModelAdmin.save_formset(self, request, form, formset, change)

save_formset メソッドは HttpRequest, モデルインスタンス、親クラスの ModelForm インスタンス、オブジェクトの追加か変更かを表すブール値 (変更 の場合には True) を引数にとります。

フォームセットの各モデルインスタンスの保存前に request.user をオブジェ クトに保存するには、以下のようにします:

class ArticleAdmin(admin.ModelAdmin):
    def save_formset(self, request, form, formset, change):
        instances = formset.save(commit=False)
        for instance in instances:
            instance.user = request.user
            instance.save()
        formset.save_m2m()
ModelAdmin.get_urls(self)

The get_urls method on a ModelAdmin returns the URLs to be used for that ModelAdmin in the same way as a URLconf. Therefore you can extend them as documented in URL ディスパッチャ:

class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(MyModelAdmin, self).get_urls()
        my_urls = patterns('',
            (r'^my_view/$', self.my_view)
        )
        return my_urls + urls

Note

Notice that the custom patterns are included before the regular admin URLs: the admin URL patterns are very permissive and will match nearly anything, so you’ll usually want to prepend your custom URLs to the built-in ones.

However, the self.my_view function registered above suffers from two problems:

  • It will not perform and permission checks, so it will be accessible to the general public.
  • It will not provide any header details to prevent caching. This means if the page retrieves data from the database, and caching middleware is active, the page could show outdated information.

Since this is usually not what you want, Django provides a convenience wrapper to check permissions and mark the view as non-cacheable. This wrapper is AdminSite.admin_view() (i.e. self.admin_site.admin_view inside a ModelAdmin instance); use it like so:

class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(MyModelAdmin, self).get_urls()
        my_urls = patterns('',
            (r'^my_view/$', self.admin_site.admin_view(self.my_view))
        )
        return my_urls + urls

Notice the wrapped view in the fifth line above:

(r'^my_view/$', self.admin_site.admin_view(self.my_view))

This wrapping will protect self.my_view from unauthorized access and will apply the django.views.decorators.cache.never_cache decorator to make sure it is not cached if the cache middleware is active.

If the page is cacheable, but you still want the permission check to be performed, you can pass a cacheable=True argument to AdminSite.admin_view():

(r'^my_view/$', self.admin_site.admin_view(self.my_view, cacheable=True))
ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs)

The formfield_for_foreignkey method on a ModelAdmin allows you to override the default formfield for a foreign key field. For example, to return a subset of objects for this foreign key field based on the user:

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "car":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
            return db_field.formfield(**kwargs)
        return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

This uses the HttpRequest instance to filter the Car foreign key field to only the cars owned by the User instance.

Other methods
ModelAdmin.add_view(self, request, form_url='', extra_context=None)

Django view for the model instance addition page. See note below.

ModelAdmin.change_view(self, request, object_id, extra_context=None)

Django view for the model instance edition page. See note below.

ModelAdmin.changelist_view(self, request, extra_context=None)

Django view for the model instances change list/actions page. See note below.

ModelAdmin.delete_view(self, request, object_id, extra_context=None)

Django view for the model instance(s) deletion confirmation page. See note below.

ModelAdmin.history_view(self, request, object_id, extra_context=None)

Django view for the page that shows the modification history for a given model instance.

Unlike the hook-type ModelAdmin methods detailed in the previous section, these five methods are in reality designed to be invoked as Django views from the admin application URL dispatching handler to render the pages that deal with model instances CRUD operations. As a result, completely overriding these methods will significantly change the behavior of the admin application.

One comon reason for overriding these methods is to augment the context data that is provided to the template that renders the view. In the following example, the change view is overridden so that the rendered template is provided some extra mapping data that would not otherwise be available:

class MyModelAdmin(admin.ModelAdmin):

    # A template for a very customized change view:
    change_form_template = 'admin/myapp/extras/openstreetmap_change_form.html'

    def get_osm_info(self):
        # ...

    def change_view(self, request, object_id, extra_context=None):
        my_context = {
            'osm_data': self.get_osm_info(),
        }
        return super(MyModelAdmin, self).change_view(request, object_id,
            extra_context=my_context)
ModelAdmin のメディア定義

たまに、 CSS や JavaScript を追加・変更ビューに追加したい場合があります。 ModelAdmin に内部クラス Media を定義すれば、これを実現できます:

class ArticleAdmin(admin.ModelAdmin):
    class Media:
        css = {
            "all": ("my_styles.css",)
        }
        js = ("my_code.js",)

これらのメディア名のパスには MEDIA_URL の内容が前置されます。また、 forms の通常のメディア定義 と同じ規則が当てはま ります。

admin にカスタムのバリデーションを追加する

admin にカスタムのバリデーションを追加するのはとても簡単です。 admin インタ フェースは django.forms を再利用しているので、 ModelAdmin クラス を使えばフォームを指定できます:

class ArticleAdmin(admin.ModelAdmin):
    form = MyArticleAdminForm

MyArticleAdminForm は、 import できる場所ならどこにでも置けます。フォー ムの中で、任意のフィールドにカスタムのバリデーションコードを追加できます:

class MyArticleAdminForm(forms.ModelForm):
    class Meta:
        model = Article

    def clean_name(self):
        # do something that validates your data
        return self.cleaned_data["name"]

このとき、 ModelForm を使うことが重要です。他のクラスではうまくいきませ ん。詳しくは forms ドキュメント内の カスタムのバリデーション を参照してください。 モデルフォームのバリデーションに関する注意 にも、さらに詳しい情報があります。

InlineModelAdmin オブジェクト

admin インタフェースには、他のモデルクラスのインスタンスを同じページで編集 する機能があります。この機能をインライン編集と呼びます。例えば以下のような 二つのモデルがあったとします:

class Author(models.Model):
   name = models.CharField(max_length=100)

class Book(models.Model):
   author = models.ForeignKey(Author)
   title = models.CharField(max_length=100)

ある著者 (Author) オブジェクトのページで、著者の書いた本 (Book) オブジェク トの情報を編集したいなら、 ModelAdmin.inlines 属性に InlineModelAdmin を指定します:

class BookInline(admin.TabularInline):
    model = Book

class AuthorAdmin(admin.ModelAdmin):
    inlines = [
        BookInline,
    ]

Django は、 InlineModelAdmin のサブクラスとして、以下の二つを提供してい ます:

* ``TabularInline``
* ``StackedInline``

これら二つの違いは、単にレンダリングに使われるテンプレートに過ぎません。

InlineModelAdmin のオプション

InlineModelAdmin クラスは ModelAdmin のサブクラスなので、以下に挙げ る独自の機能の他に、 ModelAdmin の機能を全て継承しています:

model

インライン編集する対象のモデルです。必須の引数です。

fk_name

モデルの外部キーの名前です。たいていの場合、外部キーは自動的に決定できます が、親モデルに対して外部キーを複数張っているようなモデルの場合は、 fk_name を明示的に決める必要があります。

formset

デフォルト値は BaseInlineFormset です。独自のフォームセットを指定すれば、 色々とカスタマイズできます。インラインオブジェクトのフォームは モデルフォームセット で生成されています。

form

form の値は ModelAdmin から継承されます。この値は、インラインオブジェ クトのフォームセットを生成するときに fomrset_factory に渡されます。

extra

フォームセットが、初期のフォームに加えて表示する追加のフォーム数を制御しま す。詳しくは formsets のドキュメント を参照 してください。

max_num

インラインで表示するフォームの最大個数を制御します。この値は直接オブジェク トの数には関係しませんが、あまり小さな値が設定されていると、影響することも あります。詳しくは 編集可能なオブジェクトの数を制限する を参照してください。

raw_id_fields

デフォルトの設定では、 Django の admin は ForeignKey の選択に選択ボック スインタフェース (<select>) を使います。しかし、リレーション先の全てのイン スタンスをドロップダウンに表示するときのオーバヘッドを防ぎたいときがありま す。

raw_id_fields には、モデルの ForeignKeyManyToManyField をリ ストで指定します。 raw_id_fields に指定したフィールドは、 Input ウィ ジェットを使います:

class BookInline(admin.TabularInline):
    model = Book
    raw_id_fields = ("pages",)
template

インラインオブジェクトをレンダリングするときに使われるテンプレートです。

verbose_name

モデルの内部クラス Metaverbose_name の設定をオーバライドします。

verbose_name_plural

モデルの内部クラス Metaverbose_name_plural の設定をオーバライド します。

一つのモデルから複数の外部キーが張られている場合のインライン編集の扱い

一つのモデルに対して、複数の外部キーが張られている場合があります。以下のよ うなモデルを例に考えてみましょう:

class Friendship(models.Model):
    to_person = models.ForeignKey(Person, related_name="friends")
    from_person = models.ForeignKey(Person, related_name="from_friends")

Person の admin サイトで、インラインの追加・編集ページを表示したくても、 どの外部キーを辿らせるかは自動で決められません。従って、明示的に決めてやる 必要があります:

class FriendshipInline(admin.TabularInline):
    model = Friendship
    fk_name = "to_person"

class PersonAdmin(admin.ModelAdmin):
    inlines = [
        FriendshipInline,
    ]
中間モデルを介した多対多リレーションを扱う

デフォルトの設定では、 admin で多対多のリレーションを表す場合、 ManyToManyField を定義しているモデルの中でインライン表示されるウィジェッ トを使います。しかし、 ManyToManyFieldthrough 引数に中間モデル を指定した場合、 admin は ManyToManyField のウィジェットを表示しません。 これは、中間モデルの各インスタンスを表示するのに一つのウィジェットでは足り ないためと、複数ウィジェットを表示するために必要なレイアウトが中間モデルに よって変わってしまうためです。

しかし、それでもインラインで編集を行いたい場合があります。好運なことに、イ ンライン admin モデル (inline admin model) を使えば簡単に実現できます。 例として、以下のようなモデルを考えましょう:

class Person(models.Model):
    name = models.CharField(max_length=128)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

中間モデルを admin で表示するには、まず Membership モデルに対するインラ インクラスを作成します:

class MembershipInline(admin.TabularInline):
    model = Membership
    extra = 1

上の簡単な例では、 InlineModelAdmin のデフォルトの設定を使って Membership モデルのインライン admin を定義しています。ただし、追加用の フォームの数を 1 つに制限しています。他にも、 InlineModelAdmin クラスの オプションを使えば、色々な設定をカスタマイズできます。

次に、 PersonGroup モデルの ModelAdmin クラスを定義します:

class PersonAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

class GroupAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

最後に、 PersonGroup を admin サイトに登録します:

admin.site.register(Person, PersonAdmin)
admin.site.register(Group, GroupAdmin)

これで、 admin サイトの PersonGroup の両方で、 Membership オブジェクトをインライン編集できます。

一般化リレーションをインラインで扱う

一般化リレーションオブジェクトもインラインで扱えます。以下のようなモデルが 定義されていたとしましょう:

class Image(models.Model):
    image = models.ImageField(upload_to="images")
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey("content_type", "object_id")

class Product(models.Model):
    name = models.CharField(max_length=100)

Product の追加/変更ビューで Image インスタンスを編集したり追加した りしたいなら、 django.contrib.contenttypes.genericGenericInlineModelAdmin を使います。 admin.py で、以下のように設定 してください:

from django.contrib import admin
from django.contrib.contenttypes import generic

from myproject.myapp.models import Image, Product

class ImageInline(generic.GenericTabularInline):
    model = Image

class ProductAdmin(admin.ModelAdmin):
    inlines = [
        ImageInline,
    ]

admin.site.register(Product, ProductAdmin)

django.contrib.contenttypes.genericGenericTabularInlineGenericStackedInline を提供していて、その動作は通常のインライン編集と 同じです。詳しくは contenttypes のドキュメント を参照してください。

admin テンプレートのオーバライド

admin モジュールが admin サイトの様々なページを生成するときに使うテンプレー トは、その大半を比較的簡単にオーバライドできます。オーバライドは、特定のア プリケーションやモデルだけのためにもオーバライドできます。

プロジェクトの admin テンプレートディレクトリを設定する

admin テンプレートファイルは contrib/admin/templates/admin ディレクトリ に入っています。

テンプレートをオーバライドするには、まずプロジェクトの templates ディレ クトリ内に admin ディレクトリを作成します。プロジェクトのテンプレートディ レクトリとは、 TEMPLATE_DIRS の中に設定されているディレクトリのいずれか です。

次に、 admin ディレクトリ内に、アプリケーションの名前から取った名前のディ レクトリを作成します。アプリケーションのサブディレクトリの中に、さらにモデ ルからとった名前のサブディレクトリを作成します。このとき、 admin アプリケー ションはモデル名を小文字に変換した名前でディレクトリを探すことに注意しましょ う。ですから、大小文字を区別するファイルシステム上にアプリケーションを配置 しているのなら、ディレクトリ名が全て小文字で構成されているか確認してくださ い。

特定のアプリケーション向けに admin テンプレートをオーバライドしたければ、テ ンプレートを django/contrib/admin/templates/admin からアプリケーション 名のディレクトリ下にコピーして編集してください。

例えば、 my_app の全てのモデルの変更リストにツールメニューを追加したい なら、 contrib/admin/templates/admin/change_list.html をプロジェクトの templates/admin/my_app/ ディレクトリにコピーして必要な変更を施します。

Page という名前のモデルの変更リストだけにツールメニューを追加したいなら、 ファイルを templates/admin/my_app/page ディレクトリにコピーします。

admin のテンプレートはオーバライドすべきか、置き換えるべきか

admin テンプレートはモジュラー構造で設計されているので、必ずしもいつもテン プレート全体を置き換える必要はありませんし、そうしないよう勧めます。基本的 には、変更の必要のあるセクションだけをオーバライドするのがよいでしょう。

上に挙げた例の続きとして説明しましょう。 Page モデルの History ツー ルの隣に新しくリンクを追加したいとします。 change_from.html を眺めたあ と、オーバライドする必要があるのは object-tools ブロックだけだと分かっ たとしましょう。その場合、新たな change_form.html は以下のように書けま す:

{% extends "admin/change_form.html" %}
{% load i18n %}
{% block object-tools %}
{% if change %}{% if not is_popup %}
  <ul class="object-tools">
    <li><a href="history/" class="historylink">{% trans "History" %}</a></li>
    <li><a href="mylink/" class="historylink">My Link</a></li>
    {% if has_absolute_url %}
        <li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">
            {% trans "View on site" %}</a>
        </li>
    {% endif%}
  </ul>
{% endif %}{% endif %}
{% endblock %}

これだけです!このファイルを templates/admin/my_app ディレクトリに置け ば、全てのモデル変更フォームでリンクが表示されるでしょう。

アプリケーションやモデル単位でオーバライドできるテンプレート

contrib/admin/templates/admin のテンプレートの全てが、アプリケーション やモデル単位でオーバライドできるわけではありません。以下のテンプレートはオー バライドできます:

  • app_index.html
  • change_form.html
  • change_list.html
  • delete_confirmation.html
  • object_history.html

この節で述べた方法でテンプレートをオーバライドできなくても、オーバライドし たい内容を templates/admin ディレクトリに配置することで、プロジェクト全 体の設定としてオーバライドできます。この方法は、カスタムの 404 ページや 500 ページをオーバライドするときに特に便利です。

Note

change_list_request.html のようなテンプレートは、カスタムの inclusion タグをレンダするために使われています。このテンプレートはオー バライドできますが、テンプレートを変更するときには、独自の inclusion タ グを作成しておいて、別の名前を付けておき、テンプレートで呼び出す方が よいでしょう。そうすれば、テンプレートを選択して使えるからです。

ルートテンプレートとログインテンプレート

インデクスページやログインページのテンプレートを変更したければ、 AdminSite インスタンスを自作して、 AdminSite.index_templateAdminSite.login_template プロパ ティの値を変更してください。

AdminSite オブジェクト
class AdminSite(name=None)

Django の管理サイトは django.contrib.admin.sites.AdminSite のインスタン スを使って表現しています。デフォルトでは、このクラスのインスタンスは django.contrib.admin.site としてすでに作成されていて、モデルや ModelAdmin インスタンスを登録できます。

独自のふるまいを実現する管理サイトを作りたければ、 AdminSite のサブクラ スを作成して、必要に応じてオーバライドや機能追加を行ってください。その後で、 作成したサブクラスを (他の Python クラスと同様に) 素直にインスタンス化して、 デフォルトの AdminSite インスタンスにモデルや ModelAdmin サブクラス を登録する代りに、作成したインスタンスに登録してください。

When constructing an instance of an AdminSite, you are able to provide a unique instance name using the name argument to the constructor. This instance name is used to identify the instance, especially when reversing admin URLs. If no instance name is provided, a default instance name of admin will be used.

AdminSite attributes
AdminSite.index_template

Path to a custom template that will be used by the admin site main index view. Templates can override or extend base admin templates as described in Overriding Admin Templates.

AdminSite.login_template

Path to a custom template that will be used by the admin site login view. Templates can override or extend base admin templates as described in Overriding Admin Templates.

URLconf に AdminSite インスタンスをフックする

Django admin サイト構築の最後のステップは、 AdminSite インスタンスの URLconf への設置です。設置を行うには、 URL を AdminSite.urls メソッドに 振り向けます。

以下の例では、デフォルトの AdminSite インスタンスである django.contrib.admin.site を、 /admin/ という URL にマップしていま す:

# urls.py
from django.conf.urls.defaults import *
from django.contrib import admin

admin.autodiscover()

urlpatterns = patterns('',
    ('^admin/', include(admin.site.urls)),

上の例では、 admin.autodiscover() を使って、 INSTALLED_APPSadmin.py モジュールを自動的にロードしています。

次の例では、 AdminSite インスタンス myproject.admin.admin_site/myadmin/ という URL にマップしています:

# urls.py
from django.conf.urls.defaults import *
from myproject.admin import admin_site

urlpatterns = patterns('',
    ('^myadmin/', include(admin_site.urls)),
)

自作した AdminSite を使っているのなら、 myproject.admin モジュール の中で各アプリケーションの admin.py モジュールを import しているはずなので、 autodiscover を呼ぶ必要はありません。

一つの URLconf で複数の admin サイトを使う

Django で作られた一つの Web サイト上で、複数の admin サイトインスタンスを簡 単に運営できます。方法は、単に AdminSite インスタンスを複数にして別々の URL で設置するだけです。

The method for hooking AdminSite instances into urls has changed in Django 1.1.

下の例では、 /basic-admin//advanced-admin/ という二つの URL で、 myproject.admin.basic_sitemyproject.admin.advanced_site という AdminSite インスタンスを使って、別々のバージョンの admin サイトを運営し ています:

# urls.py
from django.conf.urls.defaults import *
from myproject.admin import basic_site, advanced_site

urlpatterns = patterns('',
    ('^basic-admin/', include(basic_site.urls)),
    ('^advanced-admin/', include(advanced_site.urls)),
)

AdminSite instances take a single argument to their constructor, their name, which can be anything you like. This argument becomes the prefix to the URL names for the purposes of reversing them. This is only necessary if you are using more than one AdminSite.

Adding views to admin sites

Just like ModelAdmin, AdminSite provides a get_urls() method that can be overridden to define additional views for the site. To add a new view to your admin site, extend the base get_urls() method to include a pattern for your new view.

Note

Any view you render that uses the admin templates, or extends the base admin template, should provide the current_app argument to RequestContext or Context when rendering the template. It should be set to either self.name if your view is on an AdminSite or self.admin_site.name if your view is on a ModelAdmin.

Reversing Admin URLs

When an AdminSite is deployed, the views provided by that site are accessible using Django’s URL reversing system.

The AdminSite provides the following named URL patterns:

Page URL name Parameters
Index index  
Logout logout  
Password change password_change  
Password change done password_change_done  
i18n javascript jsi18n  
Application index page app_list app_label

Each ModelAdmin instance provides an additional set of named URLs:

Page URL name Parameters
Changelist {{ app_label }}_{{ model_name }}_changelist  
Add {{ app_label }}_{{ model_name }}_add  
History {{ app_label }}_{{ model_name }}_history object_id
Delete {{ app_label }}_{{ model_name }}_delete object_id
Change {{ app_label }}_{{ model_name }}_change object_id

These named URLs are registered with the application namespace admin, and with an instance namespace corresponding to the name of the Site instance.

So - if you wanted to get a reference to the Change view for a particular Choice object (from the polls application) in the default admin, you would call:

>>> from django.core import urlresolvers
>>> c = Choice.objects.get(...)
>>> change_url = urlresolvers.reverse('admin:polls_choice_change', args=(c.id,))

This will find the first registered instance of the admin application (whatever the instance name), and resolve to the view for changing poll.Choice instances in that instance.

If you want to find a URL in a specific admin instance, provide the name of that instance as a current_app hint to the reverse call. For example, if you specifically wanted the admin view from the admin instance named custom, you would need to call:

>>> change_url = urlresolvers.reverse('custom:polls_choice_change', args=(c.id,))

For more details, see the documentation on reversing namespaced URLs.

django.contrib.auth

revision-up-to:17812 (1.4)

Django でのユーザ認証 を参照してください。

コメントフレームワーク

revision-up-to:17812 (1.4)

Django には単純ながらカスタマイズ可能なコメントフレームワークが付属していま す。この組み込みのコメントフレームワークを使えば、任意のモデルにコメントを 付加できます。つまり、ブログエントリや写真、本、本の各章、その他あらゆるも のにコメントを付けられるのです。

Note

Django の古い (ドキュメント化されなかった) コメントフレームワークを使っ ていたのなら、アップグレードが必要です。 アップグレードガイド を参照してください。

クイックスタートガイド

comments を使うには、以下のステップに従います:

  1. INSTALLED_APPS'django.contrib.comments' を インストールします。

  2. manage.py syncdb を実行して、コメントフレームワークのテーブルを 生成します。

  3. コメントアプリケーションの URL をプロジェクトの urls.py にマップ します:

    urlpatterns = patterns('',
        ...
        (r'^comments/', include('django.contrib.comments.urls')),
        ...
    )
    
  4. コメントテンプレートタグ を使って、 コメント機能をテンプレートに埋め込みます。

コメントフレームワークの設定 も調べておきましょう。

コメントテンプレートタグ

コメントシステムは、主にテンプレートタグを使って操作します。テンプレートタ グを使えば、コメントをポストするためのフォームや、ポストされたコメントを埋 め込めます。

他のカスタムテンプレートタグライブラリと同様、使うには カスタムタグライブラリをロード しておかねばなりません:

{% load comments %}

タグライブラリをロードすれば、後で解説するテンプレートタグを使えるようにな ります。

どのオブジェクトにコメントを結びつけるか指定する

Django のコメントは、全て何らかのオブジェクトに「結びついて (attached)」い ます。コメントは、任意の Django モデルのインスタンスに結びつけられます。 以下のタグを使うと、 2 種類の方法で、コメントを結びつけたいオブジェクトを指 定できます:

  1. オブジェクトを直接参照する方法 – より一般的な方法です。たいていの場 合、コメントを結びつけたいオブジェクトはテンプレートコンテキストの中 に入っているはずです。そのオブジェクトを使います。

    例えば、あるブログのエントリ表示ページに entry という変数が入っ ていて、エントリオブジェクトを表現しているなら、以下のようにして、 entry に結び付いたコメントの数を表示できます:

    {% get_comment_count for entry as comment_count %}.
    
  2. オブジェクトをコンテンツタイプとオブジェクト id で指定する方法。何ら かの理由で、コメントを結び付ける対象のオブジェクトに直接アクセスでき ない場合に使います。

    上のような例で、オブジェクトの id が 14 だと分かっていて、かつ対 象のオブジェクトにアクセスできないなら、以下のようにします:

    {% get_comment_count for blog.entry 14 as comment_count %}
    

    この例の blog.entry は、アプリケーションラベルと (小文字にした) モデルクラス名をつなげたものです。

コメントを表示する

コメントの一覧を表示するには、テンプレートタグ render_comment_list または get_comment_list を使用します。

手軽にコメント一覧をレンダリングする

あるオブジェクトへのコメントを一覧表示する一番簡単な方法は render_comment_list を使用する方法です:

{% render_comment_list for [object] %}

たとえば:

{% render_comment_list for event %}

これは comments/list.html という名前のテンプレートを使ってコメントを レンダリングします。このテンプレートのデフォルトバージョンは Django に標準で 含まれています。

独自のコメントリストをレンダリングする

あるオブジェクトへのコメントのリストを取得するには get_comment_list を使います:

{% get_comment_list for [object] as [varname] %}

例を挙げましょう:

{% get_comment_list for event as comment_list %}
{% for comment in comment_list %}
    ...
{% endfor %}

これは Comment オブジェクトのリストを 返します。詳細は コメントモデルのドキュメント を参照してください。

コメントにリンクする
リリースノートを参照してください

特定のコメントへのパーマリンク (permalink) を提供するには、 get_comment_permalink を使います:

{% get_comment_permalink comment_obj [format_string] %}

デフォルトでは URL の後ろに追加される名前付きアンカー (訳注: # に続けて記す フラグメント識別子) は、 ‘c82’ のように、 ‘c’ にコメント ID を続けたものに なります。この動作を変更したい場合、カスタム書式を指定することもできます:

{% get_comment_permalink comment "#c%(id)s-by-%(user_name)s"%}

この書式を指定する文字列は、 Python 標準の書式化用文字列です。有効なマップキー として、コメントオブジェクトの属性すべてが利用可能になっています。

独自にカスタムしたアンカーのパターンを指定するかどうかに関わらず、 テンプレートの適切な場所に対応した名前付きアンカーを配置する必要があります。

たとえば:

{% for comment in comment_list %}
    <a name="c{{ comment.id }}"></a>
    <a href="{% get_comment_permalink comment %}">
        permalink for comment #{{ forloop.counter }}
    </a>
    ...
{% endfor %}

Warning

Safari/Webkig にはリダイレクト後に名前付きアンカーが忘れられる既知のバグが あります。これが実際問題としてコメントに与える影響は、 Safari/webkig ブラウザは正しいページにたどり着くものの名前付きアンカーの位置にまで スクロールしてくれない、というものです。

コメントの数を数える

オブジェクトに結びつけられたコメントの数を取得するには、 get_comment_count を使います:

{% get_comment_count for [object] as [varname]  %}

例を挙げましょう:

{% get_comment_count for event as comment_count %}

<p>This event has {{ comment_count }} comments.</p>
コメント投稿フォームを表示する

ユーザがコメントを投稿できるようフォームを表示するには、 render_comment_formget_comment_form を使います。

コメントフォームを手軽に出力する

コメントフォームを表示する最も簡単な方法は、 render_comment_form を使うやり方です:

{% render_comment_form for [object] %}

例を挙げましょう:

{% render_comment_form for event %}

このコードによって、Django に付属のデフォルトの comments/form.html テン プレートを使ってコメントフォームがレンダされます。

カスタムのコメントフォームを出力する

コメントフォームのルック&フィールを制御したければ、 get_comment_form を使って フォームオブジェクト を取得し、テンプレート内で使います:

{% get_comment_form for [object] as [varname] %}

これで、フォームは以下のように書けます:

{% get_comment_form for event as form %}
<table>
  <form action="{% comment_form_target %}" method="post">
    {% csrf_token %}
    {{ form }}
    <tr>
      <td colspan="2">
        <input type="submit" name="submit" value="Post">
        <input type="submit" name="preview" value="Preview">
      </td>
    </tr>
  </form>
</table>

このアプローチをとるときには、いくつか考慮すべき点があります。後述の コメントフォームに関する注意 をよく読んでく ださい。

コメントフォームターゲットを取得する

上の例では、 comment_form_target というもう一つのタグを使って、フォー ムの action 属性を取得していたことに気づいたでしょうか。このタグは、常 にコメントフォームのポスト先として正しい URL を返します。コメントフォームを 使うときには、いつも以下のように書いてください:

<form action="{% comment_form_target %}" method="post">
コメント投稿後にリダイレクトする

コメントが投稿された後にリダイレクトする URL を指定したい場合、 next という名前の非表示の input 要素をフォームに含めることができます。たとえば:

<input type="hidden" name="next" value="{% url my_comment_was_posted %}" />
コメントフォームに関する注意

コメントシステムの使っているフォームには、スパムを防ぐための重要な属性があ ります。これらの属性についてよく知っておきましょう:

  • フォームには、タイムスタンプやコメントを結び付ける対象のオブジェクト、 これらの情報を検証するための「セキュリティハッシュ(security hash)」な ど、いくつもの隠しフィールドが入っています。コメントスパム屋がよくや るように、これらのフィールドの値を改ざんしようとすると、コメントの投 稿に失敗します。

    自作のコメントフォームを出力するときには、この隠しフィールドの値を変 更せずに渡してください。

  • タイムスタンプは、長時間再生攻撃が繰り返されるのを防ぐために使われま す。フォームのリクエストからコメントのポストまで長時間経っている場合、 フォームの提出は拒否されます。

  • コメントフォームには、「 ハニーポット (honeypot)」フィールドがあ ります。このフィールドはトラップです: このフィールドに何らかのデータ が入力されると、そのコメントはスパムであると見なされます (スパムプロ グラムは、有効なフォーム入力を偽装するために、全てのフィールドを自動 的に埋めようとするからです)。

    デフォルトのフォームは、 CSS を使ってこのフォームを隠し、ラベルにも 警告の文字列を入れます。カスタムのテンプレートでコメントフォームを使 うときにも、同じようにしてください。

コメントアプリは Django に同梱されているより一般的な CSRF 対策の機能 に依存しています。そちらのドキュメントに記載されている通り、 CsrfViewMiddleware を使うのがベストです。しかし、もしそれを使っていなければ、 CSRF トークンとクッキーを出力できるよう、コメントフォームを含むすべてのビューで csrf_protect デコレータを使う必要があります。

その他の情報
組み込みのコメントモデル
revision-up-to:17812 (1.4)
class Comment

Django の組み込みコメントモデルです。次のフィールドを持ちます:

content_object

コメントが結びつけられたオブジェクトを指す GenericForeignKey 属性です。これを使うことで関連づけられたオブジェクトを取得できます (たとえば my_comment.content_object)。

このフィールドは GenericForeignKey なので、 実際には以下で説明する 2 つの属性のシンタックスシュガーです。

content_type

ContentType への ForeignKey です。これはコメントが 結びつけられたオブジェクトのタイプです。

object_pk

コメントが関連づけられたオブジェクトのプライマリキーを含んだ TextField です。

site

コメントが投稿された Site への ForeignKey です。

user

コメントを投稿した User への ForeignKey です。コメントが認証されていない ユーザによって登録された場合は空になるかもしれません。

user_name

コメントを投稿したユーザの名前です。

user_email

コメントを投稿したユーザの Email アドレスです。

user_url

コメントを投稿したユーザが入力した URL です。

comment

コメントの内容そのものです。

submit_date

コメントが送信された日付です。

ip_address

コメント投稿ユーザの IP アドレスです。

is_public

コメントがモデレーション待ち (Generic comment moderation を参照してください) ならば False です。もし True ならば、 そのコメントはサイト上で表示されます。

is_removed

コメントが削除されたならば True になります。コメントを単純に 削除するかわりに、削除済みコメントを追跡する目的で使われます。

コメントフレームワークの設定
revision-up-to:17812 (1.4)

以下の設定を使うと、コメントフレームワークのふるまいを制御できます:

COMMENTS_HIDE_REMOVED

True (デフォルト値) の場合、コメントを削除すると (テンプレートタグで取 得できる) コメントリストやコメント数の対象から外れます。この値を False にする場合、「このコメントはサイト管理者によって削除されました」といったメッ セージを出すなどの処理を実装せねばなりません。

COMMENT_MAX_LENGTH

文字数で数えたコメントフィールドの最大長です。指定値より長いコメントの投稿 は拒否されます。デフォルト値は 3000 です。

COMMENTS_APP

コメントフレームワークのカスタマイズ機能 を提供するアプリです。 INSTALLED_APPS と同じドット区切りの記法を 使ってください。独自の COMMENTS_APPINSTALLED_APPS にもリストアップしておく必要があります。

コメントアプリケーションのシグナル
revision-up-to:17812 (1.4)

コメントアプリケーションは、コメントのモデレーションやそれに類する処理を行 えるよう、 シグナル をいくつか定義しています。シグ ナルハンドラの登録方法や受信方法は シグナルの解説 を参照してください。

comment_will_be_posted
django.contrib.comments.signals.comment_will_be_posted

コメントフォームデータのチェックが済み、フォームが提出されて、コメントが保 存される直前に送信されます。このシグナルを使うと、入力されたコメントデータ をポストされた情報やその他のアクションに基づいて (置き換えで) 変更できます。

シグナルレシーバのいずれかが False を返すと、コメントの入力は無視され、 403 (not allowed) レスポンスを返します。

シグナルは Comment オブジェクトの pre_save に前後して (実際には直前に) 送信 されます。

シグナルは以下の引数を伴います:

sender
コメントモデルです。
comment
投稿処理中のコメントインスタンスです。まだデータベースには保存され ていないので、プライマリキーはなく、リレーションも正しく動作しない 可能性があります。
request
コメントの投稿に使われた HttpRequest です。
comment_was_posted
django.contrib.comments.signals.comment_was_posted

コメントの保存直後に送信されるシグナルです。

シグナルは以下の引数を伴います:

sender
コメントモデルです。
comment
投稿されたコメントインスタンスです。すでにデータベースに保存され ているので、このオブジェクトを変更した場合、再度 save() を呼び出す必要があります。
request
コメントの投稿に使われた HttpRequest です。
comment_was_flagged
django.contrib.comments.signals.comment_was_flagged

コメントが何らかの形で「フラグされた」直後に送信されます。フラグをチェック すれば、ユーザがコメントの削除を要求しているのか、モデレータによるコメント の承認/削除があったのか、その他カスタムのユーザフラグの変化などがわかりま す。

シグナルは以下の引数を伴います:

sender
コメントモデルです。
comment
投稿されたコメントインスタンスです。すでにデータベースに保存され ているので、このオブジェクトを変更した場合、再度 save() を呼び出す必要があります。
flag
コメントに結びつけられた CommentFlag です。
created
フラグが新たに結びつけられた場合は True, 他のフラグと重複する場 合には False です。
request
コメントの投稿に使われた HttpRequest です。
Django の以前のコメントシステムからの移行
revision-up-to:17812 (1.4)

Django の以前のバージョンには、もう撤廃された、ドキュメント化されていない コメントシステムがありました。このフレームワークをリバースエンジニアリング して使っていたユーザは、新たなコメントシステムに移行する必要があります。 このガイドでは、コメントシステムの移行方法を解説しています。

まず、新旧のコメントシステムの違いを示します:

  • 新しいシステムにはドキュメントがあります。
  • 新しいシステムは、 formsmodelforms のような新しく Django に 登場した機能を使っています。
  • コメントモデルは以前は FreeCommentComment モデルに分かれ ていましたが、 Comment に統合されました。
  • コメントに “email” および “URL” フィールドが追加されました。
  • レーティング (rating)、写真 (photo)、カルマ (karma) といった機能がな くなりました。これらは World Online でしか使っていなかったからです。
  • {% comment_form %} タグがなくなりました。その代り、新たなコメント のポストに使うフォームを返す {% get_comment_form %} と、 comments/form.html テンプレートを使ってフォームをレンダする {% render_comment_form %} の二つのタグが追加されました。
  • URLconf へのインクルード方法が変わりました。次のように書いていたところを:

    (r'^comments/', include('django.contrib.comments.urls.comments')),
    

    次のように書き換えてください:

    (r'^comments/', include('django.contrib.comments.urls')),
    
データの移行

コメントシステムのデータモデルは、新しいモデルで変更され、テーブルの名前も 変わりました。既存のデータを新たなコメントシステムに移す前に、 クイックスタートガイド に従って新たな コメントシステムをインストールし、適切なテーブルを生成しておいてください。

データを新たなコメントシステムに移行するには、以下のような SQL を直接実行し てください:

BEGIN;

INSERT INTO django_comments
    (content_type_id, object_pk, site_id, user_name, user_email, user_url,
    comment, submit_date, ip_address, is_public, is_removed)
SELECT
    content_type_id, object_id, site_id, person_name, '', '', comment,
    submit_date, ip_address, is_public, not approved
FROM comments_freecomment;

INSERT INTO django_comments
    (content_type_id, object_pk, site_id, user_id, user_name, user_email,
    user_url, comment, submit_date, ip_address, is_public, is_removed)
SELECT
    content_type_id, object_id, site_id, user_id, '', '', '', comment,
    submit_date, ip_address, is_public, is_removed
FROM comments_comment;

UPDATE django_comments SET user_name = (
    SELECT username FROM auth_user
    WHERE django_comments.user_id = auth_user.id
) WHERE django_comments.user_id is not NULL;
UPDATE django_comments SET user_email = (
    SELECT email FROM auth_user
    WHERE django_comments.user_id = auth_user.id
) WHERE django_comments.user_id is not NULL;

COMMIT;
コメントフレームワークをカスタマイズする
revision-up-to:17812 (1.4)

もし組み込みのコメントフレームワークがニーズに合わない場合、コメントアプリ の振る舞いを拡張して独自のデータやロジックを加えることができます。 コメントフレームワークは組み込みのコメントモデル、組み込みのコメントフォーム、 そして各種のコメントビューを拡張できるように作られています。

カスタマイズは、まず設定 COMMENTS_APP から始めましょう。 COMMENTS_APP に、あなたが使用したい、独自の振る舞いを提供するアプリの 名前を設定してください。設定は INSTALLED_APPS で使う書式と同じ書式で 行い、またそのアプリは INSTALLED_APPS の一覧に入っている必要が あります。

たとえば、もし my_comment_app という名前のアプリを使いたければ、 設定ファイルは次のようなコードを含むことになるでしょう:

INSTALLED_APPS = [
    ...
    'my_comment_app',
    ...
]

COMMENTS_APP = 'my_comment_app'

COMMENTS_APP で名前を指定したアプリは、アプリの __init__.py でモジュールレベルの関数をいくつか定義することで独自の振る舞いを提供します。 これらの関数の完全な一覧 は以下に記載しますが、 まずは簡単な例から見ていきましょう。

カスタムコメントアプリの例

もっとも一般的なカスタマイズの一例は、組み込みコメントモデルが提供するフィールド を変更するものです。たとえば、コメントを許可しているあるサイトがコメント投稿者に コメントのタイトルを付けられるようにしたいとします。組み込みコメントモデルには、 タイトルとして使えるフィールドはありません。

この種のカスタマイズを行うには、 3 つのことを行う必要があります:

  1. “title” フィールドを追加したカスタムのコメント Model を作成
  1. “title” フィールドを追加したカスタムのコメント Form を作成
  1. いくつかの関数を独自の COMMENTS_APP で定義することで、 Django にこれらのオブジェクトを使うよう伝える

ということで、上の例を続けると、 my_custom_app ディレクトリの下に 典型的なアプリの構造を作ることになります:

my_custom_app/
    __init__.py
    models.py
    forms.py

models.py の中では CommentWithTitle モデルを定義します:

from django.db import models
from django.contrib.comments.models import Comment

class CommentWithTitle(Comment):
    title = models.CharField(max_length=300)

普通は Comment モデルから派生したコメントモデルを作るでしょう。しかし、 もし「Comment モデルのフィールドを、物理的に削除あるいは変更したいが、 テンプレートは書き換えたくない」という場合には、 BaseCommentAbstractModel から派生させることに挑戦しても良いかも しれません。

次に、独自のコメントフォームを forms.py の中に定義します。これは少し 厄介です。フォームを作成してそれを返すよう CommentForm.get_comment_model() をオーバーライドし、また独自の title フィールドを処理するよう CommentForm.get_comment_create_data() をオーバーライドする必要があります:

from django import forms
from django.contrib.comments.forms import CommentForm
from my_comment_app.models import CommentWithTitle

class CommentFormWithTitle(CommentForm):
    title = forms.CharField(max_length=300)

    def get_comment_model(self):
        # Use our custom comment model instead of the built-in one.
        return CommentWithTitle

    def get_comment_create_data(self):
        # Use the data of the superclass, and add in the title field
        data = super(CommentFormWithTitle, self).get_comment_create_data()
        data['title'] = self.cleaned_data['title']
        return data

Django は特定のカスタムコメントフォームを書きやすくする 2 つの「ヘルパー」 クラスを提供しています。詳細は django.contrib.comments.forms を参照してください。

最後に、作成したクラスを使うよう Django に指示する 2 つのメソッドを my_custom_app/__init__.py の中で定義します:

from my_comments_app.models import CommentWithTitle
from my_comments_app.forms import CommentFormWithTitle

def get_model():
    return CommentWithTitle

def get_form():
    return CommentFormWithTitle

Warning

コメントアプリの中で循環インポートを作らないよう気を付けてください。 もし定義した通りにコメントの設定が使われていないように感じたなら – たとえばコメントのモデレーションポリシーが適用されていないなど – 循環インポートの問題があるかもしれません。

もしコメントに関する説明できない振る舞いが現れたなら、独自のコメント アプリケーションが Django のコメントモジュールをインポートするモジュールを (間接的なインポートも含めて) インポートしていないか確認してください。

上記のプロセスで、大半のシチュエーションに対応できるはずです。より高度な使い方 として、さらに定義することのできるメソッドがあります。それらについては次の 章で説明します。

カスタムコメントアプリの API

django.contrib.comments アプリは以下のメソッドを定義しています。 すべてのカスタムコメントアプリは、そのうち少なくとも一つを定義する必要が あります。しかし、どのメソッドも省略可能です。

get_model()

コメントに使う Model クラスを返します。このモデル は、必要な核となるフィールド群を定義した django.contrib.comments.models.BaseCommentAbstractModel を継承した ものになるはずです。

デフォルトの実装では django.contrib.comments.models.Comment を返します。

get_form()

コメントモデルの作成、検証、保存に使いたい Form クラスを返します。カスタムコメントフォームは最初に与えられる追加の引数 target_object を受け入れるべきです。これは、そのコメントに結びつけら れることになるオブジェクトです。

デフォルトの実装では django.contrib.comments.forms.CommentForm を返します。

Note

デフォルトのコメントフォームはいくつもの押し付けがましくない スパム防止機能を搭載しています (コメントフォームに関する注意 を参照してください)。もし独自のフォームに置き換えるのであれば、 組み込みフォームのソースコードを読んでみて、似たような機能を 導入した方が良いかもしれません。

get_form_target()

コメントを POST する URL を返します。これはコメントフォームをレンダリング するときに <form action> 属性になるでしょう。

デフォルトの実装は post_comment() ビューを指すリバース解決した URL を返します。

Note

もしカスタムコメントモデル・フォームを提供するけれどもデフォルトの post_comment() ビューを使いたい場合、そのモデルとフォームが 特定の追加の属性とメソッドを持つ必要があることに気付く必要があります。 詳しくは post_comment() ビューのドキュメントを参照してください。

get_flag_url()

「このコメントをフラグする」ビューの URL を返します。

デフォルトの実装は django.contrib.comments.views.moderation.flag() ビューを指すリバース解決した URL を返します。

get_delete_url()

「このコメントを削除する」ビューの URL を返します。

デフォルトの実装は django.contrib.comments.views.moderation.delete() ビューを指すリバース解決した URL を返します。

get_approve_url()

「このコメントを承認する」ビューの URL を返します。

デフォルトの実装は django.contrib.comments.views.moderation.approve() ビューを指すリバース解決した URL を返します。

コメントフォームクラス
revision-up-to:17812 (1.4)

django.contrib.comments.forms モジュールはコメントを処理するビューを書く、 あるいは カスタムコメントアプリ を書くとき に使うであろう、いくつかのフォームを含んでいます。

class CommentForm

メインのコメントフォームで、送信されたコメントを処理する標準、組み込みの 方法を表現します。これは django.contrib.comments の全ビューが、 送信されたコメントを処理するために使うクラスです。

もし Django の組み込みコメント処理用ビューに似たカスタムビューを作るので あれば、このフォームを使うと便利かもしれません。

カスタムコメントアプリ用の抽象コメントフォーム

もし カスタムコメントアプリ を作っている のであれば、フォームの処理の 一部分だけ を変更したいと思うと同時に 既存のフォームの処理を流用したいと思うでしょう。

実は CommentForm は、継承することでフォーム処理を部分的に再利用できる 2 つの抽象クラスで構成されています:

class CommentSecurityForm

コメントフォーム処理における、なりすまし防止の観点での処理を行います。

このクラスはそのコメントが結びつけられているオブジェクトを指す content_typeobject_pk フィールド、 timestamp 、そして 全フォームデータの security_hash を含んでいます。これらタイムスタンプと セキュリティハッシュによって、スパマーがフォーム送信を「リプレイ」することを 防ぎ、コメントの洪水を起こさないようにします。

class CommentDetailsForm

コメント自体の詳細を処理します。

このクラスは nameemailurl、そして comment フィールド と、関連した検証ロジックを含んでいます。

Generic comment moderation
revision-up-to:17812 (1.4) unfinished

Django’s bundled comments application is extremely useful on its own, but the amount of comment spam circulating on the Web today essentially makes it necessary to have some sort of automatic moderation system in place for any application which makes use of comments. To make this easier to handle in a consistent fashion, django.contrib.comments.moderation provides a generic, extensible comment-moderation system which can be applied to any model or set of models which want to make use of Django’s comment system.

Overview

The entire system is contained within django.contrib.comments.moderation, and uses a two-step process to enable moderation for any given model:

  1. A subclass of CommentModerator is defined which specifies the moderation options the model wants to enable.
  2. The model is registered with the moderation system, passing in the model class and the class which specifies its moderation options.

A simple example is the best illustration of this. Suppose we have the following model, which would represent entries in a Weblog:

from django.db import models

class Entry(models.Model):
    title = models.CharField(maxlength=250)
    body = models.TextField()
    pub_date = models.DateTimeField()
    enable_comments = models.BooleanField()

Now, suppose that we want the following steps to be applied whenever a new comment is posted on an Entry:

  1. If the Entry‘s enable_comments field is False, the comment will simply be disallowed (i.e., immediately deleted).
  2. If the enable_comments field is True, the comment will be allowed to save.
  3. Once the comment is saved, an email should be sent to site staff notifying them of the new comment.

Accomplishing this is fairly straightforward and requires very little code:

from django.contrib.comments.moderation import CommentModerator, moderator

class EntryModerator(CommentModerator):
    email_notification = True
    enable_field = 'enable_comments'

moderator.register(Entry, EntryModerator)

The CommentModerator class pre-defines a number of useful moderation options which subclasses can enable or disable as desired, and moderator knows how to work with them to determine whether to allow a comment, whether to moderate a comment which will be allowed to post, and whether to email notifications of new comments.

Built-in moderation options
class CommentModerator

Most common comment-moderation needs can be handled by subclassing CommentModerator and changing the values of pre-defined attributes; the full range of built-in options is as follows.

auto_close_field

If this is set to the name of a DateField or DateTimeField on the model for which comments are being moderated, new comments for objects of that model will be disallowed (immediately deleted) when a certain number of days have passed after the date specified in that field. Must be used in conjunction with close_after, which specifies the number of days past which comments should be disallowed. Default value is None.

auto_moderate_field

Like auto_close_field, but instead of outright deleting new comments when the requisite number of days have elapsed, it will simply set the is_public field of new comments to False before saving them. Must be used in conjunction with moderate_after, which specifies the number of days past which comments should be moderated. Default value is None.

close_after

If auto_close_field is used, this must specify the number of days past the value of the field specified by auto_close_field after which new comments for an object should be disallowed. Allowed values are None, 0 (which disallows comments immediately), or any positive integer. Default value is None.

email_notification

If True, any new comment on an object of this model which survives moderation (i.e., is not deleted) will generate an email to site staff. Default value is False.

enable_field

If this is set to the name of a BooleanField on the model for which comments are being moderated, new comments on objects of that model will be disallowed (immediately deleted) whenever the value of that field is False on the object the comment would be attached to. Default value is None.

moderate_after

If auto_moderate_field is used, this must specify the number of days past the value of the field specified by auto_moderate_field after which new comments for an object should be marked non-public. Allowed values are None, 0 (which moderates comments immediately), or any positive integer. Default value is None.

Simply subclassing CommentModerator and changing the values of these options will automatically enable the various moderation methods for any models registered using the subclass.

リリースノートを参照してください

moderate_after and close_after now accept 0 as a valid value.

Adding custom moderation methods

For situations where the built-in options listed above are not sufficient, subclasses of CommentModerator can also override the methods which actually perform the moderation, and apply any logic they desire. CommentModerator defines three methods which determine how moderation will take place; each method will be called by the moderation system and passed two arguments: comment, which is the new comment being posted, content_object, which is the object the comment will be attached to, and request, which is the HttpRequest in which the comment is being submitted:

CommentModerator.allow(comment, content_object, request)

Should return True if the comment should be allowed to post on the content object, and False otherwise (in which case the comment will be immediately deleted).

CommentModerator.email(comment, content_object, request)

If email notification of the new comment should be sent to site staff or moderators, this method is responsible for sending the email.

CommentModerator.moderate(comment, content_object, request)

Should return True if the comment should be moderated (in which case its is_public field will be set to False before saving), and False otherwise (in which case the is_public field will not be changed).

Registering models for moderation

The moderation system, represented by django.contrib.comments.moderation.moderator is an instance of the class Moderator, which allows registration and “unregistration” of models via two methods:

moderator.register(model_or_iterable, moderation_class)

Takes two arguments: the first should be either a model class or list of model classes, and the second should be a subclass of CommentModerator, and register the model or models to be moderated using the options defined in the CommentModerator subclass. If any of the models are already registered for moderation, the exception AlreadyModerated will be raised.

moderator.unregister(model_or_iterable)

Takes one argument: a model class or list of model classes, and removes the model or models from the set of models which are being moderated. If any of the models are not currently being moderated, the exception NotModerated will be raised.

Customizing the moderation system

Most use cases will work easily with simple subclassing of CommentModerator and registration with the provided Moderator instance, but customization of global moderation behavior can be achieved by subclassing Moderator and instead registering models with an instance of the subclass.

class Moderator

In addition to the Moderator.register() and Moderator.unregister() methods detailed above, the following methods on Moderator can be overridden to achieve customized behavior:

connect()

Determines how moderation is set up globally. The base implementation in Moderator does this by attaching listeners to the comment_will_be_posted and comment_was_posted signals from the comment models.

pre_save_moderation(sender, comment, request, **kwargs)

In the base implementation, applies all pre-save moderation steps (such as determining whether the comment needs to be deleted, or whether it needs to be marked as non-public or generate an email).

post_save_moderation(sender, comment, request, **kwargs)

In the base implementation, applies all post-save moderation steps (currently this consists entirely of deleting comments which were disallowed).

Example of using the built-in comments app
revision-up-to:17812 (1.4) unfinished

Follow the first three steps of the quick start guide in the documentation.

Now suppose, you have an app (blog) with a model (Post) to which you want to attach comments. Let’s also suppose that you have a template called blog_detail.html where you want to display the comments list and comment form.

Template

First, we should load the comment template tags in the blog_detail.html so that we can use its functionality. So just like all other custom template tag libraries:

{% load comments %}

Next, let’s add the number of comments attached to the particular model instance of Post. For this we assume that a context variable object_pk is present which gives the id of the instance of Post.

The usage of the get_comment_count tag is like below:

{% get_comment_count for blog.post object_pk as comment_count %}
<p>{{ comment_count }} comments have been posted.</p>

If you have the instance (say entry) of the model (Post) available in the context, then you can refer to it directly:

{% get_comment_count for entry as comment_count %}
<p>{{ comment_count }} comments have been posted.</p>
リリースノートを参照してください

Next, we can use the render_comment_list tag, to render all comments to the given instance (entry) by using the comments/list.html template:

{% render_comment_list for entry %}

Django will will look for the list.html under the following directories (for our example):

comments/blog/post/list.html
comments/blog/list.html
comments/list.html

To get a list of comments, we make use of the get_comment_list tag. Using this tag is very similar to the get_comment_count tag. We need to remember that get_comment_list returns a list of comments and hence we have to iterate through them to display them:

{% get_comment_list for blog.post object_pk as comment_list %}
{% for comment in comment_list %}
<p>Posted by: {{ comment.user_name }} on {{ comment.submit_date }}</p>
...
<p>Comment: {{ comment.comment }}</p>
...
{% endfor %}

Finally, we display the comment form, enabling users to enter their comments. There are two ways of doing so. The first is when you want to display the comments template available under your comments/form.html. The other method gives you a chance to customize the form.

The first method makes use of the render_comment_form tag. Its usage too is similar to the other three tags we have discussed above:

{% render_comment_form for entry %}

It looks for the form.html under the following directories (for our example):

comments/blog/post/form.html
comments/blog/form.html
comments/form.html

Since we customize the form in the second method, we make use of another tag called comment_form_target. This tag on rendering gives the URL where the comment form is posted. Without any customization, comment_form_target evaluates to /comments/post/. We use this tag in the form’s action attribute.

The get_comment_form tag renders a form for a model instance by creating a context variable. One can iterate over the form object to get individual fields. This gives you fine-grain control over the form:

{% for field in form %}
{% ifequal field.name "comment" %}
  <!-- Customize the "comment" field, say, make CSS changes -->
...
{% endfor %}

But let’s look at a simple example:

{% get_comment_form for entry as form %}
<!-- A context variable called form is created with the necessary hidden
fields, timestamps and security hashes -->
<table>
  <form action="{% comment_form_target %}" method="post">
    {% csrf_token %}
    {{ form }}
    <tr>
      <td colspan="2">
        <input type="submit" name="submit" value="Post">
        <input type="submit" name="preview" value="Preview">
      </td>
    </tr>
  </form>
</table>
Flagging

If you want your users to be able to flag comments (say for profanity), you can just direct them (by placing a link in your comment list) to /flag/{{ comment.id }}/. Similarly, a user with requisite permissions ("Can moderate comments") can approve and delete comments. This can also be done through the admin as you’ll see later. You might also want to customize the following templates:

  • flag.html
  • flagged.html
  • approve.html
  • approved.html
  • delete.html
  • deleted.html

found under the directory structure we saw for form.html.

Feeds

Suppose you want to export a feed of the latest comments, you can use the built-in LatestCommentFeed. Just enable it in your project’s urls.py:

from django.conf.urls import patterns, url, include
from django.contrib.comments.feeds import LatestCommentFeed

urlpatterns = patterns('',
# ...
    (r'^feeds/latest/$', LatestCommentFeed()),
# ...
)

Now you should have the latest comment feeds being served off /feeds/latest/.

リリースノートを参照してください

Prior to Django 1.3, the LatestCommentFeed was deployed using the syndication feed view:

from django.conf.urls import patterns
from django.contrib.comments.feeds import LatestCommentFeed

feeds = {
    'latest': LatestCommentFeed,
}

urlpatterns = patterns('',
# ...
    (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
        {'feed_dict': feeds}),
# ...
)
Moderation

Now that we have the comments framework working, we might want to have some moderation setup to administer the comments. The comments framework comes built-in with generic comment moderation. The comment moderation has the following features (all of which or only certain can be enabled):

  • Enable comments for a particular model instance.
  • Close comments after a particular (user-defined) number of days.
  • Email new comments to the site-staff.

To enable comment moderation, we subclass the CommentModerator and register it with the moderation features we want. Let’s suppose we want to close comments after 7 days of posting and also send out an email to the site staff. In blog/models.py, we register a comment moderator in the following way:

from django.contrib.comments.moderation import CommentModerator, moderator
from django.db import models

class Post(models.Model):
    title   = models.CharField(max_length = 255)
    content = models.TextField()
    posted_date = models.DateTimeField()

class PostModerator(CommentModerator):
    email_notification = True
    auto_close_field   = 'posted_date'
    # Close the comments after 7 days.
    close_after        = 7

moderator.register(Post, PostModerator)

The generic comment moderation also has the facility to remove comments. These comments can then be moderated by any user who has access to the admin site and the Can moderate comments permission (can be set under the Users page in the admin).

The moderator can Flag, Approve or Remove comments using the Action drop-down in the admin under the Comments page.

Note

Only a super-user will be able to delete comments from the database. Remove Comments only sets the is_public attribute to False.

contenttypes フレームワーク

revision-up-to:11321 (1.1) unfinished

Django には、 contenttypes アプリケーションが付属しています。 このアプリケーションを使うと、 Django で作成したプロジェクト中に存在する全 てのモデルを追跡できます。また、 contenttypes では、モデルを扱うための 高水準かつ汎用的なインタフェースを提供しています。

概要

contenttypes アプリケーションの心臓部は、 django.contrib.contenttypes.models で定義されている ContentType モデルです。 django.contrib.contenttypes.models.ContentType のインスタンスは、 プロジェクト上にインストールされているモデルの情報を表現したり保存したりし ています。 ContentType のイン スタンスは、新たにモデルをインストールすると自動的に生成されます。

ContentType のインスタンスは、 インスタンスの表現するモデルクラスを返したり、そのモデルクラスに対してオブ ジェクトをクエリするためのメソッドを提供しています。また、 ContentType モデルは ContentType を扱ったり、特定 のモデルの ContentType を取り 出すための カスタムマネジャ を持っています。

あるモデルから ContentType に リレーションを張れば、そのモデルからインストール済みの任意のモデルのインス タンスとの間に、「一般化リレーション(generic relation)」を張れます。

contenttypes フレームワークのインストール

contenttypes フレームワークは、 django-admin.py startproject の生成するデフォルトの settings.pyINSTALLED_APPS リスト に入っています。リストから除外してしまっている場合や、 INSTALLED_APPS を自分で設定した場合には、 INSTALLED_APPS'django.contrib.contenttypes' を追加してフ レームワークをインストールしてください。

通常は、 contenttypes フレームワークをインストールしておいた方がよいで しょう。 Django にバンドルされている以下のアプリケーションには、 contenttypes フレームワークが必要だからです:

  • admin アプリケーションは、管理インタフェース上で追加変更したオブ ジェクトの履歴を管理するために contenttypes を使います。
  • Django の 認証フレームワーク は、ユーザ パーミッションをモデルに結びつけるために contenttypes を使います。
  • Django のコメントシステム (django.contrib.comments) は、インス トールされている任意のモデルに対してコメントを付けられる機能を contenttypes で実現しています。
ContentType モデル
class models.ContentType

ContentType のインスタン スには 3 つのフィールドがあり、 3 つを組み合わせると、インストールされ ているモデルを一意に表現できます:

app_label

モデルの入っているアプリケーションの名前です。この名前はモデルの app_label 属性から取り出され、通常は Python の import パス の 末尾 の部分が入っています。例えば、アプリケーションが django.contrib.contenttypes なら、 app_labelcontenttypes です。

model

モデルクラスの名前です。

name

人間可読なモデル名です。この値は、モデルの verbose_name から取り出されます。

例を挙げて、 contenttypes の仕組みを見てみましょう。 contenttypes アプリケーションをインストールしておき、 INSTALLED_APPS 設定に sites アプリケーション を追加してから、 manage.py syncdb を実行してみてください。 django.contrib.sites.models.Site モデルがデータベースにインストールされ るはずです。それに伴って、以下の値がセットされた ContentType の新たなインスタ ンスが生成されているはずです:

  • app_label'sites' (django.contrib.sites の末尾) に設定 されています。
  • model'site' に設定されています。
  • name'site' に設定されています。
ContentType インスタンスのメソッド
class models.ContentType

ContentType インスタンス には、インスタンスの表現しているモデルクラスを取得したり、モデルクラス のインスタンスを取り出したりするためのメソッドがあります:

models.ContentType.get_object_for_this_type(**kwargs)

ContentType インスタンス の表現しているモデルでサポートされている 照合メソッドの引数 <field-lookups-intro> を取り、モデルインスタンスの get() 照合 <get-kwargs> を行って、対応するオブジェクトを返します。

models.ContentType.model_class()

ContentType インスタンス の表現しているモデルクラスを返します。

例を挙げましょう。まず、 User モデル の ContentType インスタンスを 照合します:

>>> from django.contrib.contenttypes.models import ContentType
>>> user_type = ContentType.objects.get(app_label="auth", model="user")
>>> user_type
<ContentType: user>

取り出した UserContentType から、 User モデルクラスを取り出したり、 User インスタンスを照合したりできます:

>>> user_type.model_class()
<class 'django.contrib.auth.models.User'>
>>> user_type.get_object_for_this_type(username='Guido')
<User: Guido>

get_object_for_this_type()model_class() を組 み合わせると、非常に重要なユースケースを実現できます:

  1. 二つのメソッドを使えば、特定のモデルクラスを import して使うのではな く、インストールされている全てのモデルに対して操作を行えるような一般 化された高水準のコードを書けます。実行時に app_labelmodel を指定して ContentType を照合し、 得られたモデルクラスからオブジェクトを取り出せるのです。
  2. 別のモデルから ContentType にリレーショ ンを張って、モデルのインスタンスと、 ContentType の表すモデ ルクラスを結び付け、モデルクラスのメソッドにアクセスできます。

Django にバンドルされているアプリケーションには、後者のテクニックを使ってい るものがいくつかあります。例えば、 Django の認証フレームワークに入っている パーミッションのシステム では、 Permission モデルの中で、 ContentType への外部キー を張っています。そうすることで、 Permission は「ブログにエントリを追加」 や「ニュースストーリーを削除」といった権限を表現できます。

ContentTypeManager カスタムマネジャ
class models.ContentTypeManager

ContentType には ContentTypeManager` という カスタムマネジャがあります。このカスタムマネジャには、以下のメソッドが あります:

clear_cache()

ロード済みの ContentType インスタ ンスを保持しておくための内部キャッシュをクリアします。このメソッド を自分で呼ぶことはほとんどないでしょう。 Django は必要に応じて自動 的にメソッドを呼び出します。

get_for_model(model)

モデルクラスやモデルのインスタンスを引数にとり、そのモデルを表す ContentType インスタ ンスを返します。

ContentType を扱いたいけれど も、わざわざモデルのメタデータを取り出して ContentType を手動で照合する のが面倒な場合には get_for_model() メソッ ドが特に便利です:

>>> from django.contrib.auth.models import User
>>> user_type = ContentType.objects.get_for_model(User)
>>> user_type
<ContentType: user>
一般化リレーション

上で述べた Permission モデルの例のよう に、自作のモデルから ContentType に外部キーを張れ ば、モデルを別のモデルクラスに結び付けられます。しかし、もう一歩踏み込めば、 ContentType を使って真の一般 化リレーション (または多態性: polymorphic リレーション) を実現できます。

簡単な例として、以下のようなタグシステムを挙げましょう:

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic

class TaggedItem(models.Model):
    tag = models.SlugField()
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

    def __unicode__(self):
        return self.tag

通常の ForeignKey は、他のモデル を「指し示す」だけに過ぎません。従って、 TaggedItem モデルで ForeignKey を使う場合、ただ一つの モデルに対してしかタグを保存できません。この問題を解決し、任意のモデルにリ レーションを張れるようにするために、 contenttypes アプリケーションでは、 特殊なフィールドタイプ、 django.contrib.contenttypes.generic.GenericForeignKey を提供してい ます。 GenericForeignKey のセッ トアップは、以下の 3 つのパートに分かれています:

  1. ContentType への ForeignKey を定義します。

  2. リレーション先のモデルインスタンスの主キー値を保存するためのモデル フィールドを定義します (ほとんどのモデルでは、 IntegerField または PositiveIntegerField です)。

    このフィールドは、 GeneicRelation の対象モデルの主キーと同じ型でな ければなりません。例えば、モデルフィールドに IntegerField を使っ ているなら、対象モデルの主キーに CharField を使うことはできません。

  3. GenericForeignKey を定 義します。 GenericForeignKey の引 数に、上で定義したフィールドの名前を指定します。フィールド名が GenericForeignKey の探 すデフォルトの名前である content_typeobject_id の場合に は、引数を省略してかまいません。

これで、通常の ForeignKey に似た API を実現できます。 TaggedItem はリレーションを張っている対象のモデル インスタンスを返す content_object フィールドを持つようになります。 content_object の値は、 TaggedItem を生成するときに指定できます:

>>> from django.contrib.auth.models import User
>>> guido = User.objects.get(username='Guido')
>>> t = TaggedItem(content_object=guido, tag='bdfl')
>>> t.save()
>>> t.content_object
<User: Guido>

Due to the way GenericForeignKey is implemented, you cannot use such fields directly with filters (filter() and exclude(), for example) via the database API. They aren’t normal field objects. These examples will not work:

# This will fail
>>> TaggedItem.objects.filter(content_object=guido)
# This will also fail
>>> TaggedItem.objects.get(content_object=guido)
逆方向の一般化リレーション

リレーション対象にどのモデルがよく使われるのかが分かっていれば、 「逆方向の」一般化リレーションを張って、 API を追加できます。例を挙げましょ う:

class Bookmark(models.Model):
    url = models.URLField()
    tags = generic.GenericRelation(TaggedItem)

これで、 Bookmark インスタンスは tags 属性をそなえます。この属性を 使うと、インスタンスにリレーションを張っている TaggedItems を取り出せま す:

>>> b = Bookmark(url='http://www.djangoproject.com/')
>>> b.save()
>>> t1 = TaggedItem(content_object=b, tag='django')
>>> t1.save()
>>> t2 = TaggedItem(content_object=b, tag='python')
>>> t2.save()
>>> b.tags.all()
[<TaggedItem: django>, <TaggedItem: python>]

Just as django.contrib.contenttypes.generic.GenericForeignKey accepts the names of the content-type and object-ID fields as arguments, so too does GenericRelation; if the model which has the generic foreign key is using non-default names for those fields, you must pass the names of the fields when setting up a GenericRelation to it. For example, if the TaggedItem model referred to above used fields named content_type_fk and object_primary_key to create its generic foreign key, then a GenericRelation back to it would need to be defined like so:

tags = generic.GenericRelation(TaggedItem, content_type_field='content_type_fk', object_id_field='object_primary_key')

逆方向のリレーションを張らなければ、手動で照合する必要があります:

>>> b = Bookmark.objects.get(url='http://www.djangoproject.com/')
>>> bookmark_type = ContentType.objects.get_for_model(b)
>>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id,
...                           object_id=b.id)
[<TaggedItem: django>, <TaggedItem: python>]

Note that if the model with a GenericForeignKey that you’re referring to uses a non-default value for ct_field or fk_field (e.g. the django.contrib.comments app uses ct_field="object_pk"), you’ll need to pass content_type_field and object_id_field to GenericRelation.:

comments = generic.GenericRelation(Comment, content_type_field="content_type", object_id_field="object_pk")

GenericRelation` を持つオブジェ クトを削除すると、このオブジェクトに GenericForeignKey でリレーショ ンを張っているオブジェクトも全て削除されるので注意してください。つまり、上 の例では、 Bookmark オブジェクト b を削除すると、 b にリレーショ ンを張っている t1t2 といった TaggedItem も同時に削除される のです。

Generic relations and aggregation

Django’s database aggregation API <topics-db-aggregation doesn’t work with a GenericRelation. For example, you might be tempted to try something like:

Bookmark.objects.aggregate(Count('tags'))

This will not work correctly, however. The generic relation adds extra filters to the queryset to ensure the correct content type, but the aggregate method doesn’t take them into account. For now, if you need aggregates on generic relations, you’ll need to calculate them without using the aggregation API.

フォームや admin で一般化リレーションを扱う

django.contrib.contenttypes.generic では、二つのクラス、 GenericInlineFormSetGenericInlineModelAdmin を提供しています。これらのクラスを使うと、フォームや admin で一般化リレーショ ンを扱えます。詳しくは モデルフォームセットadmin のドキュメントを参照してください。

class generic.GenericInlineModelAdmin

GenericInlineModelAdmin クラスは、 InlineModelAdmin の全てのプロパティを継承していますが、一般化リレーションを扱うために、 以下の二つの属性を備えています:

ct_field

モデル内の ContentType の外部キーフィールド名です。デフォルトの値は content_type です。

ct_fk_field

リレーション先オブジェクトの ID を表す整数フィールドの名前です。 デフォルトの値は object_id です。

クロスサイトリクエストフォージェリ (CSRF) 対策

revision-up-to:17812 (1.4)

CSRF ミドルウェアとテンプレートタグは、簡単に使える クロスサイトリクエストフォージェリ (Cross Site Request Forgeries) 対策を提供しています。このタイプの攻撃は、悪意のあるウェブサイトを訪れたユーザー のログイン済みの権限で、あなたのサイトに対して何らかの操作を行うことを目的とした リンクやフォームボタン、 JavaScript を設置したウェブサイトによって行われます。 また、関連する攻撃として、ユーザーを騙して別のユーザー権限でログインさせる ログイン CSRF と呼ばれる攻撃もありますが、これも含まれます。

CSRF 攻撃に対する第一の防御は、 GET (と、9.1.1 Safe Methods,HTTP 1.1, RFC 2616#section-9.1.1 で定義された ‘安全な’ メソッド) リクエストから副作用を 取り除くというものです。そして、 POST, PUT, DELETE のような、’安全でない’ メソッ ドによるリクエストについては、下記の手順に従うことで対策することができます。

使い方

CSRF 対策をあなたのビューで有効にするには、以下の手順に従ってください。:

  1. 'django.middleware.csrf.CsrfViewMiddleware' ミドルウェアを MIDDLEWARE_CLASSES に追加してください。 (このミドルウェアは、 CSRF 対策が為されていることを前提として動作するどのミドルウェアよりも前に 追加します。)

    また、代わりに 対策したい特定のビューに対して、 csrf_protect() デコレータを使用することも できます (下記参照)

  1. 自身のサイト内で POST リクエストを送るすべてのフォームの <form> タグ内 で、 csrf_token テンプレートタグを使用します。例:

    <form action="." method="post">{% csrf_token %}
    

    外部のサイトに対してリクエストを送るフォームについては使用すべきではあり ません。 CSRF トークンが流出し、脆弱性を生むからです。

  1. 対応するビューの内部で、 'django.core.context_processors.csrf' コンテキストプロセッサーを使用出来るようにします。通常、2つの方法のうち、 どちらかの方法を選択します。:

    1. RequestContext を使用する。 RequestContext は、 (TEMPLATE_CONTEXT_PROCESSORS の設定によらず) 'django.core.context_processors.csrf' を常に使用します。もし、ジェ ネリックビューや Django 付属のアプリを使用している場合は、あなたは既に この方法を使用しています。なぜなら、これらのアプリは常に RequestContext を使用しているからです。
    1. 手動でインポートし、プロセッサーを使って CSRF トークンを生成して、 テンプレートのコンテキストに追加する。例:

      from django.core.context_processors import csrf
      from django.shortcuts import render_to_response
      
      def my_view(request):
          c = {}
          c.update(csrf(request))
          # ... view code here
          return render_to_response("a_template.html", c)
      

      このような処理を行う、 render_to_response() のラッパー関数を作成しても良いかもしれません。

補助スクリプトの extras/csrf_migration_helper.py を使えば、これらの手順を 行わなければならないテンプレートやコードを自動的に見つけてくれます。 また、どうやって使えばよいかのヘルプもすべて用意されています。

AJAX

上記の手順を AJAX を用いた POST リクエストで行うのは、少し不便です。あなたは、 すべての POST リクエストについて、 CSRF トークンを POST するデータに含めることを 覚えておかなければなりません。なので、別の方法が用意されています。それは、各 XMLHttpRequest に対して、 X-CSRFToken という独自ヘッダーに CSRF トークンの 値を設定することです。多くの JavaScript のフレームワークはすべてのリクエストに ついて、ヘッダーを設定するようなフック機能を提供しているので、この操作は多くの 場合、簡単に行うことができます。 jQuery の場合、 ajaxSend イベントを以下の ように記述します:

jQuery(document).ajaxSend(function(event, xhr, settings) {
    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    function sameOrigin(url) {
        // url could be relative or scheme relative or absolute
        var host = document.location.host; // host + port
        var protocol = document.location.protocol;
        var sr_origin = '//' + host;
        var origin = protocol + sr_origin;
        // Allow absolute or scheme relative URLs to same origin
        return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
            (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
            // or any other URL that isn't scheme relative or absolute i.e relative.
            !(/^(\/\/|http:|https:).*/.test(url));
    }
    function safeMethod(method) {
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }

    if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
        xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
    }
});

Note

jQuery 1.5 ではバグがあるため、上記の例は正しく動作しません。使用している jQuery のバージョンが 1.5.1 以上であることを確認してください。

これを サイトで使用される JavaScript のファイルに追加すれば、 jQuery 経由で 送信された AJAX POST リクエストは、CSRF 対策に引っかかることはなくなります。

上記のコードは、 jQuery cookie plugin を用いて、 getCookie を置き換え 、jQuery 1.5 以降で追加された settings.crossDomain を用いて sameOrigin を置き換えることに よって、さらに簡略化できます。

加えて、 csrf_token を使用して、クライアントに CSRF クッキーを送って いなかった場合、ユーザーがクッキーを受け取っていることを ensure_csrf_cookie() を用いて、保証する 必要があるかもしれません。

別のテンプレートエンジン

Django の組み込みではないテンプレートエンジンを使用する場合、テンプレートの コンテキストからトークンが取得できることを確認した上で、フォームに手動で追加して ください。

例えば、 Cheetah テンプレート言語を使用する場合、フォームは以下のコードを含む でしょう。:

<div style="display:none">
    <input type="hidden" name="csrfmiddlewaretoken" value="$csrf_token"/>
</div>

JavaScript に関しては、 取得した CSRF トークンの値を使用することによって、上記と 同じ方法で使用することができます。

デコレータメソッド

CsrfViewMiddlewre を追加して、サイト全体で対策する代わりに、まったく同じ機能 を保護が必要な特定のビューのみに持たせたいという場合には、 csrf_protect デコレータを使用することができます。ただし、 CSRF トークンを出力に埋め込むビュー と、フォームから POST されたデータを受け取るビュー (これらは、同じビューの 時も多いですが、違うビューの時もあります) の 両方で 使用しなけれなりません。

デコレータのみを使用することは 推奨されません 。なぜなら、もし、あなたが デコレータをつけ忘れてしまった場合、それがセキュリティホールを生むことになる からです。’念には念を (belt and blaces)’ の原則から両方を使用することは良いこと ですし、使用してもわずかなオーバーヘッドにしかならないでしょう。

csrf_protect(view)

CsrfViewMiddleware の CSRF 対策機能をビューに付加するデコレータ

使い方:

from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render

@csrf_protect
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)
拒否されたリクエスト

受け取ったリクエストが CsrfViewMiddleware によって行われる認証に失敗した場合 、デフォルトでは、ユーザに ‘403 Forbidden’ が送信されます。これは普通、本当に CSRF が行われたか、プログラマのミスによって、 POST フォームに CSRF トークンを 含め忘れたかでない限りは起こりません。

けれども、エラーページがあまり親切でないと感じるのならば、このような場面を処理 するために、自作のビューを設定することができます。 そうするには、単に settings の CSRF_FAILURE_VIEW を設定してください。

仕組み

CSRF 対策は以下の要素からなります :

  1. ランダムな値 (いわゆる、独立一時セッション (session independent nonce) ) が設定されており、外部のサイトから参照できない CSRF クッキー。

    このクッキーは CsrfViewMiddleware によって設定されます。これは、クッキー がずっと保持されることを前提としていますが、絶対に破棄されないクッキーを作成 することは不可能なので、 django.middleware.csrf.get_token() (この関数 は、内部的に CSRF トークンを取り出すために使用されています。) が呼び出された すべてのレスポンスについて、 CSRF クッキーが送信されます。

  1. すべての POST リクエストを送信するフォームに含まれる、 ‘csrfmiddlewaretoken’ という名前を持つ hidden フィールド。この値フィールドの値には、 CSRF クッキー の値が使われます。

    この処理は、テンプレートタグによって行われます。

  1. HTTP GET, HEAD, OPTIONS, TRACE メソッドを除く、すべてのメソッドについて、 CSRF クッキーと ‘csrfmiddlewaretoken’ フィールドを保持しており、なおかつ 正しい値を保持しているリクエスト。もし、そうでないならば、ユーザーは 403 エラーを受け取ることになります。

    この確認は、 CsrfViewMiddleware によって行われます。

  1. 加えて、 HTTPS リクエストの場合は、 リファラ (referer) が CsrfViewMiddleware によって厳密にチェックされます。これは、 独立一時 セッションを用いた HTTPS 通信における中間者攻撃(Man-In-The-Middle atack) に対応する必要があるからです。(不幸にも) HTTPS を使用しているサイトにおい ても、 HTTP の’Set-Cookie’ ヘッダーが認められてしまうという事実によります。 (HTTP では、リファラヘッダの内容は十分に信頼出来ないため、リファラのチェック は行われません。)

これらの処理により、あなたのウェブサイト由来のフォームだけが POST を送り返せる ことを保証できます。

ここでは、故意に GET リクエスト (と、その他 ‘安全’ と RFC 2616 によって定義 されたリクエスト) を無視しています。 これらのリクエストは危険な副作用を持た ないはずなので、 GET リクエストを使った CSRF 攻撃は威力を持たないのです。 RFC 2616 では、POST, PUT, DELETE が ‘安全でない’ ものとして定義されており、 その他のメソッドについては、安全でないものとみなして、最大限の対策を行なって います。

キャッシュする

csrf_token がテンプレート内で使用されている (もしくは、 get_token 関数が何らかの別の方法で呼び出されていた) 場合、 CsrfViewMiddleware は、 クッキーと Vary: Cookie ヘッダをレスポンスに付加するでしょう。これは、この ミドルウェアがキャッシュの扱い方を教えれば、キャッシュを扱うミドルウェアがうまく 処理してくれることを期待することを意味しています (UpdateCacheMiddleware は 他のどのミドルウェアよりも後に置きます)。

けれども、あなたが特定のビューに対してキャッシュを設定するデコレータを使用した 場合、 CSRF ミドルウェアは、まだ Vary ヘッダーや CSRF クッキーを設定できていない はずなので、レスポンスはこれらを含まないままキャッシュされてしまいます。この 場合、 CSRF トークンを必要とするであろうビューには、すべて django.views.decorators.csrf.csrf_protect() デコレータを先に使用しておくべき です。:

from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect

@cache_page(60 * 15)
@csrf_protect
def my_view(request):
    # ...
テストする

CsrfViewMiddleware は、すべての POST リクエストについて CSRF トークンを 必要とするため、普通、ビュー関数のテストの大きな障害になるでしょう。そのため、 Django のテスト用の HTTP クライアントは、 このミドルウェアと csrf_protect デコレータの制限を緩めるフラグを各リクエストに付加するので、これらがリクエストを 拒否することはなくなります。その他のすべての処理 (例えば、 クッキーの送信など) は、通常と同様に働きます。

もし、何らかの理由で CSRF のチェックを 有効にしたい と考えるのであれば、 CSRF のチェックを有効にしたテストクライアントを作成することができます。:

>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)
制限

サイト内のサブドメインは、ドメイン全体に対してクッキーを設定することができる でしょう。クッキーをセットしたり、対応するトークンを使用することによって、サブ ドメインからは CSRF 対策を巧みにすり抜けることができるでしょう。この問題を回避 するための唯一の手段は、サブドメインを信用できるユーザーによって管理させる(もし くは、最低でもクッキーを設定させないようにする) ことです。特筆すべき点は、 信用出来ない人間にサブドメインを与えることは、 CSRF 以外にも、セッションフィク セーション (session fixation) のような他の脆弱性も生むため、良い案ではありま せんし、この脆弱性は現在一般に使用されているブラウザにおいて簡単に修正できるも のではないことです。

特殊な場合

ある特定のビューでは、ここで紹介した通常のパターンに当てはまらないような特殊な 使い方が必要になることがあるでしょう。これらの状況では、いくつかのユーティリティ が役に立つでしょう。これらが必要になると思われるシナリオは、以下の節に書かれて います。

ユーティリティ
csrf_exempt(view)

このデコレータは、CSRF 対策のチェックが無効化されるビューを表します。例:

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')
requires_csrf_token(view)

通常、 csrf_token テンプレートタグは CsrfViewMiddleware.process_view や、それに準ずる csrf_protect の ようなものが実行されない限りは、動作しません。ビューに対するデコレータの requires_csrf_token は、このテンプレートタグが動作することを保証する ために使用されます。このデコレータは csrf_protect に似ていますが、到達 したリクエストを拒否することは決してありません。

例:

from django.views.decorators.csrf import requires_csrf_token
from django.shortcuts import render

@requires_csrf_token
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)
リリースノートを参照してください

このデコレータはビューに対して、強制的に CSRF クッキーを送出させます。

シナリオ
いくつかのビューでは CSRF 対策を解除しなければならない

ほとんどのビューでは CSRF 対策が必要としますが、いくつかだけはそうでない場合 です。

解決策: ミドルウェアを無効化し、必要とするビューすべてに対して csrf_protect を付加するよりも、ミドルウェアを有効にした上で csrf_exempt() を使用する方が良いでしょう。

CsrfViewMiddleware.process_view が使用されていない

ビューが実行される前に、CsrfViewMiddleware.process_view が実行されていない かもしれない場合があります。 - 例としては、404 や 500 のエラーハンドラーです。 - そのような状況でも CSRF トークンがフォーム内に必要になる場合です。

解決策: requires_csrf_token() を使用して ください。

CSRF 対策が無効化されているビューにおいて、CSRF トークンが必要になる

いくつかのビューでは csrf_exempt によって、対策が解除され、無効化されている かもしれません。そのような状況でも、 CSRF トークンが必要になる場合です。

解決策: csrf_exempt()requires_csrf_token() の後に使用してくだ さい。 (すなわち、 requires_csrf_token が最も内側のデコレータになるという ことです)

ビュー内の特定の経路で対策が必要になる

あるビューにおいて、特定の状態でのみ CSRF 対策が必要になり、なおかつ、 他の場合には CSRF 対策を行えない場合です。

解決策: csrf_exempt() をビュー全体では使用 し、対策が必要な経路にのみ csrf_protect() を 使用してください。例:

from django.views.decorators.csrf import csrf_exempt, csrf_protect

@csrf_exempt
def my_view(request):

    @csrf_protect
    def protected_path(request):
        do_something()

    if some_condition():
       return protected_path(request)
    else:
       do_something_else()
ページが HTML フォームではなく AJAX を使用している

あるページにおいて、 POST リクエストを AJAX 経由で送信し、なおかつ、ページが CSRF クッキーが送出されるために必要な csrf_token を含む HTML 上のフォ ームを持たない場合です。

解決策: そのページを生成するビューに対して、 ensure_csrf_cookie() を使用してください。

組み込みアプリと再利用されるアプリ

開発者は CsrfViewMiddleware を無効化することができるので、組み込みアプリ のうち、 CSRF に対する安全性を保証する必要があるすべてのアプリには csrf_protect デコレータが使用されています。他の場面で再利用されるアプリを 作成する開発者は、これと同じ保証が必要なビューに対しては csrf_protect デコ レータを使用することが推奨されています。

設定

Django の CSRF の動作を調整するためのいくつかの設定があります。

CSRF_FAILURE_VIEW
リリースノートを参照してください

デフォルト値: 'django.views.csrf.csrf_failure'

到達したリクエストが CSRF 対策によって拒否された場合に使用されるビュー関数への ドット区切りのパスです。 ビュー関数は以下の引数を取ります:

def csrf_failure(request, reason="")

reason は、リクエストが拒否された理由を表す短いメッセージです。 (開発者や ログをとるのためのもので、一般のユーザーのためのものではありません)

databrowse

revision-up-to:11321 (1.1)

databrouse はデータを閲覧するためのインタフェースを簡単に作成するための Django アプリケーションです。

Django の Admin サイトはモデルに対するイントロスペクションによって、動的に 管理サイトを構築しています。 databrowse も同様に、モデル定義からリッチなブ ラウジングウェブサイトを生成します。

Note

databrowse は 非常に 新しいアプリケーションで、まだ活発な開発下にあ ります。次の Django のリリースまでには相当変更が加えられるでしょう。

そのことさえ念頭におけば、 databrowse 自体はとても簡単に利用でき、コー ドを書く必要もありません。ですから、ごくごくわずかに時間を費してコード を書くだけで試せます。

databrowse の使い方
  1. Django に databrowse のデフォルトのテンプレートを教えます。やり方は いくつかあります:

    • 'django.contrib.databrowse'INSTALLED_APPS に追加し ます。この方法は、 TEMPLATE_LOADERS 設定に app_directories テンプレートローダが入っている場合に使えます (デフォ ルトでは入っています) 。詳しくは テンプレートローダのドキュメント を参照して ください。
    • あるいは、 django/contrib/databrowse/templates ディレクトリへ の完全なパスを調べ、 TEMPLATE_DIRS 設定に追加してください。
  2. databrowse サイトにいくつかモデルを登録します:

    from django.contrib import databrowse
    from myapp.models import SomeModel, SomeOtherModel
    
    databrowse.site.register(SomeModel)
    databrowse.site.register(SomeOtherModel)
    

    モデルの インスタンスではなくクラス を登録してください。

    このコードは、何らかのタイミングで実行される場所であればどこに書いて もかまいません。例えば URLconf (urls.py) に書くのがよいでしょう。

  3. URLconf を変更して、mod:~django.contrib.databrowse モジュールを import します:

    from django.contrib import databrowse
    

    そして、以下の一行を追加します:

    (r'^databrowse/(.*)', databrowse.site.root),
    

    プレフィクスはなんでも構いません – databrowse/ でも db/ でも なんでも好きなプレフィクスを使ってください。

  4. Django サーバを起動して /databrowse/ をブラウザで表示してください。

ユーザにログインを要求する

たった数行追加するだけで、ビューへのアクセスをログインしているユーザに限定 できます。まず、以下の import 行を URLconf に追加します:

from django.contrib.auth.decorators import login_required

次に、 URLconf を変更して、 databrowse.site.root() ビューを django.contrib.auth.decorators.login_required() で修飾 (decorate) し ます:

(r'^databrowse/(.*)', login_required(databrowse.site.root)),

ユーザ認証のドキュメント にあるような、ログインを サポートするための URLconf を設定していないのなら、 以下のようなマッピングも追加しておきます:

(r'^accounts/login/$', 'django.contrib.auth.views.login'),

最後のステップは、 django.contrib.auth.views.login() で必要なログイン フォームの作成です。 ユーザ認証のドキュメント に は、テンプレートの詳細版と簡略版の両方を記載しています。

flatpages アプリケーション

revision-up-to:11321 (1.1) unfinished

Django にはオプションのアプリケーション、 “flatpages” が付属しています。 “flatpages” を使うと、データベースに素 (“flat”) の HTML コンテンツを Django の admin インタフェースや Python API から保存して管理できるようになります。

flatpage オブジェクトは、 URL、タイトル、内容だけからなる単純なオブジェクト です。 flatpage は一回限りしかレンダリングされないような、特殊なケースのペー ジ、例えば “About” や “Privacy Policy” のようなページで、データベースに保 存しておきたいがカスタムのアプリケーションを組むほどではないようなものに使っ て下さい。

flatpage ではカスタムのテンプレートも使えますし、デフォルトのシステム全体で 使われるフラットページテンプレートも使えます。フラットページは単一のサイト にも、複数のサイトにも関連づけできます。

自作のテンプレートにコンテンツを入れる場合、 content フィールドを空 (blank) にしておいてもよくなりました。

Django で構築されたサイトの中にも、 flatpages を使っているものがあります:

インストール

flatpages アプリケーションをインストールするには、以下の手順に従って下さい:

  1. 'django.contrib.sites' がまだ INSTALLED_APPS 設定に追 追加されていなければ追加し、 sites フレームワーク をインストールします。

    Also make sure you’ve correctly set SITE_ID to the ID of the site the settings file represents. This will usually be 1 (i.e. SITE_ID = 1, but if you’re not using the sites framework to manage multiple sites, it could be the ID of a different site.

  2. 'django.contrib.flatpages'INSTALLED_APPS に加え ます。

  3. 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'MIDDLEWARE_CLASSES に加えます。

  4. python manage.py syncdb を実行します。

flatpages の仕組み

manage.py syncdb を実行すると、データベースには django_flatpagesdjango_flatpages_sites という二つのテーブルが作成されます。 django_flatpages は、 URL をタイトルとテキストコンテンツに関連づける単 純な検索テーブルです。 django_flatpages_sites は flatpage をサイトに関 連づけます。

全てのからくりは FlatpageFallbackMiddleware の中にあります。 Django アプリケーションのいずれかが 404 エラーを送出すると、 このミドルウェアが最後の試みとして、該当する URL がないかデータベースをチェッ クします。もっと詳しく言えば、ミドルウェアは、該当 URL に対応し、かつ サイト ID が SITE_ID に対応しているような flatpage がないか調べます。

一致するオブジェクトが見つかると、 flatpages ミドルウェアは以下のアルゴリズ ムに従って応答します:

  • flatpage にカスタムのテンプレートがある場合、テンプレートを読み込みま す。それ以外の場合には、flatpages/default.html という名のテン プレートを読み込みます。
  • flatpage はテンプレートに唯一のコンテキスト変数、 flatpage を渡します。この変数は、flatpage オブジェクトです。 テンプレートのレンダリングには RequestContext を使います。

条件に一致するオブジェクトがなければ、リクエストは通常通りに処理されます。

ミドルウェアが有効になるのは 404 レスポンスの場合だけです。 500 など、他の HTTP 状態コードでは有効になりません。

MIDDLEWARE_CLASSES の順番には注意が必要です。通常、このミドルウェ アはリクエストを処理する最後の段階なので、 FlatpageFallbackMiddleware はリストの末尾において下さい。

ミドルウェアの詳細は ミドルウェアのドキュメント を参照してくださ い。

404 テンプレートがあるか確かめましょう

Django が FlatpageFallbackMiddleware ビューを踏むのは、別のビューが 404 応答を生成したときだけだということに 注意しましょう。他のビューやミドルウェアで 404 を生成させようとして、実 際には別の例外を送出してしまった場合 (例えば、 404 例外に対応する適切な テンプレートを用意していなかった場合は、 TemplateDoesNotExist が 送出されます) には、応答は HTTP 500 (“Internal Server Error”) であり、 FlatpageFallbackMiddleware はフラットページを提供しようとしません

flatpage の追加、変更、削除
admin インタフェースからの操作

Django 自動管理インタフェースを有効にしていれば、 “Flatpages” セクションが admin インデクスページに表示されます。他のオブジェクトと同じように flatpages を編集してください。

Python API からの操作
class models.FlatPage

flatpage は標準の Django モデル で表現されて おり、コードは django/contrib/flatpages/models.py にあります。 flatpage オブジェクトには Django データベース API を介してアクセスできます。

flatpage のテンプレート

デフォルトでは、 flatpages は flatpages/default.html テンプレート を使ってレンダリングされますが、このテンプレートはオーバライドできます。

オーバライドを行うには、 flatpages/default.html テンプレートを自分 で作成する必要があります。 flatpages ディレクトリを作成し、その下に default.html という名のテンプレートファイルを置いて下さい。

flatpage テンプレートに渡されるコンテキスト変数は flatpage の一つだ けです。この変数は flatpage オブジェクトを表します。

簡単な flatpages/default.html テンプレートの例を示しましょう:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
    "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>

flatpage の管理ページでは、生の HTML を入力しています。従って、 flatpage.titleflatpage.content は、テンプレート上で 自動 HTML エスケープ が必要なコンテンツとして 扱われません

django.contrib.formtools

revision-up-to:11321 (1.1)

Django のフォーム (django.forms) を扱うための高水準の抽象 API です。

フォームプレビュー
revision-up-to:11321 (1.1)

Django には、フォームプレビュー (form preview) アプリケーションが付属してい ます。フォームプレビューは「HTMLフォームを表示し、プレビューを行わせ、フォー ム提出時に何らかの処理を行う」というワークフローを自動化する上で役立ちます:

ちょっとした Python クラスを書くだけで、プレビューつきのフォームアプリケー ションを作成できます。

概要

フォームプレビューフレームワークは、 django.forms.Form のサブクラ スを定義するだけで、以下のワークフローを管理できるようにします:

  1. フォームを HTML 形式で Web ページ上に表示します。
  2. フォームデータが POST で提出されると、データを検証します。 a. データの検証に成功したら、プレビューページを表示します。 b. 検証に失敗したら、エラーメッセージつきでフォームを再表示します。
  3. プレビューページで「承認 (confirm)」フォームを提出すると、予め定義 しておいたフックメソッド、 done() を呼出します。 このフックメソッドには検証済みのデータが渡されます。

フォームプレビューフレームワークは、隠しフィールドを使って、プレビューペー ジに共有鍵のハッシュ値を渡します。プレビューページのフォームパラメタを変更 してフォームを提出しようとすると、ハッシュ比較テストに失敗します。

FormPreview の使い方
  1. Django にデフォルトのフォームプレビューテンプレートの場所を設定します:

    • INSTALLED_APPS 設定に 'django.contrib.formtools' を 追加します。 TEMPLATE_LOADERS 設定に app_directories テンプレートローダを指定 (デフォルトで指定され ています) しておく必要もあります。 テンプレートローダのドキュメント も参照 してください。
    • app_directories を使わない場合、 TEMPLATE_DIRS 設定 に django/contrib/formtools/templates の絶対パスを追加して ください。
  2. FormPreview のサブクラスを作成し、 done() メソッドをオーバ ライドします:

    from django.contrib.formtools.preview import FormPreview
    from myapp.models import SomeModel
    
    class SomeModelFormPreview(FormPreview):
    
        def done(self, request, cleaned_data):
            # cleaned_data を使って何らかの処理を行い、
            # "success" ページにリダイレクトする
            return HttpResponseRedirect('/form/success')
    

    このメソッドは HttpRequest オブジェクトと、バ リデーション・クリーニング済みのフォームデータの入った辞書を引数にと ります。メソッドはプレビュー内容を承認した後に遷移する先のページにリ ダイレクトする HttpResponseRedirect を返さねば なりません。

  3. URLconf を変更して、 FormPreview サブクラスを import します:

    from myapp.preview import SomeModelFormPreview
    from myapp.forms import SomeModelForm
    from django import forms
    

    そして、 URLconf に以下の行を追加します。モデルからフォームを生成す るなら、以下のようにするとよいでしょう:

    (r'^post/$', SomeModelFormPreview(SomeModelForm)),
    

    SomeModelForm はモデルのフォームまたはモデルフォームクラスです。

  4. Django のサーバを実行して、ブラウザで /post/ にアクセスします。

FormPreview クラス
class FormPreview

FormPreview クラスは、プレビューのワーク フローを表現する単純な Pythonのクラスです。 フォームプレビュークラスを作成 するときには、django.contrib.formtools.preview.FormPreview のサブ クラスを作成して、 done() メソッ ドをオーバライドします。フォームプレビュークラスは、コードベースのどこに置 いても構いません。

FormPreview のテンプレート

デフォルトでは、フォームは formtools/form.html を使ってレンダされま す。また、プレビューページのレンダには formtools/preview.html を使 います。これらのテンプレートは、 FormPreview のサブクラスで、それぞれ preview_template および form_template 属性を設定すれ ばオーバライドできます。デフォルトのテンプレートの内容は “file”django/contrib/formtools/templates を参照してください。

フォームウィザード (Form wizard)
revision-up-to:11321 (1.1)

Django には、 フォーム を複数のページに分割する 「フォームウィザード」アプリケーションがオプションで付いています。フォーム ウィザードは、フォームの状態を HTML の <input type="hidden"> フィー ルドにハッシュ化して保存し、最終的にフォームを提出するまで、サーバでフォー ムデータを処理させません。

フォームウィザードは、とても長いフォームを扱う必要があって、フォームを一つ のページに納めると不格好になってしまうような場合に使うとよいでしょう。 例えば、最初のページではユーザに重要な情報を尋ね、次のページでは比較的些細 な情報を訪ねるといったフォームで、フォームウィザードを使います。

「ウィザード (wizard)」という用語の意味は、 Wikipedia で解説されています

フォームウィザードの仕組み

ユーザがウィザードを使うときの基本的なワークフローは、以下の通りです:

  1. ユーザはウィザードの最初のページを訪問し、フォームを入力して内容を提 出 (submit) します。
  2. サーバは提出されたデータを検証します。データが有効でなければ、エラー メッセージつきでフォームを再表示します。データが有効なら、データのセ キュアなハッシュを計算して、ユーザに次のフォームを表示し、検証済みの データとハッシュを <input type="hidden"> フィールドに保存し ます。
  3. 以降のウィザード上の全フォームでステップ 1 と 2 を繰り返します。
  4. ユーザが全てのフォームを提出し、提出されたデータが全て有効であった場 合、ウィザードはデータを処理します。すなわち、データベースへの保存や 電子メールの送信といった、アプリケーションで必要な処理を実施します。
使い方

このアプリケーションは、可能な限り処理を自動化しています。基本的には、開発 者側で行う必要があるのは以下の 4 つの作業だけです:

  1. django.forms のフォームクラスをウィザードの各ページごとに作成 します。
  2. FormWizard クラスを作成し て、全てのフォームが提出され、フォームデータが有効だった場合の処理を 記述します。同時に、ウィザードの挙動もいくつかオーバライドできます。
  3. フォームをレンダリングするためのテンプレートを作成します。全部のフォー ムの表示に使うテンプレートを一つだけ作成してもよいですし、各フォーム に対して固有のテンプレートを定義してもかまいません。
  4. URLconf が FormWizard クラ スを指すように設定します。
フォームクラスを定義する

フォームウィザード作成の最初のステップは、フォームクラスの作成です。 フォームの作成には django.formsForm クラスを使わねばなりません。 Form クラスの開設 は forms のドキュメント を参照してください。

フォームクラスはコードベースのどこに置いてもかまいませんが、慣習的にはアプ リケーションフォルダの forms.py に置くことになっています。

例として、「コンタクトフォーム」のウィザードを作成してみましょう。このウィ ザードは、最初のページで送り手の e-mail アドレスとタイトルを入力させ、次の ページでメッセージ本体を入力させます。 forms.py は以下のようになる でしょう:

from django import forms

class ContactForm1(forms.Form):
    subject = forms.CharField(max_length=100)
    sender = forms.EmailField()

class ContactForm2(forms.Form):
    message = forms.CharField(widget=forms.Textarea)

ウィザードは、ページ間のデータの受け渡しに HTML の隠しフィールドを使うため、 最後のページに表示するフォーム以外では FileField を使えません。

フォームウィザードクラスを作成する

次のステップはフォームウィザードクラスの作成です。 フォームウィザードクラス は、 django.contrib.formtools.wizard.FormWizard のサブクラスにせね ばなりません。

フォームクラスと同様、フォームウィザードクラスはコードベースのどこに配置し てもかまいませんが、慣習的には forms.py の中に書きます。

サブクラスの定義で唯一必ず行わなければならないのは done() メソッドの実装で す。 done() メソッドは、 全ての フォームが提出され、フォームデータが有効であった場合に何をするかを 決めるメソッドです。このメソッドには二つの引数が渡されます:

  • requestHttpRequest オブジェクトです。
  • form_listdjango.forms のフォームクラスからなるリストで す。

以下の簡単な例では、データベースの操作を行わずに、単に検証済みのデータをテ ンプレートに表示しています:

from django.shortcuts import render_to_response
from django.contrib.formtools.wizard import FormWizard

class ContactWizard(FormWizard):
    def done(self, request, form_list):
        return render_to_response('done.html', {
            'form_data': [form.cleaned_data for form in form_list],
        })

このメソッドは POST で送信されるので、よき Web 市民たるべく、データの処 理後にはリダイレクトすべきでしょう。というわけで、もう一つの例を示します:

from django.http import HttpResponseRedirect
from django.contrib.formtools.wizard import FormWizard

class ContactWizard(FormWizard):
    def done(self, request, form_list):
        do_something_with_the_form_data(form_list)
        return HttpResponseRedirect('/page-to-redirect-to-when-done/')

フォームウィザードの提供しているフックを詳しく知りたければ、後の フォームウィザードの特殊なメソッド を参照してください。

フォームのテンプレートを作成する

次に、ウィザードのフォームをレンダリングするためのテンプレートを作成する必 要があります。デフォルトでは、全てのフォームは forms/wizard.html と いう名前のテンプレートを使います。 (このテンプレート名は、後で説明する get_template() をオーバライドして 変更できます。このフックを使えば、各フォームで別々のテンプレートを使えます。)

テンプレートには、以下のコンテキストが渡されます:

  • step_field – ウィザードのステップ情報を格納している隠しフィール ドの名前です。
  • step0 – 現在のステップ (ゼロから始まる数です)。
  • step – 現在のステップ (1 から始まる数です)。
  • step_count – 全ステップ数です。
  • form – 現在のステップのフォームインスタンスです (空の場合と、エ ラーつきの場合がありえます)。
  • previous_fields – 現在のステップよりも前のデータフィールドと、検 証済みフォームのハッシュ値の入ったフィールドを表現する文字列です。こ れらのフィールドは全て隠しフィールドです。フィールドの内容は生の HTML なので、内容を処理するには safe() テンプレートフィルタを使っ て自動エスケープを抑制する必要があります。

辞書オブジェクト extra_context にオブジェクトを渡せば、コンテキスト に任意のオブジェクトを追加できます。 extra_context の指定には以下の 二つの方法があります:

  • フォームウィザードのサブクラスの extra_context 属 性に辞書を指定します。
  • URLconf に追加のパラメタとして extra_context を 渡します。

テンプレート例の全体像は以下のようになります:

{% extends "base.html" %}

{% block content %}
<p>Step {{ step }} of {{ step_count }}</p>
<form action="." method="post">
<table>
{{ form }}
</table>
<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
{{ previous_fields|safe }}
<input type="submit">
</form>
{% endblock %}

ウィザードを正しく動作させるには、 previous_fields, step_field およ び step0 を全て表示せねばなりません。

ウィザードを URLconf に組み込む

最後に、 urls.py にフォームウィザードオブジェクトを追加します。 ウィザードはフォームオブジェクトを引数に取ります:

from django.conf.urls.defaults import *
from mysite.testapp.forms import ContactForm1, ContactForm2, ContactWizard

urlpatterns = patterns('',
    (r'^contact/$', ContactWizard([ContactForm1, ContactForm2])),
)
フォームウィザードの特殊なメソッド
class FormWizard

done() メソッドの他 にも、フォームウィザードは特殊なメソッドをいくつか提供しており、ウィザー ドの動作をカスタマイズできます。

こうしたメソッドには step という引数をとるものがあります。 step はゼロから始まるカウンタで、ウィザードの現在のステップを表しています。 (例えば、最初のフォームは 0 で、2 番目のフォームは 1 です。)

FormWizard.prefix_for_step()

ステップを指定すると、フォームのプレフィクス文字列を返します。 デフォルトでは、単にステップ番号そのものを使います。詳しくは フォームプレフィクスのドキュメント <form-prefix> を参照してください。

デフォルトの実装は以下の通りです:

def prefix_for_step(self, step):
    return str(step)
FormWizard.render_hash_failure()

ハッシュチェックに失敗した際にテンプレートをレンダするためのメソッドで す。このメソッドをオーバライドする必要はほとんどありません。

デフォルトの実装は以下の通りです:

def render_hash_failure(self, request, step):
    return self.render(self.get_form(step), request, step,
        context={'wizard_error': 'We apologize, but your form has expired. Please continue filling out the form from this page.'})
FormWizard.security_hash()

受け取ったリクエストオブジェクトとフォームインスタンスに対するセキュリ ティハッシュを計算します。

デフォルトでは、フォームデータの MD5 ハッシュと SECRET_KEY を使います。このメソッドをオーバライドする必要はほとんどありません。

実装例を示します:

def security_hash(self, request, form):
    return my_hash_function(request, form)
FormWizard.parse_params()

リクエストオブジェクトと、 URLconf を使って URL からキャプチャした args / kwargs を元に、ウィザードの状態を保存するためのフックで す。

デフォルトでは何もしません。

実装例を示します:

def parse_params(self, request, *args, **kwargs):
    self.my_state = args[0]
FormWizard.get_template()

指定されたステップのページ表示に使うテンプレート名を返します。

デフォルトでは、ステップに関係なく 'forms/wizard.html' を返します。

実装例を示します:

def get_template(self, step):
    return 'myapp/wizard_%s.html' % step

get_template() が文字列のリストを返す場合、ウィザード はテンプレートシステムの select_template() 関数を使います。つま り、リスト中から最初に見つかったテンプレートを使います。 select_template() については テンプレートのドキュメントで解説しています 。例えば:

def get_template(self, step):
    return ['myapp/wizard_%s.html' % step, 'myapp/wizard.html']
FormWizard.render_template()

指定したステップのテンプレートをレンダし、 HttpResponseRedirect オブジェクトを返します。

カスタムのコンテキストを追加したり、 MIME タイプを変更したりしたければ、 このメソッドをオーバライドしてください。テンプレート名をオーバライドし たいだけなら、 get_template() を使ってください。

テンプレートは「フォームのテンプレートを作成する」で解説したコンテキス トを使ってレンダされます。

FormWizard.process_step()

ウィザードの内部状態を変更するためのフックです。このフックには検証済み のフォームオブジェクトが渡されます。フォームには、必ずクリーニング済み で有効なデータが入っています。

このメソッドでフォームデータの内容を変更しては なりません 。内容に変 更を加えたければ、 self.extra_context を設定するか、 self.form_list に入っている提出済みフォームを入れ替えてください。

このメソッドは、フォームを提出する 全ての ステップでページのレンダリ ング時に呼び出されるので注意してください。

関数シグネチャを以下に示します:

def process_step(self, request, form, step):
    # ...

django.contrib.humanize

revision-up-to:11321 (1.1)

humanize は、データを「人にやさしく (human touched) 」表示するための Django テンプレートフィルタです。

これらのフィルタを有効にするには、 INSTALLED_APPS 設定に 'django.contrib.humanize' を加えます。インストール後、テンプレート上で {% load humanize %} を呼び出せば、以下のフィルタを利用できるようになり ます:

apnumber

1-9 の数字に対して、数をアルファベットで表します。それ以外の数はそのまま数 字で返します。これは Associated Press の書式に従っています。

例:

  • 1'one' になります
  • 2'two' になります。
  • 1010 になります。

渡す値は整数でも、整数を文字列で表したものでもかまいません。

intcomma

整数を三桁ごとにカンマで区切った形式の文字列に変換します。

例:

  • 4500'4,500' になります。
  • 45000'45,000' になります。
  • 450000'450,000' になります。
  • 4500000'4,500,000' になります。

渡す値は整数でも、整数を文字列で表したものでもかまいません。

intword

大きな整数を読みやすいテキスト表現に変換します。100 万を超えるような値を扱 う場合に便利です。

例:

  • 1000000'1.0 million' になります。
  • 1200000'1.2 million' になります。
  • 1200000000'1.2 billion' になります。

1000000000000000 (1 quadrillion) までサポートしています。

渡す値は整数でも、整数を文字列で表したものでもかまいません。

ordinal

整数を序数形式の文字列に変換します。

例:

  • 1'1st' になります。
  • 2'2nd' になります。
  • 3'3rd' になります。

渡す値は整数でも、整数を文字列で表したものでもかまいません。

naturalday

日付が今日、明日、昨日のいずれかに該当する場合、それぞれ「今日 (“today”)」、 「明日 (“tomorrow”) 」、「昨日 (“yesterday”)」を返します。それ以外の日付の 場合は、引数に渡したフォーマット文字列を使って日付をレンダします。

引数: now タグと同じ日付フォーマット形式です。

今日が 2007 年 2 月 17 日とすると、以下のように日付を表示します:

  • 16 Feb 2007昨日 に変わります。
  • 17 Feb 2007今日 に変わります。
  • 18 Feb 2007明日 に変わります。
  • 引数を与えない場合、今日、昨日、明日以外の日付は DATE_FORMAT 設定に従ってフォーマットされます。

localflavor アドオン

revision-up-to:11321 (1.1)

Python の「バッテリ入り (batteries included)」哲学に従って、 Django には様々 な国や文化のための有用なコードが付属しています。こうしたコードは 「localflavor アドオン」と呼ばれ、 django.contrib.localflavor パッケー ジに収められています。

localflavor パッケージは、各国、各文化圏のコードを、 それぞれ ISO 3166 国別コード に従って名付けたサブパッケージにまとめてい ます。

localflavor アドオンの大部分は、 forms フレームワークから導出された、ローカライ ズされたフォームコンポーネントで占められています。例えば、 USStateField にはアメリカの州 名略号を検証する方法が組み込まれていますし、 FISocialSecurityNumber は、フィ ンランドの社会保障番号の検証方法が組み込まれています。

ローカライズコンポーネントは、サブパッケージを import するだけで使えます。 例えば、フランスの電話番号を入力するためのフィールドを生成したければ、以下 のようにします:

from django import forms
from django.contrib.localflavor.fr.forms import FRPhoneNumberField

class MyForm(forms.Form):
    my_french_phone_no = FRPhoneNumberField()
localflavor のサポートする地域

localflavor がサポートしている国や文化圏は、以下の通 りです:

django.contrib.localfravor パッケージ内には、 generic というサブ パッケージもあります。このパッケージは、複数の国や文化で便利なコードをまと めています。現状では、このモジュールには、アメリカの標準をデフォルトとしな い、 forms に基づいた日付や時刻の入力フィールド が入っています。使い方を以下に示します:

from django import forms
from django.contrib.localflavor import generic

class MyForm(forms.Form):
    my_date_field = generic.forms.DateField()
新たなローカルフレーバを追加する

私達は、これからもローカルフレーバを充実させていきたいと考えています。ロー カルフレーバに取り込みたいコードがあるなら、 チケットを作成 してください。 ローカルフレーバの作成でお願いしたいのは、文字列を Unicode リテラルで表現 (u'mystring') し、ファイルのエンコーディングに頼って指定しないで欲しい ということです。既にあるローカルフレーバのコードが参考になるでしょう。

Argentina: アルゼンチン (ar)
class ar.forms.ARPostalCodeField

入力が正しい旧形式のアルゼンチン郵便番号または CPA であるか検証するフォー ムフィールドです。

class ar.forms.ARDNIField

入力が正しい Documento Nacional de Identidad (DNI) であるか検証するフォー ムフィールドです。

class ar.forms.ARCUITField

入力が正しい Código Único de Identificación Tributaria (CUIT) 番号であ るかか検証するフォームフィールドです。

class ar.forms.ARProvinceSelect

アルゼンチンの州および自治領を選べる Select ウィジェットです。

Australia: オーストラリア (au)
class au.forms.AUPostCodeField

入力が正しいオーストラリアの郵便番号であるか検証するフォームフィールド です。

class au.forms.AUPhoneNumberField

入力がオーストラリアの電話番号であるか検証するフォームフィールドです。 有効な番号は 10 桁の数字からなります。

class au.forms.AUStateSelect

オーストラリアの州や領を選べる Select ウィジェットです。

Austria: オーストリア(at)
class at.forms.ATZipCodeField

入力が正しいオーストリアの ZIP コードであるか検証するフォームフィールド です。

class at.forms.ATStateSelect

選択肢のリストにオーストリアの州が設定された Select ウィジェット です。

class at.forms.ATSocialSecurityNumberField

入力が正しいオーストリアの社会保障番号であるか検証するフォームフィール ドです。

Brazil: ブラジル (br)
class br.forms.BRPhoneNumberField

入力が正しいブラジルの電話番号であるか検証するフォームフィールドです。 正しい形式は XX-XXXX-XXXX です。

class br.forms.BRZipCodeField

入力が正しいブラジルのZIPコードであるか検証するフォームフィールドです。 正しい形式はXXXXX-XXXです。

class br.forms.BRStateSelect

ブラジルの州や領を選べる Select ウィジェットです。

Canada: カナダ (ca)
class ca.forms.CAPhoneNumberField

入力が正しいカナダの電話番号であるか検証するフォームフィールドです。 正しい形式はXXX-XXX-XXXXです。

class ca.forms.CAPostalCodeField

入力が正しいカナダの郵便番号であるか検証するフォームフィールドです。 正しい形式はXXX XXXです。

class ca.forms.CAProvinceField

入力が正しいカナダの州名か、州名略号であるか検証するフォームフィールド です。

class ca.forms.CASocialInsuranceNumberField

入力が正しいカナダ社会保障番号 (SIN) であるか検証するフォームフィールド です。正しい SIN は、XXX-XXX-XXX の形式で、 Luhn mod-10 checksum 検証を通ります。

class ca.forms.CAProvinceSelect

カナダの州や領を選べる Select ウィジェットです。

Chile: チリ (cl)
class cl.forms.CLRutField

入力が正しいチリ国民識別番号 (‘Rol Unico Tributario’ or RUT) であるか検 証するフォームフィールドです。正しい形式は XX.XXX.XXX-X です。

class cl.forms.CLRegionSelect

チリの地域 (Regiones) を選べる Select ウィジェットです。

Czech: チェコ (cz)
class cz.forms.CZPostalCodeField

入力が正しいチェコの郵便番号であるか検証するフォームフィールドです。 正しい形式は XXXXX または XXX XX で、各桁の文字は数字です。

class cz.forms.CZBirthNumberField

入力が正しいチェコの戸籍登録番号 (Czech Birth Number) であるか検証する フォームフィールドです。 正しい形式は XXXXXX/XXXX (スラッシュは省略可) です。

class cz.forms.CZICNumberField

入力が正しい Czech IC 番号か検証するフィールドです。

class cz.forms.CZRegionSelect

チェコの地域を選べる Select ウィジェットです。

Finland: フィンランド (fi)
class fi.forms.FISocialSecurityNumber

入力が正しいフィンランド社会保障番号であるか検証するフォームフィールド です。

class fi.forms.FIZipCodeField

入力が正しいフィンランドのZIPコードであるか検証するフォームフィールドで す。正しいコードは 5 桁の数字からなります。

class fi.forms.FIMunicipalitySelect

フィンランドの市名 (municipality) を選べる Select ウィジェットです。

France: フランス (fr)
class fr.forms.FRPhoneNumberField

入力が正しいフランスの電話番号であるか検証するフォームフィールドです。 正しい形式は、 0X XX XX XX XX, 0X.XX.XX.XX.XX, または 0XXXXXXXXX です。 入力は 0X XX XX XX XX 形式に正規化されます。

class fr.forms.FRZipCodeField

入力が正しいフランスのZIPコードであるか検証するフォームフィールドです。 正しいZIPコードは5桁の数字からなります。

class fr.forms.FRDepartmentSelect

フランスの県名 (department) を選べる Select ウィジェットです。

Germany: ドイツ (de)
class de.forms.DEIdentityCardNumberField

入力が正しいドイツの身分保障番号 (Personalausweis) であるか検証するフォー ムフィールドです。正しい番号は XXXXXXXXXXX-XXXXXXX-XXXXXXX-X で、どの桁 グループもゼロだけで構成されていてはなりません。

class de.forms.DEZipCodeField

入力が正しいドイツのZIPコードであるか検証するフォームフィールドです。正 しいコードは5桁の数字からなります。

class de.forms.DEStateSelect

ドイツの州を選べる Select ウィジェットです。

The Netherlands: オランダ (nl)
class nl.forms.NLPhoneNumberField

入力が正しいオランダの電話番号であるか検証するフォームフィールドです。

class nl.forms.NLSofiNumberField

入力が正しいオランダ社会保障番号 (SoFI/BSN) であるか検証するフォームフィー ルドです。

class nl.forms.NLZipCodeField

入力が正しいオランダのZIPコードであるか検証するフォームフィールドです。

class nl.forms.NLProvinceSelect

オランダの県 (province) を選べる Select ウィジェットです。

Iceland: アイスランド (is_)
class is_.forms.ISIdNumberField

入力が正しいアイスランドの身分証明番号 (kennitala) であるか検証するフォー ムフィールドです。形式は XXXXXX-XXXX です。

class is_.forms.ISPhoneNumberField

入力が正しいアイスランド電話番号 (7 桁の数字で、最初の3桁以後にハイフン やスペースが入っていてもよい) であるか検証するフォームフィールドです。

class is_.forms.ISPostalCodeSelect

アイスランドの郵便番号を選べる Select ウィジェットです。

India: インド (in_)
class in.forms.INStateField

入力が正しいインドの州・領名または略号であるか検証するフォームフィール ドです。入力は車両番号登録に使われる標準の 2 文字略号形式に正規化されま す。

class in.forms.INZipCodeField

入力が正しいインドのZIPコードであるか検証するフォームフィールドです。形 式は XXXXXXX です。

class in.forms.INStateSelect

インドの州や領を選べる Select ウィジェットです。

Italy: イタリア (it)
class it.forms.ITSocialSecurityNumberField

入力が正しいイタリア社会保障番号 (codice fiscale) であるか検証する フォームフィールドです。

class it.forms.ITVatNumberField

入力が正しいイタリアの VAT 番号 (partita IVA) であるか検証するフォーム フィールドです。

class it.forms.ITZipCodeField

入力が正しいイタリアのZIPコードであるか検証するフォームフィールドです。 正しいコードは 5 桁の数字です。

class it.forms.ITProvinceSelect

イタリアの県 (province) を選べる Select ウィジェットです。

class it.forms.ITRegionSelect

イタリアの地域名 (region) を選べる Select ウィジェットです。

Japan: 日本 (jp)
class jp.forms.JPPostalCodeField

入力が正しい日本の郵便番号であるか検証するフォームフィールドです。7 桁 の数字で、ハイフンはあってもなくても構いません。

class jp.forms.JPPrefectureSelect

日本の県を選べる Select ウィジェットです。

Mexico: メキシコ (mx)
class mx.forms.MXStateSelect

メキシコの州を選べる Select ウィジェットです。

Norway: ノルウェー (no)
class no.forms.NOSocialSecurityNumber

入力が正しいノルウェー社会保証番号 (personnummer) であるか検証するフォー ムフィールドです。

class no.forms.NOZipCodeField

入力が正しいノルウェーのZIPコードであるか検証するフォームフィールドです。 正しいコードは 4 桁の数字です。

class no.forms.NOMunicipalitySelect

ノルウェーの市名 (municipality, fylker) を選べる Select ウィジェッ トです。

Peru: ペルー (pe)
class pe.forms.PEDNIField

入力が正しいペルー国民識別番号 (DNI) であるか検証するフォームフィールド です。

class pe.forms.PERUCField

入力が正しい納税登録番号 (Registro Unico de Contribuyentes, RUC) である か検証するフォームフィールドです。正しい RUC 番号は 11 桁の数字形式です。

class pe.forms.PEDepartmentSelect

ペルーの県 (department) を選べる Select ウィジェットです。

Poland: ポーランド (pl)
class pl.forms.PLNationalIdentificationNumberField

入力が正しいポーランド国民識別番号 (PESEL) であるか検証するフォームフィー ルドです。

class pl.forms.PLNationalBusinessRegisterField

入力が正しいポーランド法人登記番号 (REGON) であるか検証するフォームフィー ルドです。REGON は 7 桁または 9 桁の数字で、 http://wipos.p.lodz.pl/zylla/ut/nip-rego.html のチェックサムアルゴリズ ムに従います。

class pl.forms.PLPostalCodeField

入力が正しいポーランドの郵便番号であるか検証するフォームフィールドです。 正しい郵便番号は XX-XXX 形式の数字です。

class pl.forms.PLTaxNumberField

入力が正しいポーランド納税者番号 (NIP) であるか検証するフォームフィール ドです。正しい形式は XXX-XXX-XX-XX または XX-XX-XXX-XXX です。NIP に使 われるチェックサムアルゴリズムは http://wipos.p.lodz.pl/zylla/ut/nip-rego.html で定義されています。

class pl.forms.PLAdministrativeUnitSelect

ポーランドの行政単位 (administrative unit) を選べる Select ウィジェッ トです。

class pl.forms.PLVoivodeshipSelect

ポーランドの郡 (voivodeship, 行政州) を選べる Select ウィジェットで す。

Romania: ルーマニア (ro)
class ro.forms.ROCIFField

入力が正しいルーマニア社会保障番号 (CIF) であるか検証するフォームフィー ルドです。入力の先頭に RO がついていた場合、戻り値からは除去します。

class ro.forms.ROCNPField

入力が正しいルーマニア個人番号 (CNP) であるか検証するフォームフィールド です。

class ro.forms.ROCountyField

入力をルーマニアの地域 (judet) またはその略号として検証するフォームフィー ルドです。このフィールドは、入力値の示す地域名を、標準の車両登録番号で 使われる略号に正規化して返します。このフィールドは、分音符号で書かれた 名前しか解釈できません。正しい値を入力させるのが難しいときは、 ROCountySelect の利用を検討してください。

class ro.forms.ROCountySelect

ルーマニアの地域 (judete) を選べる Select ウイジェットです。

class ro.forms.ROIBANField

入力がルーマニア国際銀行の正しい口座番号であるか検証するフォームフィー ルドです。正しい口座番号の形式は ROXX-XXXX-XXXX-XXXX-XXXX-XXXX で、ハイ フンはあってもなくてもかまいません。

class ro.forms.ROPhoneNumberField

入力が正しいルーマニアの電話番号であるか検証するフォームフィールドです。 このフィールドは、いくつかの特殊な番号を排除します。

class ro.forms.ROPostalCodeField

入力が正しいルーマニアの郵便番号であるか検証するフォームフィールドです。

Slovakia: スロバキア (sk)
class sk.forms.SKPostalCodeField

入力が正しいスロバキアの郵便番号であるか検証するフォームフィールドです。 正しい番号は、 XXXXX または XXX XX の形式をとります。

class sk.forms.SKDistrictSelect

スロバキアの州 (district) を選べる Select ウィジェットです。

class sk.forms.SKRegionSelect

スロバキアの地域 (region) を選べる Select ウィジェットです。

South Africa: 南アフリカ (za)
class za.forms.ZAIDField

入力が正しい南アフリカ身分証明番号であるか検証するフォームフィールドで す。検証では、 Luhn チェックサムと、簡単な (完全に厳密ではない) 誕生日 のチェックを行います。

class za.forms.ZAPostCodeField

入力が正しい南アフリカの郵便番号であるか検証するフォームフィールドです。 正しい郵便番号は 4 桁からなります。

Spain: スペイン (es)
class es.forms.ESIdentityCardNumberField

入力が正しいスペインの NIF/NIE/CIF (納税者識別番号) であるか検証するフォー ムフィールドです。

class es.forms.ESCCCField

入力が正しいスペイン銀行口座番号 (Codigo Cuenta Cliente, CCC) であるか 検証するフォームフィールドです。正しい CCC 番号は、 EEEE-OOOO-CC-AAAAAAAAAA の形式であり、 E, O, C および A はそれぞれ組織、 支店、チェックサムおよび口座番号を示しています。チェックサムの上下の桁 は、それぞれ支店番号および口座番号のチェックサム値です。区切り文字にス ペースを使ってもよく、区切り文字がなくてもかまいません。

class es.forms.ESPhoneNumberField

入力が正しいスペインの電話番号であるか検証するフォームフィールドです。 正しい番号は、 9 桁からなり、先頭の番号は 6, 8, または 9 です。

class es.forms.ESPostalCodeField

入力が正しいスペインの郵便番号であるか検証するフォームフィールドです。 正しい番号は 5 桁の数字からなり、先頭の二桁が州を表す 01 から 52 の間の 値をとります。

class es.forms.ESProvinceSelect

スペインの州名を選べる Select ウィジェットです。

class es.forms.ESRegionSelect

スペインの領名を選べる Select ウィジェットです。

Switzerland: スイス (ch)
class ch.forms.CHIdentityCardNumberField

入力が正しいスイスの身分証明書番号であるか検証するフォームフィールドで す。正しい番号は、 X1234567<0 または 1234567890 の形式であり、正しいチェッ クサム値を持たねばなりません。 http://adi.kousz.ch/artikel/IDCHE.htm を 参照してください。

class ch.forms.CHPhoneNumberField

入力が正しいスイスの電話番号であるか検証するフォームフィールドです。正 しい電話番号の形式とは、 0XX XXX XX XX, 0XX.XXX.XX.XX, および 0XXXXXXXXX です。番号は 0XX XXX XX XX 形式に正規化されます。

class ch.forms.CHZipCodeField

入力が正しいスイスのZIPコードであるかフォームフィールドです。正しいコー ドは 4 桁からなります。

class ch.forms.CHStateSelect

スイスの州名を選べる Select ウィジェットです。

United Kingdom: イギリス (uk)
class uk.forms.UKPostcodeField

入力が正しいイギリスの郵便番号であるか検証するフォームフィールドです。 検証に使われている正規表現は、 http://www.govtalk.gov.uk/gdsc/schemas/bs7666-v2-0.xsd で定義されている British Standard BS7666 address types をもとにしていま す。

class uk.forms.UKCountySelect

イギリスの地域名を選べる Select ウィジェットです。

class uk.forms.UKNationSelect

イギリスの地方名を選べる Select ウィジェットです。

United States of America: アメリカ合衆国 (us)
class us.forms.USPhoneNumberField

入力が正しいアメリカの電話番号であるか検証するフォームフィールドです。

class us.forms.USSocialSecurityNumberField

入力がアメリカの社会保障番号 (SSN) であるか検証するフォームフィールドで す。正しい SSN 番号は、以下の規則に従います:

  • XXX-XX-XXXX 形式であること
  • 0 ばかりでできた桁グループがないこと
  • 先頭の桁グループが 666 でないこと
  • 広報に使われるブロック (987-65-4320 から 987-65-4329) の範囲内で ないこと
  • 広報で使われているために、明らかに無効であると知られている番号 (Woolworth 番号、または 1962 promotional number) でないこと
class us.forms.USStateField

入力がアメリカの州名または州名略号であるか検証するフォームフィールドで す。入力を郵便向けの標準 2 文字州名略号に正規化します。

class us.forms.USZipCodeField

入力が正しいアメリカの郵便番号であるか検証するフォームフィールドです。 XXXXX または XXXXX-XXXX 形式の番号が有効です。

class us.forms.USStateSelect

アメリカの州や領を選べる Select ウィジェットです。

class us.models.PhoneNumberField

入力がアメリカ合州国の電話番号形式 (XXX-XXX-XXXX) に従っているかを チェックする CharField です。

class us.models.USStateField

アメリカ合州国の州名を二文字の略号でデータベースに保存するモデルフィー ルドです。 forms.USStateField モデルフィールドとして表示されます。

メッセージフレームワーク

revision-up-to:17812 (1.4)

Web アプリケーションでは一般的に、フォーム処理などのユーザによる入力の後に、一 度だけのメッセージ表示(フラッシュメッセージとも呼ばれる)を行いたいことが有りま す。

このために、Django はクッキー及びセッションベースのメッセージ処理を、匿名ユーザ と認証済みユーザの両方に対してサポートしています。このメッセージ機能 (messages) は、その後の(通常は次の)リクエストで表示するための、一時的なメッセージの保存と 取得を可能にします。全てのメッセージは特定の メッセージレベル (level) と共 にタグ付けされます(例えば、infowarning または error など)。

メッセージ機能を有効にする

メッセージ機能は ミドルウェア クラスと コンテキ ストプロセッサ を介して実装されています。

django-admin.py startproject によって作られるデフォルトの settings.py には、メッセージ機能を有効にするための以下の全ての設定が既に含まれています。

もし、メッセージ機能を使いたくない場合は、 INSTALLED_APPS から 'django.contrib.messages' を、 MIDDLEWARE_CLASSES から MessageMiddleware の行を、そして TEMPLATE_CONTEXT_PROCESSORS から messages を削除して下さい。

メッセージ処理の設定をする
ストレージバックエンド

このメッセージフレームワークでは、一時的にデータを保存するバックエンドとして、 さまざまなものを使うことができます。

Django は、3 つの組み込みストレージクラスを提供しています。

class django.contrib.messages.storage.session.SessionStorage

このクラスは、リクエストのセッション内に全てのメッセージを保存します。 つまり、Django の contrib.sessions アプリケーションが必要になります。

class django.contrib.messages.storage.cookie.CookieStorage

このクラスは、メッセージデータをクッキー内(secret hash 認証による改ざん対策 がされている)に保存することで、リクエスト間をまたがった通知を行います。古い メッセージは、クッキーのデータサイズが 2048 バイトを超えた際に削除されます。

class django.contrib.messages.storage.fallback.FallbackStorage

このクラスは、最初に CookieStorage を使い、メッセージがひとつのクッキー 内に収まらない場合は SessionStorage を使います。これもまた Django の contrib.sessions アプリケーションを必要とします。

この仕様によって、可能な限りセッションへの記録を行いません。これは一般的な ケースにおいて、最も良いパフォーマンスを提供するでしょう。

FallbackStorage がデフォルト のストレージクラスです。もしこれがあなたの要件に適していないなら、他のストレー ジクラスへのインポートパスを以下の例の様に MESSAGE_STORAGE へ設定し て下さい:

MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'

あなた独自のストレージクラスを書くには、django.contrib.messages.storage.base にある BaseStorage クラスのサブクラスを定義し、_get_store メソ ッドを実装して下さい。

メッセージレベル

メッセージフレームワークは、Python の logging モジュールに似た設定可能なレベル の仕組みを基本としています。メッセージレベル (message levels) は、タイプによっ てグループ化することで、メッセージがフィルタリングされ、各ビューやテンプレート で違う表示になるようにします。

django.contrib.messages から直接読み込まれる組み込みレベルは:

定数名 目的
DEBUG 開発用のメッセージ、本番環境では無視される(または削除される)
INFO ユーザーに対して情報を伝えるためのメッセージ
SUCCESS アクションが成功した、例) “あなたのプロフィールの更新が成功しました”
WARNING 失敗ではないが、その危険性がある
ERROR アクションが成功していないか、何かの失敗がある

MESSAGE_LEVEL の設定は、メッセージを記録するレベルの最小値 (minimum recorded level) を変更するために使われます(また、 `リクエスト別の設定`_ が可能 です)。試しにこれより低いレベルのメッセージを追加してみると、無視されることでし ょう。

メッセージタグ

メッセージタグ (message tags) とは、メッセージレベルを文字列によって表現したも のです。加えて、ビュー内で直接追加される拡張タグがあります(詳細は 拡張メッセージタグを追加する を参照)。複数のタグはひとつの文字列内に格納され 、スペースによって分割されています。一般的に、メッセージタグは、メッセージタイ プによるスタイルのカスタマイズを行う際のCSSクラス名として使われます。デフォルト では、各々のレベルには、定数名を小文字に変換した文字列のタグが付与されています。

レベル定数名 タグ文字列
DEBUG debug
INFO info
SUCCESS success
WARNING warning
ERROR error

メッセージレベルのデフォルトタグ(組み込みとカスタムタグのどちらでも)を変更するに は、 MESSAGE_TAGS へ変更したいレベルを含めた辞書を設定します。 その場合は、上書きしたいレベルだけを指定してタグを設定します。:

from django.contrib.messages import constants as messages
MESSAGE_TAGS = {
    messages.INFO: '',
    50: 'critical',
}
ビューとテンプレート内でメッセージを使う
add_message(request, level, message, extra_tags='', fail_silently=False)
メッセージを追加する

メッセージの追加:

from django.contrib import messages
messages.add_message(request, messages.INFO, 'Hello world.')

いくつかのショートカットメソッドは、一般に使われるタグ(通常はHTMLのクラス名になる )と共にメッセージ追加の標準的な手段を提供します:

messages.debug(request, '%s SQL statements were executed.' % count)
messages.info(request, 'Three credits remain in your account.')
messages.success(request, 'Profile details updated.')
messages.warning(request, 'Your account expires in three days.')
messages.error(request, 'Document deleted.')
メッセージを表示する

テンプレート内で、このような使い方をします:

{% if messages %}
<ul class="messages">
    {% for message in messages %}
    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

もし、あなたがコンテキストプロセッサを使っている場合、あなたのテンプレートは RequestContext を使ってレンダリングされないといけません。そうでないならば、 message をテンプレート内で使えるようにして下さい。

たとえ、メッセージが一つであったとしても、それでも messages をイテレートし なければなりません、なぜなら、そうしなければ、そのメッセージのストレージが次の リクエストまでに削除されないからです。

カスタムメッセージレベルを作成する

メッセージレベルは単なる整数に過ぎません、だから、あなたは独自のレベルの定数を 定義して、よりカスタムされたユーザのフィードバックを生成できます。例えば:

CRITICAL = 50

def my_view(request):
    messages.add_message(request, CRITICAL, 'A serious error occurred.')

カスタムメッセージレベルを作成した時、存在するレベルのオーバーロードをしないよ うに注意しないといけません。以下は組み込みレベルが使用している値です:

レベル定数名
DEBUG 10
INFO 20
SUCCESS 25
WARNING 30
ERROR 40

もしカスタムレベルに対してHTMLやCSS内で使うためのIDが欲しいなら、 MESSAGE_TAGS で設定をする必要があります。

Note

再利用可能なアプリケーションを作る場合は、組み込みのメッセージレベル のみを使い、カスタムレベルに頼らないことが推奨されています。

リクエスト別に記録するレベルの最小値を変更する

記録するレベルの最小値 (minimum recorded level) は、 set_level メソッドを使 うことでリクエスト別に設定をすることが出来ます:

from django.contrib import messages

# Change the messages level to ensure the debug message is added.
messages.set_level(request, messages.DEBUG)
messages.debug(request, 'Test message...')

# In another request, record only messages with a level of WARNING and higher
messages.set_level(request, messages.WARNING)
messages.success(request, 'Your profile was updated.') # ignored
messages.warning(request, 'Your account is about to expire.') # recorded

# Set the messages level back to default.
messages.set_level(request, None)

同様に、現在のレベルを get_level で取得することが出来ます:

from django.contrib import messages
current_level = messages.get_level(request)

記録するレベルの最小値についての情報は、先に メッセージレベル を参照して下さ い。

拡張メッセージタグを追加する

直接メッセージタグの操作をするには、各種追加用のメソッドにて任意で拡張メッセー ジタグ (extra tags) の文字列を設定することができます:

messages.add_message(request, messages.INFO, 'Over 9000!',
                     extra_tags='dragonball')
messages.error(request, 'Email box full', extra_tags='email')

拡張メッセージタグは、そのメッセージレベルのデフォルトタグの前に追加され、スペ ースで分割されます。

メッセージフレームワークが無効でもエラーを発生しない

再利用可能なアプリケーション(またはコード片)を書く際に、あなたにはメッセージ機 能が必要だがアプリケーションのユーザには必要でなかった場合、以下の例のように、 add_message とそれに類するメソッドへ fail_silently=True をキーワード引 数で追加すればエラーの発生を抑止することが出来ます:

messages.add_message(request, messages.SUCCESS, 'Profile details updated.',
                     fail_silently=True)
messages.info(request, 'Hello world.', fail_silently=True)

Note

fail_silently=True の設定は、メッセージフレームワークが無効の状態で add_message などのメソッドを使った時の MessageFailure エラーのみを隠 蔽し、その他のエラーは発生させます。他の原因で発生するエラーを隠蔽しません。

メッセージの有効期限

メッセージのデータは、ストレージのインスタンスをイテレートした時に、削除対象と してマークされます(そして、レスポンスが実行された際に削除されます)。

メッセージが削除されないようにするためには、イテレート後にストレージインスタン スへ False を設定します:

storage = messages.get_messages(request)
for message in storage:
    do_something_with(message)
storage.used = False
並列リクエスト時の挙動

クッキー(とセッション)を使用している対価として、 いかなるバックエンドを使って も、複数のリクエストが並列で実行された時には、それらのクッキーやセッションの動 きは不安定になります。例えば、もしクライアントがあるウィンドウ(またはタブ) でメッセージを生成するリクエストを行って、そして次に別ウィンドウで、その未処理 のメッセージを取得するリクエストを最初のウィンドウがリダイレクトする前に行ったら 、予想されるメッセージの表示場所は、最初のウィンドウではなく二番目のウィンドウ です。

短い間に、複数のリクエストが同じクライアントから送信されると、ほとんどの場合に おいて、メッセージがウィンドウに表示されることも作成されることも保証されません 。また、覚えておくこととして、この点は一般的なアプリケーションでは問題にならず 、そして HTML5 では、ウィンドウ/タブのそれぞれがコンテキストを持つようになるの で、 全く問題にならなくなるでしょう。

設定

少しの設定でメッセージの動きを操作出来ます:

  • MESSAGE_LEVEL
  • MESSAGE_STORAGE
  • MESSAGE_TAGS
  • SESSION_COOKIE_DOMAIN

redirects アプリケーション

revision-up-to:11321 (1.1)

Django にはオプションとして redirects アプリケーションがついてきます。この アプリケーションを使うと、リダイレクト先をデータベースに保存し、適切なリダ イレクト処理をおこなってくれます。

インストール

redirects アプリケーションをインストールするには、以下の 3 ステップの操作を 行います:

  1. INSTALLED_APPS"django.contrib.redirects" を追加し ます。
  2. MIDDLEWARE_CLASSES"django.contrib.redirects.middleware.RedirectFallbackMiddleware" を追加します。
  3. manage.py syncdb を実行します。
動作の仕組み

manage.py syncdb を実行すると、データベースに django_redirects とい う名のテーブルを作成します。このテーブルは site_id, old_path および new_path というフィールドを持った検索テーブルです。

全ての処理は RedirectFallbackMiddleware で行われます。 Django アプリケー ション内で 404 エラーが送出されると、このミドルウェアは最後の手段として redirects データベースにリクエスト URL がないか調べます。特に、 SITE_ID に対応するサイト ID を持った old_path を探します。

  • 一致するエントリが見つかり、かつ new_path が空でなければ new_path にリダイレクトします。
  • 一致するエントリは見つかったが new_path が空の場合には、 410 (“Gone”) HTTP ヘッダと空の (コンテンツのない) 応答を送信します。
  • 一致するエントリがなければ、リクエストを通常通りに処理します。

ミドルウェアが起動されるのは 404 エラーに対してだけで、 500 やその他の状態 コードでは起動されません。

MIDDLEWARE_CLASSES の設定順には注意が必要です。一般に、 RedirectFallbackMiddleware はリクエスト処理の最終手段なので、リストの末 尾に指定します。

ミドルウェアについての詳しい情報は ミドルウェアのドキュメント <topics-http-middleware> を参照してください。

リダイレクトの追加、変更、削除
admin インタフェースから

Django の自動 admin インタフェースを有効にしていれば、 “Redirects” という名 前のセクションが admin のインデクスページに表示されているはずです。Django の他のオブジェクトと同じように編集してください。

Python API から
class models.Redirect

リダイレクトは django/contrib/redirects/models.py で定義されている標 準の Django モデル で表現されています。 Django のデータベース API を使えば、リダイレ クトオブジェクトにアクセスできます。

sitemaps フレームワーク

revision-up-to:11321 (1.1)

Django には、 サイトマップ XML ファイルを簡単に生成できる高水準 のサイトマップ生成フレームワークが付属しています。

概要

サイトマップ (sitemap) とは、自分のサイト上のページの更新頻度や特定のペー ジ間の「重要度」を検索エンジンのインデクサに対して知らせるために、Web サイ ト上に配置する XML ファイルです。この情報があると、検索エンジンがサイトのイ ンデクスを生成するときに役立ちます。

Django のサイトマップフレームワークを使うと、この XML ファイルの情報を Python コードで表現でき、ファイルの生成を自動化できます。

sitemaps は Django の 配信フレームワーク によく似ています。サイトマップの生成は簡単で、ただ Sitemap クラスを書いて、 URLconf に指定するだけです。

インストール

sitemaps アプリケーションは以下の手順でインストールします:

  1. INSTALLED_APPS 設定に 'django.contrib.sitemaps' を加 えます。
  2. TEMPLATE_LOADERS 設定に、 'django.template.loaders.app_directories.load_template_source' が入っているか確かめます。デフォルトの設定ファイルには入っているので、 注意が必要なのは設定を変更している時だけです。
  3. sites フレームワーク をインストールし ておいてください。

(注意: sitemaps アプリケーションは、データベースに何らテーブルをインストール しません。 INSTALLED_APPSsitemaps を入れておかねばならな いのは、 load_template_source() テン プレートローダがデフォルトのテンプレートを捜し出せるようにするためです。)

初期化

自分の Django サイト上でサイトマップ生成を行わせるには、 URLconf に以下の行を追加します:

(r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps})

これで、 Django はクライアントが /sitemap.xml にアクセスしたときに サイトマップを生成するようになります。

サイトマップファイルの名前はさして重要ではありませんが、ファイルの場所は重 要です。検索エンジンは、サイトマップ内のリンクをインデクス化する際、ファイ ルの置かれている URL レベルとその下のリンクしかたどりません。例えば、 sitemap.xml がルートディレクトリ下にあれば、 Google はサイト上の全 ての URL を参照します。一方、サイトマップの場所が /content/sitemap.xml であれば、 /content/ で始まる URL しか 参照しません。

ビュー関数 sitemap() には、必須の引数 {'sitemaps': sitemaps} があり ます。 sitemaps はセクションラベル (例えば blognews) を、 Sitemap クラス (例えば BlogSitemapNewsSitemap) に対応づける辞書にします。あるいは、 Sitemap クラスの インスタンス (例えば BlogSitemap(some_bar)) でもかまいません。

Sitemap クラス

Sitemap クラスとは、サイトマップ上のエン トリの「セクション」を表現するための Python のクラスです。例えば、ある Sitemap クラスはブログ上の全てのエントリ を表し、別のクラスはイベントカレンダー上の全てのイベントを表現する、といっ た具合です。

最も単純化すれば、全てのセクションは sitemap.xml という一つのファイ ルにまとめあげられることになります。とはいえ、 sitemaps フレームワークを使 えば、各セクションごとに個別のサイトマップファイルがあるようなサイトマップ インデクスを生成できます (後述の サイトマップインデクスを生成する を参照 してください)。

Sitemap クラスは django.contrib.sitemaps.Sitemap のサブクラスでなければなりません。クラ スはコードベースのどこに置いてもかまいません。

簡単な例

ブログシステムを使っていて、 Entry というモデルがあるとしましょう。 サイトマップに全てのブログエントリへのリンクを含めたければ、サイトマップク ラスは以下のようになります:

from django.contrib.sitemaps import Sitemap
from mysite.blog.models import Entry

class BlogSitemap(Sitemap):
    changefreq = "never"
    priority = 0.5

    def items(self):
        return Entry.objects.filter(is_draft=False)

    def lastmod(self, obj):
        return obj.pub_date

注意点:

  • changefreqpriority はクラス属性 で、それぞれ <changefreq> および <priority> エレメントに対応 しています。これらの属性は、上の例の lastmod のよう に、メソッドとしても定義できます。
  • items() はオブジェクトのリストを返すだけのメソッドで す。このメソッドの返すオブジェクトは、サイトマップの各プロパティ (location, lastmod, changefreq, priority) に対応するメ ソッドに渡されます。
  • lastmod は Python の datetime オブジェクトを返さ ねばなりません。
  • この例には location メソッドがありませんが、自分でメ ソッドを定義して、オブジェクトの URL を指定してもかまいません。デフォ ルトでは、 location() は各オブジェクトに対して get_absolute_url() を呼び出し、その結果を返します。
Sitemap クラスリファレンス
class Sitemap

Sitemap のサブクラスでは、以下のメソッドや属性を定義できます:

items

必須です。 オブジェクトのリストを返すメソッドです。フレームワー クはオブジェクトの が何であるかを問いません。重要なのは、オブ ジェクトが location(), lastmod(), changefreq(), priority() といった メソッドに渡されるという点だけです。

location

省略可能です。 メソッドまたは属性です。

メソッドとして定義する場合、 items() の返すオブジェ クトを引数にとり、オブジェクトに対する絶対 URLの文字列を計算して返 さねばなりません。

属性として定義する場合、 items() の返す 全てのオブジェクトに共通して 使われる絶対 URL を表す文字列にしま す。

いずれの場合も、「絶対 URL」とは、以下の例のようにプロトコルおよび ドメイン部を含まない URLを指します:

  • 正しい: '/foo/bar/'
  • 誤り: 'example.com/foo/bar/'
  • 誤り: 'http://example.com/foo/bar/'

location を指定していない場合、フレームワークは items() の返す各オブジェクトに対して get_absolute_url() メソッドを呼び出します。

lastmod

省略可能です。 メソッドまたは属性です。

メソッドとして定義する場合、 items() の返すオブジェ クトを引数にとり、オブジェクトの最終更新日時を Python の datetime.datetime オブジェクトで返さねばなりません。

属性として定義する場合、 items() の返す 全てのオブジェクトに共通して 使われるオブジェクトの最終更新日時を Python の datetime.datetime オブジェクトで返さねばなりません。

changefreq

省略可能です。 メソッドまたは属性です。

メソッドとして定義する場合、 items() の返すオブジェ クトを引数にとり、オブジェクトの更新頻度を Python の文字列型で返さ ねばなりません。

属性として定義する場合、 items() の返す 全てのオブジェクトに共通して 使われるオブジェクトの更新頻度を Python の文字列型で返さねばなりません。

メソッド、属性を問わず、 changefreq の値は以下のい ずれかにします:

  • 'always'
  • 'hourly'
  • 'daily'
  • 'weekly'
  • 'monthly'
  • 'yearly'
  • 'never'
priority()

省略可能です。 メソッドまたは属性です。

メソッドとして定義する場合、 items() の返すオブジェ クトを引数にとり、オブジェクトの重要度 (priority) を Python の文字 列型か浮動小数型で返さねばなりません。

属性として定義する場合、 items() の返す 全てのオブジェクトに共通して 使われるオブジェクトの重要度を Python の文字列型か浮動小数型で返さねばなりません。

priority の値は 0.41.0 のようにします。 デフォルトの重要度は 0.5 です。重要度の詳細は sitemaps.org のドキュメント を参照してください。

ショートカット

sitemaps フレームワークでは、よく使われる状況向けに、二つの便宜クラスを用意 しています:

class FlatPageSitemap

django.contrib.sitemaps.FlatPageSitemap クラスは、現在の SITE_ID (sites のドキュメント 参照) 向けの全ての フラットページ を 検索し、サイトマップのエントリを生成します。各エントリには location 属性だけが設定され、 lastmod, changefreq, priority は設定されません。

class GenericSitemap

django.contrib.sitemaps.GenericSitemap クラスは任意の 汎用ビュー <ref-generic-views> と組み合わせて使えます。 GenericSitemap を使うには、汎用ビュー に渡すのと同じ info_dictGenericSitemap に渡してインスタンスを 生成します。 info_dict には少なくとも queryset がなけれ ばなりません。また、 info_dictqueryset で取り出され るオブジェクトの日時のフィールドを指定する date_field エントリ がある場合、サイトマップ生成時にエントリの lastmod 属 性に使われます。 GenericSitemap のコ ンストラクタには、 prioritychangefreq といったキーワード引数も指定できます。 これらの引数の値は、全ての URL に共通の属性になります。

FlatpageSitemapGenericSitemap の両方を組み込んだ URLconf の例は以下のようになります:

from django.conf.urls.defaults import *
from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap
from mysite.blog.models import Entry

info_dict = {
    'queryset': Entry.objects.all(),
    'date_field': 'pub_date',
}

sitemaps = {
    'flatpages': FlatPageSitemap,
    'blog': GenericSitemap(info_dict, priority=0.6),
}

urlpatterns = patterns('',
    # info_dict を使った汎用ビューの設定
    # ...

    # サイトマップ
    (r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap',
        {'sitemaps': sitemaps})
)
サイトマップインデクスを生成する

sitemap フレームワークには、個々のサイトマップファイルを参照するサイトマッ プインデクスを生成する機能もあります。サイトマップインデクスからサイトマッ プファイルへの参照は、 sitemaps 辞書に定義されている各セクションご とにひとつづつ作成されます。サイトマップインデクスを使うには、少しだけやり 方を変えます:

  • URLconf に、 django.contrib.sitemaps.views.index()django.contrib.sitemaps.views.sitemap() という二つのビューを使 います。
  • django.contrib.sitemaps.views.sitemap() にキーワード引数 section を指定します。

上の例にならうと、URLconf は以下のようになります:

(r'^sitemap.xml$', 'django.contrib.sitemaps.views.index', {'sitemaps': sitemaps}),
(r'^sitemap-(?P<section>.+)\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),

この設定では、 sitemap-flatpages.xmlsitemap-blog.xml へ の参照が入った sitemap.xml が自動生成されます。 Sitemap クラスと sitemaps 辞書に 手を加える必要はありません。

50,000 以上の URL を含むサイトマップの場合、インデクスファイルを生成せねば なりませんが、 Django は自動的にサイトマップをページ分割し、インデクスにそ の内容を反映します。

Google に ping を打つ

サイトマップの変更時に、Google に「ping を打」って、サイトのインデクスを再 構築させたい場合もあるでしょう。 sitemap フレームワークで ping を打つには、 django.contrib.sitemaps.ping_google()`() を呼び出します。

ping_google()

ping_google() にはオプションの引数 sitemap_url がありま す。この引数にはサイトのサイトマップの絶対 URL (例えば '/sitemap.xml')を指定します。 sitemap_url を指定しなかっ た場合、 ping_google() は URLconf の逆引きを行って、サイトマップ の在処を探します。

サイトマップの URL を捜し出せなかった場合、 ping_google()django.contrib.sitemaps.SitemapNotFound 例外を送出します。

Google に登録しておきましょう!

ping_google() が動作するのはは、 Google Webmaster Tools でサイ トを登録してある場合だけです。

ping_google() の用法として有用なのは、モデルの save() メソッド で呼び出すというものです:

from django.contrib.sitemaps import ping_google

 class Entry(models.Model):
     # ...
     def save(self, force_insert=False, force_update=False):
         super(Entry, self).save(force_insert, force_update)
         try:
             ping_google()
         except Exception:
             # Bare 'except' because we could get a variety
             # of HTTP-related exceptions.
             pass

とはいえ、 ping_google() は Google のサーバに HTTP リクエストを送信 するので、 save() のたびにネットワークアクセスのオーバヘッドが生じます。 もっと効率的にやりたければ、 cron 化されたスクリプトなど、一定の時点で実行 するようスケジュールしたタスクの中で ping_google() を呼び出すとよい でしょう。

manage.py で Google に Ping を送信する

サイトマップアプリケーションをプロジェクトに追加したら、 manage.py コマ ンドラインインタフェースを使って、以下のように Google サーバに ping を送信 できます:

python manage.py ping_google [/sitemap.xml]

“sites” フレームワーク

revision-up-to:11321 (1.1)

Django にはオプションとして使える “sites” フレームワークが付属しています。 “sites” はオブジェクトや機能を特定の Web サイトに関連付けるためのフックであ ると同時に、 Django で作成したサイトのドメイン名と「分かりやすい名前 verbose name」を保存しています。

一つの Django で複数のサイトを管理していて、サイト間に違いを持たせたい場合 に使ってください。

sites フレームワークは、簡単なモデルだけでできています:

class django.contrib.sites.models.Site

モデルには、 domainname という二つのフィールドがあり ます。あるサイトの設定ファイルの SITE_ID 設定は、そのサイトを表 す Site オブジェクトのデータベース上 での ID を指定します。

site の使い道は自由ですが、 Django では簡単な呼び出し規約で自動的に sites を使える方法を 2 種類提供しています。

使用例

どういう状況で sites を使うのでしょうか?例を挙げて説明しましょう。

コンテンツを複数のサイトに関連づける

LJWorld.comLawrence.com は同じニュース組織、Kansaz 州 Lawrence にある Lawrence Journal-World newspaper が管理しています。 LJWorld.com はニュース に、 Lawrence.com は地域の娯楽情報にフォーカスしていますが、編集者は 両方の サイトで同じニュースを公開したいと考える場合もあります。

この問題を何も考えずに扱うなら、サイト構築担当者に対して、 LJWorld.com と Lawrence.com に同じ記事を出すよう 2 度依頼することになります。しかしこれは サイト構築担当にとって非効率的ですし、同じ記事のコピーが複数データベースに 入ることになってしまいます。

もっとましで簡単な方法ががあります: どちらのサイトも同じデータベースを使い、 1 つの記事を複数のサイトに関連づけるというものです。この関係は、 Django モ デルの用語で言えば Article モデルの ManyToManyField で表現されます:

from django.db import models
from django.contrib.sites.models import Site

class Article(models.Model):
    headline = models.CharField(max_length=200)
    # ...
    sites = models.ManyToManyField(Site)

このモデルは、以下のようにいくつかの点で優れています:

  • site 構築担当が 1 つのインタフェース (Django admin サイト) で両方のサ イトにある全てのコンテンツを編集できます。

  • 同じ記事をデータベース上に何度も書き込まなくて済み、一つのレコードと して保存できます。

  • サイト開発者は同じビューコードを両方のサイトで使えます。ビューコード では、リクエストされている記事が現在のサイト用のものかチェックします。 例えば以下のようなコードになるでしょう:

    from django.conf import settings
    
    def article_detail(request, article_id):
        try:
            a = Article.objects.get(id=article_id, sites__id__exact=settings.SITE_ID)
        except Article.DoesNotExist:
            raise Http404
        # ...
    
コンテンツを単一のサイトに関連づける

あるモデルを ForeignKey を使って 他対一の関係で Site に関連づけても構 いません。

例えば、ある記事をあるサイトだけで表示できるようにしたければ、モデルは以下 のように書きます:

from django.db import models
from django.contrib.sites.models import Site

class Article(models.Model):
    headline = models.CharField(max_length=200)
    # ...
    site = models.ForeignKey(Site)

この方法でも、前節で述べたのと同じような恩恵を得られます。

ビュー内で現在のサイトをフックに使う

低水準では、 Django ビューの中で sites フレームワークを使って、ビューを呼び 出しているサイトごとに固有の処理を実行できます。

例えば:

from django.conf import settings

def my_view(request):
    if settings.SITE_ID == 3:
        # Do something.
    else:
        # Do something else.

もちろん、上のようにサイト ID をハードコードするのは見栄えよくありません。 この種のハードコード化は、すぐに実行しなければならないハックのときにはベス トでしょう。同じことをよりクリーンに実現するには、サイトのドメイン名をチェッ クします:

from django.conf import settings
from django.contrib.sites.models import Site

def my_view(request):
    current_site = Site.objects.get(id=settings.SITE_ID)
    if current_site.domain == 'foo.com':
        # Do something
    else:
        # Do something else.

settings.SITE_ID の値から Site オブジェクトを取得するというイディ オムはよく使われるので、 Site のモデ ルマネジャには get_current() メソッドがあります。以下の例は上の例と同じ です:

from django.contrib.sites.models import Site

def my_view(request):
    current_site = Site.objects.get_current()
    if current_site.domain == 'foo.com':
        # Do something
    else:
        # Do something else.
現在のドメインを取得して表示する

LJWorld.com と Lawrence.com には e-mail による通知機能があり、読者が登録し ておくとニュースが届いたときに通知メールを受け取れるようになっています。こ のからくりは簡単で、 Web フォームから登録すると、「ご登録ありがとうございま した」という内容のメールを受け取ります。

登録処理を行うコードを二度開発するのは非効率的で冗長なので、舞台裏では複数 サイトで同じコードを使うようにします。ただし、「ご登録ありがとうございます」 通知はサイトごとに変えなければなりません。 Site オブジェクトを使えば、現在のサイ トの namedomain の値を使って「ありがとうございます」メッセージ を抽象化できます。

フォーム処理ビューの例は以下の通りです:

from django.contrib.sites.models import Site
from django.core.mail import send_mail

def register_for_newsletter(request):
    # フォームの値チェックなどを行い、ユーザを登録する
    # ...

    current_site = Site.objects.get_current()
    send_mail('Thanks for subscribing to %s alerts' % current_site.name,
        'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % current_site.name,
        'editor@%s' % current_site.domain,
        [user.email])

    # ...

Lawrence.com では、 e-mail の件名は “Thanks for subscribing to lawrence.com alerts.” です。 LJWorld.com では、件名は “Thanks for subscribing to LJWorld.com alerts.” で、メール本体も同様です。

より柔軟 (で、重たい) 方法として、 Django テンプレートシステムを使った方法 と比較してみましょう。 Lawrence.com と LJWorld.com は別々のテンプレートディ レクトリ (TEMPLATE_DIRS) を持っているので、以下のようにすればサ イト間の違いをテンプレートシステムに追い出せます:

from django.core.mail import send_mail
from django.template import loader, Context

def register_for_newsletter(request):
    # フォームの値チェックなどを行い、ユーザを登録する
    # ...

    subject = loader.get_template('alerts/subject.txt').render(Context({}))
    message = loader.get_template('alerts/message.txt').render(Context({}))
    send_mail(subject, message, 'editor@ljworld.com', [user.email])

    # ...

この場合、 LJWorld.com と Lawrence.com のテンプレートディレクトリ下に subject.txtmessage.txt の二つのテンプレートを作成します。 ただし、こうすればより柔軟にはなりますが、複雑さは増します。

不要な複雑さと冗長性を排除するためには、 Site オブジェクトを可能な限り使うとよ いでしょう。

現在のドメインの完全な URL を取得する

Django の get_absolute_url() は、オブジェクトの URL をドメイン名なしで 取得する際には便利ですが、場合によっては、完全な URL、すなわち http:// とドメイン名、その他全てを表示したいこともあるでしょう。これには sites フレー ムワークを使います。簡単な例を示します:

>>> from django.contrib.sites.models import Site
>>> obj = MyModel.objects.get(id=3)
>>> obj.get_absolute_url()
'/mymodel/objects/3/'
>>> Site.objects.get_current().domain
'example.com'
>>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
'http://example.com/mymodel/objects/3/'
現在の Site オブジェクトをキャッシュする

現在のサイトを表す Site オブジェクト は、もともとデータベースに保存されているので、 get_current() を呼ぶたび にデータベース呼び出しが発生してしまいます。ただし、 Django はもう少し賢く Site を扱います。 すなわち、現在のサイトをキャッシュし、それ以降 get_current() を呼び出し ても、データベースに触らずキャッシュから Site オブジェクトを返します。

何らかの理由で、データベースクエリを強制したい場合には、 clear_cache()`() を使って キャッシュを消去させられます:

# 最初の呼び出し: データベースから Site オブジェクトを取り出す
current_site = Site.objects.get_current()
# ...

# 2 回目の呼び出し: キャッシュから取り出す
current_site = Site.objects.get_current()
# ...

# 3 回目の呼び出しで、データベースクエリを強制する
Site.objects.clear_cache()
current_site = Site.objects.get_current()
CurrentSiteManager
class django.contrib.sites.managers.CurrentSiteManager

アプリケーション内で Site が重要な働 きを持っている場合、 CurrentSiteManager という便利なクラ スを検討してみてください。

CurrentSiteManager はモデルの マネジャ クラスで、クエリ結果を現在の Site に関連づけられたオブジェクトだけ に自動的にフィルタします。

CurrentSiteManager を使うには、モデ ルの中に明示的に追加します。例を示します:

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Photo(models.Model):
    photo = models.FileField(upload_to='/home/photos')
    photographer_name = models.CharField(max_length=100)
    pub_date = models.DateField()
    site = models.ForeignKey(Site)
    objects = models.Manager()
    on_site = CurrentSiteManager()

このモデルでは、 Photo.objects.all() を使うとデーターベース上の全ての Photo オブジェクトを返しますが、 Photo.on_site.all() を使うと、 SITE_ID 設定に従って、現在のサイトに関連づけられた Photo オ ブジェクトだけを返します。

つまり、以下の二つの文は等価になります:

Photo.objects.filter(site=settings.SITE_ID)
Photo.on_site.all()

CurrentSiteManagerPhoto の どのフィールドが Site なのかをどうやっ て見付けるのでしょう? CurrentSiteManager はデフォルトでは site という名前のフィールドを探します。モデル内で site 以外の 名前の ForeignKeyManyToManyField` を定義している場 合、 CurrentSiteManager に明示的に フィールド名を渡す必要があります。以下のモデルでは、 publish_on という 名前のフィールドがその例です:

from django.db import models
from django.contrib.sites.models import Site
from django.contrib.sites.managers import CurrentSiteManager

class Photo(models.Model):
    photo = models.FileField(upload_to='/home/photos')
    photographer_name = models.CharField(max_length=100)
    pub_date = models.DateField()
    publish_on = models.ForeignKey(Site)
    objects = models.Manager()
    on_site = CurrentSiteManager('publish_on')

CurrentSiteManager を使って、存在し ないフィールド名を渡そうとすると、 Django は ValueError を送出します。

CurrentSiteManager を使っていたとし ても、結局は (サイト固有でない) 通常の Manager をモデル内に持っておく必 要に迫られるでしょう。 マネジャのドキュメント でも説明しましたが、手動でマネジャを定義すると、Django は objects = models.Manager() を使った自動マネジャ生成を行わなくなるからで す。また、 Django の一部 (例えば admin サイトや汎用ビュー) では、モデル内で 最初に定義されている マネジャを常に使うようになっています。そのため、 admin サイトから全てのオブジェクトにアクセスしたい (サイト固有のフィルタリ ングを行わない) 場合には、モデル内で objects = models.Manager()CurrentSiteManager の定義より前 に配置しておかねばなりません。

Django 内での site フレームワークの役割

Django を使う際、必ずしも sites フレームワークを使わねばならないというわけ ではありません。とはいえ、 Django はいくつかの場所で sites の恩恵を利用でき るので、ぜひとも sites を活用するよう勧めます。 Django を単一のサイトを駆動 するためだけに使っているとしても、ひと手間かけてサイトオブジェクトを作成し、 domainname を指定して、その ID を SITE_ID 設定に指定 してみてください。

Django における sites フレームワークの役割は以下の通りです:

  • リダイレクションフレームワーク では、各 リダイレクトオブジェクトが特定のサイトに関連づけられています。 Django が リダイレクト先を探すとき、フ レームワークは現在の SITE_ID を考慮します。
  • コメントフレームワークでは、各コメントが特定のサイトに関連づけられて います。コメントが投稿されると、 site は現在の SITE_ID に 設定されます。コメントを何らかのテンプレートタグでリスト表示する場合、現 在のサイトに関するコメントだけが表示されます。
  • フラットページフレームワーク では、各フ ラットページは特定のサイトに関連づけられています。フラットページを作成す る際には、 site を指定せねばなりません。 FlatpageFallbackMiddleware は現在の SITE_ID をチェックして、表示すべきフラットページを取 得します。
  • 配信フレームワーク では、 title および description のテンプレートから自動的に {{ site }} にアクセ スできます。 {{ site }}Site オブジェクトで、現在の site を表現します。また、フィード項目の URL を提供 するためのフックでは、完全指定 (full-qualified) のドメインを指定していな い場合、現在の Site オブジェクトの domain を使います。
  • 認証フレームワーク では、 django.contrib.auth.views.login() ビューが現在の Site 名を {{ site_name }} とい う形でテンプレートに渡しています。
  • ショートカットビュー (django.views.defaults.shortcut()) では、オブ ジェクトの URL のドメイン部を計算する際に現在の Site オブジェクトを使います。
  • Site オブジェクトに完全指定のホスト 名を定義しておくと、 admin フレームワークで、現在の サイト上で表示 (view on site) のリンク URL の構築に使います。
RequestSite オブジェクト

django.contrib 内のアプリケーションの中には、 sites フレームワークを利用はできるけれども、 必須にはしない ようなものが あります (sites を使いたくない人や、 sites フレームワークが必要とするデータ ベーステーブルの作成が 不可能な 人もいるためです)。こうした場合のために、 sites フレームワークでは RequestSite クラスを提供しています。このクラスは、データベースバックエンド上に sites フ レームワークがない場合のフォールバックとして使われます。

RequestSite オブジェクトは、通常の Site オブジェクトと同様のインタフェー スを備えていますが、 __init__()HttpRequest オブジェクトを取るところが違います。この オブジェクトはリクエストのドメイン情報を見ることで domainname を決定します。 Site オブジェクトとイ ンタフェースを合わせるため、 RequestSite オブジェクトにも save()delete() といったメソッドが ありますが、これらのメソッドを呼び出すと NotImplementedError を送出 します。

配信フィードフレームワーク

revision-up-to:11321 (1.1)

Django には高水準の配信フィード (syndication feed) 生成フレームワークがつい てきます。このフレームワークを使えば、 RSS 形式や Atom 形式のフィードを簡 単に生成できます。

配信フィードの作成は、ちょっとした Python クラスを書くだけでできます。フィー ドは好きな数だけ生成できます。

Django には低水準のフィード生成 API もついてきます。 Web コンテキストの外で フィードを作成したい場合や、低水準での操作が必要な場合に使ってください。

高水準フレームワーク
概要

高水準のフィード生成フレームワークはビューで実現されていて、デフォルトでは /feeds/ にフックされています。 Django は URL の残りの部分 (/feeds/ 以後の部分) を使って、どのフィードを出力するかを決めます。

フィードを生成するには、 Feed ク ラスを書き、 URLConf 内で指定します。

初期化

Django サイトで配信フィードを使うには、 URLConf に以下のような行を追加します:

(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}),

この行は、 Django に "feeds/" で始まる全ての URL を RSS フレームワー クで処理するように教えます (もちろん "feeds/" は自分の好きなプレフィ クスに置き換えられます)。

上の URLconf には追加の引数、 {'feed_dict': feeds} があります。この引数 は、URL に対してどのクラスを使ってフィード生成を行うかを配信フレームワーク に教えます。

特に、 feed_dict はフィードの slug (短い URL ラベル) を Feed クラスに対応づける辞書でな くてはなりません。

feed_dict は URLconf の中で定義できます。 URLconf の完全な例を示しましょ う:

from django.conf.urls.defaults import *
from myproject.feeds import LatestEntries, LatestEntriesByCategory

feeds = {
    'latest': LatestEntries,
    'categories': LatestEntriesByCategory,
}

urlpatterns = patterns('',
    # ...
    (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
        {'feed_dict': feeds}),
    # ...
)

上の例では、二つのフィード:

  • feeds/latest/ にある、 LatestEntries で表されるフィード
  • feeds/categories/ にある、 LatestEntriesByCategory で表され るフィード

を登録しています。

セットアップしたら、あとは Feed クラス自体を定義するだけです。

Feed クラス

Feed クラスは、ひとつの配信フィー ドを表現する単純な Python クラスです。フィードは単純な形式 (「サイトニュー ス」フィードや、最新のブログエントリを表示する基本的な形式 ) にも、もっと複 雑な形式 (特定のカテゴリの全てのエントリを表示するフィード) にもできます。

Feed クラスは django.contrib.syndication.feeds.Feed のサブクラスにせねばなりませ ん。クラスはコードベースのどこにでも置けます。

簡単な例

以下の例は chicagocrime.org で使っているもので、最新の 5 件のニュース項 目を記述するようになっています:

from django.contrib.syndication.feeds import Feed
from chicagocrime.models import NewsItem

class LatestEntries(Feed):
    title = "Chicagocrime.org site news"
    link = "/sitenews/"
    description = "Updates on changes and additions to chicagocrime.org."

    def items(self):
        return NewsItem.objects.order_by('-pub_date')[:5]

注意:

  • django.contrib.syndication.feeds.Feed のサブクラスになっています。
  • title, link および description は、それぞれ標準的 な RSS の <title>, <link> および <description> 要素に対応して います。
  • items() はフィードの <item> 要素に含めるオブジェクトのリスト を返すメソッドです。この例では Django の Object-Relational マッパ を使って NewsItem を返していますが、 items() は必ずしもモデルインスタ ンスを返さねばならないわけではありません。 Django モデルを使えばいくつか の機能を何もせずに使えるというだけの話で、 items() は望みのどんな 型のオブジェクトを返してもかまいません。
  • RSS フィードの代わりに Atom フィードを生成する場合、 description 属性の代わりに subtitle 属性を設定してください。詳しくは Atom フィードと RSS フィードを並行出力する を参照してください。

まだやるべきことが残っています。 RSS フィード中では、 <item> には <title>, <link>, <description> といったエレメントがあります。 そこで、これらのエレメントにどのデータを入れるのかをフレームワークに教える 必要があります。

  • <title><description> の中身を指定するには、 feeds/latest_title.html または feeds/latest_description.html という名前の Django テン プレート を作成します。 latest は URLconf 中に指定しておいた、フィードの slug です。 .html 拡張子 が必要なことに注意して下さい。 RSS システムはこれらのテンプレートを各 要素に対してレンダリングします。このとき、二つのテンプレートコンテキ スト変数を渡します:

    • {{ obj }} – 現在のオブジェクト (items() の返すオブ ジェクトの中の一つ) です。
    • {{ site }} – 現在のサイトを表現する、 django.contrib.sites.models.Site オブジェクトです。この変数 は {{ site.domain }}{{ site.name }} を参照する際に 便利です。最新の開発版の Django を使っていて、 sites フレームワー クを 使っていない 場合、この値は django.contrib.sites.models.RequestSite オブジェクトになり ます。詳しくは RequestSite の説明 を参照してください。

    titledescription のテンプレートを作成しなかった場合、 RSS フレームワークは "{{ obj }}" で表されるテンプレートをデフォルト値 として使います。すなわち、オブジェクトの文字列表現が使われます。 Feed クラスに title_templatedescription_template といった属性値を指定す れば、これらのテンプレートの名前を指定できます。

  • <link> の内容を指定するには二つの方法があります。 items() の各要素毎に、Django はまずオブジェクトに対して get_absolute_url() メソッドを実行しようと試みます。このメソッドが なければ、 Feed クラスで定 義されている item_link() メソッドを呼び出そうとします。このと き、メソッドにはオブジェクト自体を引数 item として渡します。 get_absolute_url()item_link() は、いずれも通常の Python 文字列で URL を返さねばなりません。また、 get_absolute_url() と同様、 item_link() の返す値は直接 URL に組み込めなければなりません。このため、プログラマは、必要に応じ て URL のクオート処理や変換を行って、全ての文字が ASCII 文字からなる 値に変換する責任があります。

  • 上の LatestEntries の例では、以下のような簡単なフィードテンプレートに できます:

    * latest_title.html:
    
    {{ obj.title }}
    
    • latest_description.html:

      {{ obj.description }}
      
複雑な例

配信フレームワークは、パラメタを使ったより複雑なフィードをサポートしています。

例えば、 chicagocrime.org では、シカゴ市内の全ての警官の巡回区域 (beat) ごとに最新の犯罪情報のフィードを提供しています。全ての巡回区域毎に Feed クラスを用意するのは馬鹿ら しい話です。 DRY 則 に反していますし、データの都合とプログラム ロジックを連結させてしまうことになります。その代わりに、配信フレームワーク では、フィードの URL に指定した情報に従って適切な要素を出力するような汎用の フィードを生成できるようにしています。

chicagocrime.org では、巡回区域単位のフィードに以下のような URL でアクセス できるようになっています:

  • /rss/beats/0613/ – 0613 区の最近の犯罪を返します。
  • /rss/beats/1424/ – 1424 区の最近の犯罪を返します。

ここでは "beats" が slug になっています。配信フレームワークは slug より 後ろの URL 部分要素 (URL bit) を調べ (06131424)、それらの URL bit にどのような意味を与え、フィード公開する項目の選択にどう影響を及ぼさせ るかをユーザがフックで指定できるようにします。

例を挙げてわかりやすく説明しましょう。巡回区域単位のフィードを生成するコー ドは以下のようになります:

from django.contrib.syndication.feeds import FeedDoesNotExist
from django.core.exceptions import ObjectDoesNotExist

class BeatFeed(Feed):
    def get_object(self, bits):
        # In case of "/rss/beats/0613/foo/bar/baz/", or other such clutter,
        # check that bits has only one member.
        if len(bits) != 1:
            raise ObjectDoesNotExist
        return Beat.objects.get(beat__exact=bits[0])

    def title(self, obj):
        return "Chicagocrime.org: Crimes for beat %s" % obj.beat

    def link(self, obj):
        if not obj:
            raise FeedDoesNotExist
        return obj.get_absolute_url()

    def description(self, obj):
        return "Crimes recently reported in police beat %s" % obj.beat

    def items(self, obj):
       return Crime.objects.filter(beat__id__exact=obj.id).order_by('-crime_date')[:30]

このクラスに URL /rss/beats/0613/ でアクセスしたときの、 RSS フレー ムワークの基本的なアルゴリズムは以下の通りです:

  • フレームワークに URL /rss/beats/0613/ が渡されます。フレーム ワークは slug 以後の URL 部分を検出し、 slug 以後の文字列をスラッシュ ("/") で分割して、 Feed クラスの get_object() メソッドの引数 bits に渡して呼び出します。上 の例では bits['0613'] になります。リクエストが /rss/beats/0613/foo/bar/ であれば bits['0613', 'foo', 'bar'] です。

  • get_object() は指定された bits を使って適切な巡回区域を選 択する役割を担っています。上の場合では、 Django のデータベース API を 使って巡回区域を決定しています。 無効なパラメタが指定された場合、 get_object()django.core.exceptions.ObjectDoesNotExist を返さねばなりません。 関数が失敗すると Beat.DoesNotExist を送出し、 Beat.DoesNotExistObjectDoesNotExist のサブクラスなので、 Beat.objects.get() 呼び出しの周りには try/except がありま せん。 get_object() の中で ObjectDoesNotExist を送出すると、 Django はリクエストに対して 404 エラーを返します。

    get_object()/rss/beats/ を扱えるようになりまし た。

    get_object() を使って /rss/beats/ を処理させる方法が あります。それは、 bits が空のリストのときです。上の例では、 len(bits) !=1 のとき、 ObjectDoesNotExist 例外を送出する ので、 /rss/beats/ は 404 エラーページを生成します。しかし、 実際にはここで好きな処理を行って構いません。たとえば、全ての beat の フィードを合わせたような結果を生成して返してもよいのです。

  • フィードの <title>, <link>, および <description> を生成す るために、 Django はそれぞれ title(), link() および description() といったメソッドを使います。こうしたメソッドは 前述の例では単なる文字列でできたクラス属性でしたが、実際には文字列に もメソッドにもできます。 title, link および description については、 Django は以下のようなアルゴリズムで値を決めます:

    • get_object() の返すオブジェクト obj を引数にして、メ ソッドを呼び出そうと試みます。
    • 失敗した場合、メソッドを引数無しで呼び出そうと試みます。
    • 失敗した場合、クラス属性を使います。

    link() メソッドの中では、 objNone の場合、すなわ ちURL が完全に指定されなかった場合の処理を定義しておかねばなりません。 この部分で、 obj が存在するかどうかチェックしない場合には、他のメ ソッドでも、 objNone であるかチェックする必要があるでしょ う (link() メソッドは、フィード生成プロセスのきわめて初期段階 で呼び出されるので、例外ではじき出しておくのにいい場所です)。

  • 最後に、上の例の items() には引数 obj があることに注意し て下さい。 items の内容を解決するアルゴリズムは上と同じです。 すなわち、まず items(obj), 次いで items(), そしてクラ ス属性 items` (この値はリストでなければなりません) の順です。

下記の ExampleFeed クラスには、 Feed クラスの全てのメソッドと属 性についてのドキュメントが書かれています。

フィードの形式を指定する

このフレームワークは、デフォルトでは RSS 2.0 のフィードを生成します。

生成するフィードの形式を変えたければ、 Feed クラスの feed_type 属性 を変更します:

from django.utils.feedgenerator import Atom1Feed

class MyFeed(Feed):
    feed_type = Atom1Feed

feed_type にはインスタンスではなくクラスオブジェクトを指定するよう注意 して下さい。

現在利用可能なフィードの型は以下の 3 つです:

エンクロージャ

podcast のフィードを生成するときなどに使われるエンクロージャ (enclusure) の 指定には、 item_enclosure_url, item_enclosure_length および item_enclosure_mime_type フックを使って下さい。後述の使用例にある ExampleFeed クラスを参照してください。

言語

配信フレームワークによって生成されたフィードには、自動的に適切な <language> タグ (RSS 2.0) や xml:lang 属性 (Atom) が入ります。 これらの値には LANGUAGE_CODE を直接使います。

URL

link メソッド/属性は絶対 URL (すなわち "/blog/") またはドメイン やプロトコルを完全指定した URL ("http://www.example.com/blog/") のいず れかを返さねばなりません。 link がドメインを返さない場合、配信フレー ムワークは現在のサイトのドメインを SITE_ID に従って挿 入します。

Atom フィードにはフィードの現在の場所を定義する <link rel="self"> が必 要です。配信フレームワークは現在の SITE_ID の設定に従ってドメインから取り出 した値を自動的に入れるようになっています。

Atom フィードと RSS フィードを並行出力する

Atom と RSS の 両方の バージョンを利用したい開発者もいることでしょう。 Django を使えば簡単に実現できます。自作の Feed クラスをサブクラス化して、 feed_type を変更し、 URLconf を更新して、他のバージョン向けのエント リを追加するだけです。

完全な例を示しましょう:

from django.contrib.syndication.feeds import Feed
from chicagocrime.models import NewsItem
from django.utils.feedgenerator import Atom1Feed

class RssSiteNewsFeed(Feed):
    title = "Chicagocrime.org site news"
    link = "/sitenews/"
    description = "Updates on changes and additions to chicagocrime.org."

    def items(self):
        return NewsItem.objects.order_by('-pub_date')[:5]

class AtomSiteNewsFeed(RssSiteNewsFeed):
    feed_type = Atom1Feed
    subtitle = RssSiteNewsFeed.description

Note

上の例では、RSS フィードは description を使っています。一方、 Atom フィードでは subtitle を使っています。Atom フィードはフィー ドレベルの description を持たず、 subtitle を持っている からです。

Feed クラスに description を定義しておいても、Django は description の値を自動的に subtitle エレメントに入れたりはしません。 subtitledescription は必ずしも同じものを指さないか らです。その代わり、適切な説明の入った文字列をモデルの subtitle 属性として指定せねばなりません。

上の例では、たまたま RSS フィードの description は十分短いので、 そのまま使っています。

対応する URLconf は以下のようにします:

from django.conf.urls.defaults import *
from myproject.feeds import RssSiteNewsFeed, AtomSiteNewsFeed

feeds = {
    'rss': RssSiteNewsFeed,
    'atom': AtomSiteNewsFeed,
}

urlpatterns = patterns('',
    # ...
    (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
        {'feed_dict': feeds}),
    # ...
)
Feed クラスリファレンス
class django.contrib.syndication.feeds.Feed

この節の例では、 Feed クラスで利 用できる全ての属性とメソッドについて説明しています:

from django.contrib.syndication.feeds import Feed
from django.utils import feedgenerator

class ExampleFeed(Feed):

    # FEED TYPE -- 省略可能です。
    # django.utils.feedgenerator.SyndicationFeed のサブクラスを
    # 指定せねばなりません。 RSS 2.0, Atom 1.0 といったフィードの形式
    # を表します。
    # feed_type を指定しなければ、 RSS 2.0 を使います。
    # クラスのインスタンスではなく、クラス自体にせねばなりません。

    feed_type = feedgenerator.Rss201rev2Feed

    # TEMPLATE NAMES -- 省略可能です。
    # フィード項目のタイトルと詳細をレンダリングするための Django テン
    # プレート名を表す名前でなければなりません。いずれも省略可能です。
    # 片方、または両方を省略した場合、 Django は
    # 'feeds/SLUG_title.html' および 'feeds/SLUG_description.html' とい
    # う名前のテンプレートを使います。 SLUG は URL に指定した slug です。

    title_template = None
    description_template = None

    # TITLE -- 以下の三つの形式の少なくともいずれか一つが必要です。配信
    # フレームワークは以下の順に値を探します。

    def title(self, obj):
        """
        get_object() の返すオブジェクトを引数にとり、フィードのタイトルを
        通常の python 文字列で返します。
        """

    def title(self):
        """
        フィードのタイトルを通常の python 文字列で返します。
        """

    title = 'foo' # ハードコード形式のフィードのタイトルです。

    # LINK -- 以下の三つの形式の少なくともいずれか一つが必要です。配信
    # フレームワークは以下の順に値を探します。

    def link(self, obj):
        """
        get_object() の返すオブジェクトを引数にとり、フィードへのリンクを
        通常の python 文字列で返します。
        """

    def link(self):
        """
        フィードへのリンクを通常の python 文字列で返します。
        """

    link = '/foo/bar/' # ハードコード形式のフィードのリンクです。

    # GUID -- 省略可能です。配信フレームワークは以下の順に値を探します。
    # このプロパティは Atom フィード (のフィードレベルの ID エレメント)
    # でしか使いません。省略すると、フィードのリンクを ID に使います。

    def feed_guid(self, obj):
        """
        get_object() の返すオブジェクトを引数にとり、一意なフィードの識
        別子を Python 文字列として返します。
        """

    def feed_guid(self):
        """
        一意なフィードの識別子を Python 文字列として返します。
        """

    feed_guid = '/foo/bar/1234' # ハードコード形式の guid です。

    # DESCRIPTION -- 以下の三つの形式の少なくともいずれか一つが必要です。
    # 配信フレームワークは以下の順に値を探します。

    def description(self, obj):
        """
        get_object() の返すオブジェクトを引数にとり、フィードの説明
        を通常の python 文字列で返します。
        """

    def description(self):
        """
        フィードの説明を通常の python 文字列で返します。
        """

    description = 'Foo bar baz.' # ハードコード形式のフィードの説明です。

    # AUTHOR NAME -- 以下の三つの形式のいずれか一つを指定できます。配信
    # フレームワークは以下の順に値を探します。省略可能です。

    def author_name(self, obj):
        """
        get_object() の返すオブジェクトを引数にとり、フィードの作者名を
        通常の python 文字列で返します。
        """

    def author_name(self):
        """
        フィードの作者名を通常の python 文字列で返します。
        """

    author_name = 'Sally Smith' # ハードコード形式のフィードの作者名です。

    # AUTHOR E-MAIL -- 以下の三つの形式のいずれか一つを指定できます。配信
    # フレームワークは以下の順に値を探します。省略可能です。

    def author_email(self, obj):
        """
        get_object() の返すオブジェクトを引数にとり、フィードの作者の email を
        通常の python 文字列で返します。
        """

    def author_name(self):
        """
        フィードの作者の email を通常の python 文字列で返します。
        """

    author_email = 'test@example.com' # ハードコード形式の作者の email です。

    # AUTHOR LINK -- 以下の三つの形式のいずれか一つを指定できます。配信
    # フレームワークは以下の順に値を探します。省略可能です。どの場合でも、
    # URL には "http://" およびドメイン名を入れねばなりません。

    def author_link(self, obj):
        """
        get_object() の返すオブジェクトを引数にとり、フィードの作者の
        URL を通常の python 文字列で返します。
        """

    def author_link(self):
        """
        フィードの作者の URL を通常の python 文字列で返します。
        """

    author_link = 'http://www.example.com/' # ハードコード形式の作者 URL です。

    # CATEGORIES -- 以下の三つの形式はいずれも省略可能です。フレームワー
    # クは以下に示した順番で値を探します。いずれの場合も、メソッド/属性
    # 値は文字列を返すイテレータを返さねばなりません。

    def categories(self, obj):
        """
        get_object() の返すオブジェクトを引数にとり、フィードのカテゴリ
        を表す文字列を返すイテレータを返します。
        """

    def categories(self):
        """
        フィードのカテゴリを表す文字列を返すイテレータを返します。
        """

    # カテゴリリストのハードコード表現です。
    categories = ("python", "django")

    # COPYRIGHT NOTICE -- 以下の三つの形式はいずれも省略可能です。
    # フレームワークは以下に示した順番で値を探します。

    def copyright(self, obj):
        """
        get_object() が返すようなオブジェクトを引数 obj にとり、
        フィードの著作権表示を通常の Python 文字列型で返します。
        """

    def copyright(self):
        """
        フィードの著作権表示を通常の Python 文字列型で返します。
        """

    # 著作権表示のハードコード表現です。
    copyright = 'Copyright (c) 2007, Sally Smith'

    # TTL -- 以下の三つの形式はいずれも省略可能です。
    # フレームワークは以下に示した順番で値を探します。
    # Atom フィードでは無視されます。

    def ttl(self, obj):
        """
        get_object() が返すようなオブジェクトを引数 obj にとり、
        フィードの TTL (寿命) を 通常の Python 文字列型で返します。
        """

    def ttl(self):
        """
        フィードの TTL (寿命) を 通常の Python 文字列型で返します。
        """

    ttl = 600 # TTL のハードコード表現です。

    # ITEMS -- 以下の三つの形式の少なくともいずれか一つが必要です。配信
    # フレームワークは以下の順に値を探します。

    def items(self, obj):
        """
        get_object() の返すオブジェクトを引数にとり、このフィードで公
        開する item のリストを返します。
        """

    def items(self):
        """
        フィードで公開する item のリストを返します。
        """

    items = ('Item 1', 'Item 2') # ハードコード形式の item リストです。

    # GET_OBJECT -- 異なる URL パラメタに対して異なるデータを公開する場
    # 合に必要なメソッドです。 (前述の "複雑な例" を参照してください)

    def get(self, bits):
        """
        URL から取り出した文字列のリストを引数にとり、フィードで表現す
        るオブジェクトからなるリストを返します。エラー時には
        django.core.exceptions.ObjectDoesNotExist を送出します。
        """

    # ITEM LINK -- 以下の三つの形式の少なくともいずれか一つが必要です。配信
    # フレームワークは以下の順に値を探します。

    # まず、フレームワークは以下の二つのメソッドを順に試します。失敗す
    # ると、 items() の返す各オブジェクトに対して get_absolute_url() を
    # 呼び出します。

    def item_link(self, item):
        """
        items() の返す item を引数に取り、item への URL を返します。
        """

    def item_link(self):
        """
        item への URL を返します。
        """

    # ITEM_GUID -- 以下のメソッドは省略可能です。
    # このプロパティは Atom フィード (のフィードレベルの ID エレメント)
    # でしか使いません。省略すると、item のリンクを ID に使います。

    def item_guid(self, obj):
        """
        items() の返す item を引数にとり、 item の ID を返します。
        """

    # ITEM AUTHOR NAME -- 以下の三つの形式のいずれか一つを指定できます。配信
    # フレームワークは以下の順に値を探します。省略可能です。

    def item_author_name(self, item):
        """
        items() の返す item を引数に取り、item の作者名を通常の python
        文字列で返します。
        """

    def item_author_name(self):
        """
        作者名を返します。
        """

    item_author_name = 'Sally Smith' # ハードコード形式の作者名です。

    # ITEM AUTHOR E-MAIL -- 以下の三つの形式のいずれか一つを指定できます。配信
    # フレームワークは以下の順に値を探します。省略可能です。
    #
    # この属性を指定する場合、item_author_name も指定せねばなりません。

    def item_author_email(self, obj):
        """
        items() の返す item を引数に取り、item の作者の e-mail を通常の
        python 文字列で返します。
        """

    def item_author_email(self):
        """
        作者の e-mail を返します。
        """

    item_author_email = 'test@example.com' # ハードコード形式の作者 e-mail です。

    # ITEM AUTHOR LINK -- 以下の三つの形式のいずれか一つを指定できます。配信
    # フレームワークは以下の順に値を探します。省略可能です。この場合、
    # URL には "http://" およびドメイン名を入れねばなりません。
    #
    # この属性を指定する場合、 item_author_name も指定せねばなりません。

    def item_author_link(self, obj):
        """
        items() の返す item を引数に取り、item の作者の URL を通常の
        python 文字列で返します。
        """

    def item_author_link(self):
        """
        item の作者の URL を通常の python 文字列で返します。
        """

    item_author_link = 'http://www.example.com/' # ハードコード形式の作者 URL です。

    # ITEM ENCLOSURE URL -- エンクロージャを公開する場合、以下の三つの
    # 形式の少なくともいずれか一つが必要です。配信フレームワークは以下
    # の順に値を探します。


    def item_enclosure_url(self, item):
        """
        items() の返す item を引数に取り、item のエンクロージャ URL を返します。
        """

    def item_enclosure_url(self):
        """
        フィード中の各 item のエンクロージャ URL を返します。
        """

    item_enclosure_url = "/foo/bar.mp3" # ハードコード形式のエンクロージャ URL です。

    # ITEM ENCLOSURE LENGTH -- エンクロージャを公開する場合、以下の三つ
    # の形式の少なくともいずれか一つが必要です。配信フレームワークは以
    # 下の順に値を探します。この場合、戻り値はバイト単位で長さを表した
    # 整数か、整数を表す文字列でなければなりません。

    def item_enclosure_length(self, item):
        """
        items() の返す item を引数に取り、item のエンクロージャ長を返します。
        """

    def item_enclosure_length(self):
        """
        フィード中の各 item のエンクロージャ長を返します。
        """

    item_enclosure_length = 32000 # ハードコード形式のエンクロージャ長です。

    # ITEM ENCLOSURE MIME TYPE -- エンクロージャを公開する場合、以下の
    # 三つの形式の少なくともいずれか一つが必要です。配信フレームワーク
    # は以下の順に値を探します。

    def item_enclosure_mime_type(self, item):
        """
        items() の返す item を引数に取り、item のエンクロージャ MIME タ
        イプを返します。
        """

    def item_enclosure_mime_type(self):
        """
        各 item のエンクロージャの MIME タイプを返します。
        """

    item_enclosure_mime_type = "audio/mpeg" # ハードコード形式の MIME
                                            # タイプです。

    # ITEM PUBDATE -- 以下の三つの形式のいずれか一つを指定できます。
    # 省略可能です。
    # このメソッドは指定の要素に対する公開日を取得するためのフックです。
    # どのケースでも、メソッドや属性は Python の datetime.datetime
    # オブジェクトを返さねばなりません。

    def item_pubdate(self, item):
        """
        items() の返す item を引数に取り、item の公開日を返します。
        """

    def item_pubdate(self):
        """
        公開日を返します。
        """

    item_pubdate = datetime.datetime(2005, 5, 3) # ハードコード形式の公開日です。

    # ITEM CATEGORIES -- 以下の三つの形式はいずれも省略可能です。指定さ
    # れた item に対するカテゴリリストを取得するためのフックです。いずれ
    # の場合も、メソッド/属性値は文字列を返すイテレータを返さねばなりま
    # せん。

    def item_categories(self, item):
        """
        items() の返す item を引数にとり、 item のカテゴリ
        を表す文字列を返すイテレータを返します。
        """

    def item_categories(self):
        """
        フィード内の全 items のカテゴリを返します。
        """

    item_categories = ("python", "django") # ハードコード形式のカテゴリです。

    # ITEM COPYRIGHT NOTICE (Atom フィードにのみ適用されます)
    # 以下の三つの形式のいずれか一つを指定できます。配信フレームワーク
    # は以下の順に値を探します。省略可能です。

    def item_copyright(self, obj):
        """
        items() の返す item を引数にとり、 item の著作権表示を
        通常の Python 文字列型で返します。
        """

    def item_copyright(self):
        """
        全 item の著作権表示を通常の Python 文字列型で返します。
        """

    # 著作権表示をハードコードする場合の指定方法です。
    item_copyright = 'Copyright (c) 2007, Sally Smith'
低水準フレームワーク

高水準の RSS フレームワークは、背後で低水準のフレームワークを使ってフィード の XML を生成しています。このフレームワーク自体は、 django/utils/feedgenerator.py に単一のモジュールとして収められています。

このフレームワークを使って、自分で低水準のフィード生成処理を実装できます。 また、フィードジェネレータのサブクラスを作成すれば、 Feedfeed_type オプションに指定して使えます。

SyndicationFeed クラス

feedgenerator モジュールには、ベースクラス:

class django.utils.feedgenerator.SyndicationFeed

と、以下のサブクラスが定義されています:

class django.utils.feedgenerator.RssUserland091Feed
class django.utils.feedgenerator.Rss201rev2Feed
class django.utils.feedgenerator.Atom1Feed

これらのクラスはいずれも、特定のタイプの XML を生成する方法を知っており、 以下のような共通のインタフェースを持っています:

SyndicationFeed.__init__(**kwargs)

メタデータの入った辞書をもとにフィードを生成します。メタデータはフィー ド全体に適用されます。以下の引数が必須です:

  • title
  • link
  • description

また、以下のようなオプションキーワードをサポートしています:

  • language
  • author_email
  • author_name
  • author_link
  • subtitle
  • categories
  • feed_url
  • feed_copyright
  • feed_guid
  • ttl

これ以外のキーワード引数を __init__ に渡すと、 self.feed に保存 されます。使い方は カスタムのフィードジェネレータ を参照してください。

パラメタは全て Unicode オブジェクトで指定します。ただし、 categories は Unicode オブジェクトのリストです。

SyndicationFeed.add_item(**kwargs)

指定のパラメタをもった項目をフィードに追加します。

以下の引数は必須です:

  • title
  • link
  • description

また、以下のオプションの引数があります:

  • author_email
  • author_name
  • author_link
  • pubdate
  • comments
  • unique_id
  • enclosure
  • categories
  • item_copyright
  • ttl

それ以外のキーワード引数は カスタムのフィードジェネレータ 用に保存されます。

パラメタには Unicode オブジェクトを指定します。ただし:

  • pubdatePython datetime 型オブジェクト にします。
  • enclosurefeedgenerator.Enclosure のインスタンスにします。
  • categories は Unicode オブジェクトのシークエンスにします。
SyndicationFeed.write(outfile, encoding)

フィードを指定のエンコーディングでファイルライクオブジェクト outfile に 出力します。

SyndicationFeed.writeString(encoding)

フィードを指定のエンコーディングの文字列として返します。

以下の例では Atom 1.0 フィードを生成して、標準出力に出力しています:

>>> from django.utils import feedgenerator
>>> f = feedgenerator.Atom1Feed(
...     title=u"My Weblog",
...     link=u"http://www.example.com/",
...     description=u"In which I write about what I ate today.",
...     language=u"en")
>>> f.add_item(title=u"Hot dog today",
...     link=u"http://www.example.com/entries/1/",
...     description=u"<p>Today I had a Vienna Beef hot dog. It was pink, plump and perfect.</p>")
>>> print f.writeString('utf8')
<?xml version="1.0" encoding="utf8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
...
</feed>
カスタムのフィードジェネレータ

カスタムのフォーマットでフィードを生成したいなら、二つ方法があります。

完全に独自の形式のフィードなら、 SyndicationFeed をサブクラス化して、 write() および writeString() メソッドを完全に書き直すとよいでしょう。

しかし、 (GeoRSS や Apple の iTunes podcast フォーマット )のように、既 存のフィードフォーマットから派生したものであれば、もっといい選択肢がありま す。この手の派生フォーマットは、元のフォーマットにエレメントや属性を追加し ていて、 SyndicationFeed のメソッドには、こうした追加の属性を取得するた めのものがあります。ですから、適切なフィードクラス (Atom1FeedRss201rev2Feed) をサブクラス化して、コールバックを拡張すればよいのです。 拡張用のメソッドを以下に示します:

SyndicationFeed.root_attributes(self, )
フィードのルート要素 (feed/channel) に追加する属性の入った dict を返します。
SyndicationFeed.add_root_elements(self, handler)
フィードのルート要素 (feed/channel) 要素に新たに要素を付加する ためのコールバックです。 handler は Python 組み込み SAX ライブラリ の XMLGenerator です。このオブジェクトのメソッドを呼び出して、 処理中 の XML ドキュメントに要素を追加します。
SyndicationFeed.item_attributes(self, item)
フィードの各要素 (item/entry) に追加する属性の入った dict を返します。引数 item は、 SyndicationFeed.item() に渡された データの入っている dict です。
SyndicationFeed.add_item_elements(self, handler, item)
各要素の (item/entry) 要素に新たに要素を付加するためのコールバッ クです。 handleritem は上と同じです。

Warning

これらのメソッドをオーバライドするときは、スーパクラスのメソッドを忘れ ずに呼び出してください。スーパクラス側でも、必須の要素を追加するために これらのメソッドを使っているからです。

例えば、 iTunes RSS フィードジェネレータを実装するなら、書き始めは以下のよ うになるでしょう:

class iTunesFeed(Rss201rev2Feed):
    def root_attibutes(self):
        attrs = super(iTunesFeed, self).root_attibutes()
        attrs['xmlns:itunes'] = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
        return attrs

    def add_root_elements(self, handler):
        super(iTunesFeed, self).add_root_elements(handler)
        handler.addQuickElement('itunes:explicit', 'clean')

もちろん、カスタムのフィードクラスを定義するには他にもたくさん作業が必要で すが、上の例を見れば基本的な考え方は理解できるはずです。

django.contrib.webdesign

revision-up-to:11321 (1.1)

django.contrib.webdesign パッケージは “django.contrib” のアドオン の一部で、Web 開発者 ではなく デザイナ にとって便利なヘルパを提供しています。

現時点では、このパッケージにたテンプレートタグが一つ入っているだけです。 Django に取り込みたい Web デザイナフレンドリな機能のアイデアがあるなら、 ぜひ 開発チームに提案 してください。

テンプレートタグ

django.contrib.webdesign のテンプレートタグを使うには、 'django.contrib.webdesign'INSTALLED_APPS 設定に追加しま す。その上で、テンプレートに {% load webdesign %} を入れれば、テンプレー トタグを使えます。

lorem

ラテン語の “lorem ipsum” からランダムな文を生成して出力します。テンプレート 内にサンプルデータを入れるときに便利です。

使用法:

{% lorem [count] [method] [random] %}

{% lorem %} 引数なしでも使えますが、3 つの省略可能な引数を指定できます:

引数 説明
count 出力する文または単語の個数を表す数 (または変数) です。 デフォルトは 1 です。
method w にすると単語を、 p にすると HTML の <p> タグ を使った段落を、 b にすると平文の段落ブロックを出力し ます。 (デフォルトは b) です。
random random を指定すると、テキストを生成するときにお決まり の文 (“Lorem ipsum dolor sit amet...”) を使いません。

例:

  • {% lorem %} とすると、おなじみの “lorem ipsum” 文を出力します。
  • {% lorem 3 p %} とすると、おなじみの “lorem ipsum” 文と、ランダム な文をそれぞれ HTML の <p> タグでラップしたものを出力します。
  • {% lorem 2 w random %} とすると、ランダムな 2 単語のラテン語を出 力します。

admin

Django の自動化管理インタフェースです。詳しくは チュートリアルその 2admin のドキュメント を参照してください。

auth および contenttypes パッケージをインストールしておく必要があります。

auth

Django の認証フレームワークです。詳しくは Django でのユーザ認証 を参照して下さ い。

comments

シンプルかつ柔軟なコメントシステムです。 コメントフレームワーク を参照してください。

contenttypes

コンテンツの「タイプ」をフックしするための軽量フレームワークです。 コンテンツタイプは、インストールされている Django の個々のモデルを指します。

contenttypes のドキュメント を参照してください。

csrf

クロスサイトリクエストフォージェリ (Cross Site Request Forgeries) を阻止す るためのミドルウェアです。

csrf のドキュメント を参照してください。

flatpages

「フラット (flat) な」 HTML コンテンツをデータベースで扱うためのフレームワー クです。

flatpages のドキュメント を参照してください。

sites パッケージもインストールしておく必要があります。

formtools

Django の新しいフォーム (django.forms) に対する高水準の抽象化インタフェー スです。

django.contrib.formtools.preview

「 HTML フォームを表示し、必ずプレビューを行ってからフォームデータを提出す る」というワークフローを抽象化したものです。

フォームプレビューのドキュメント を参照してください。

django.contrib.formtools.wizard

フォームを複数の Web ページにわたるように分割します。

フォームウィザードのドキュメント を参照してください。

gis

空間情報の保存、操作、表示を実現する、Django の上に構築された世界クラスの 地理空間情報フレームワークです。

詳細については /ref/contrib/gis/index のドキュメントを参照してください。

humanize

データに「人間くささ (human touch)」を与えるための Django テンプレートフィ ルタです。

humanize のドキュメント を参照してください。

localflavor

特定の国や文化でのみ有用な Django の短いコード (snippet) を集めたものです。 例えば、 django.contrib.localflavor.us.forms には、米国の郵便番号 (U.S. zip code) を検証するための USZipCodeField が入っています。

localflavor のドキュメント を参照してくだ さい。

markup

一般的なマークアップ言語を実装したテンプレートフィルタのコレクションです。

markup のドキュメント を参照してください。

messages

messages フレームワークが追加されました。

クッキーまたはセッションベースの、一時的なメッセージを格納・取得する フレームワークです。

messages のドキュメント を参照してください。

redirects

リダイレクトを管理するためのフレームワークです。

redirects のドキュメント を参照してください。

sessions

セッション管理のためのフレームワークです。

セッションのドキュメント を参照してください。

sites

一つのデータベースと Django を使って複数のウェブサイトを操作できるようにす るための軽量フレームワークです。このフレームワークを使うと、オブジェクトを 特定の (一つまたは複数の) サイトに関連づけできます。

sites のドキュメント を参照してください。

sitemaps

Google サイトマップ XML ファイルを生成するためのフレームワークです。

sitemaps のドキュメント を参照してください。

syndication

RSS および Atom 形式の配信フィード (syndication feed) をごく簡単に生成する ためのフレームワークです。

配信フィードフレームワークのドキュメント を参照してください。

webdesign

Web の 開発者 ではなく デザイナ のためのヘルパやユーティリティです。

webdesign のドキュメント を参照してください。

その他のアドオン

contrib に入れたらよいと思う機能について何かアイデアがあるなら、是非教 えて下さい! コードを書いて、 django-users mailing list に送って下さい。

データベースのサポート状況

revision-up-to:11321 (1.1) unfinished

Django は可能な限り全てのデータベースバックエンドをサポートしようとしていま すが、残念ながら全てのサーバが全く同じ仕様というわけではないので、どの機能 をサポートすべきか、どういった仕様を仮定するかといった設計上の判断を下して います。

このドキュメントでは、このドキュメントでは、 Django を使う上で関係のあるデー タベース機能について説明します。ただし、このドキュメントは特定のデータベー スサーバ向けのドキュメントとして書かれたものではなく、リファレンスマニュア ルでもありません。

PostgreSQL notes

PostgreSQL 8.2 to 8.2.4

The implementation of the population statistics aggregates STDDEV_POP and VAR_POP that shipped with PostgreSQL 8.2 to 8.2.4 are known to be faulty. Users of these releases of PostgreSQL are advised to upgrade to Release 8.2.5 or later. Django will raise a NotImplementedError if you attempt to use the StdDev(sample=False) or Variance(sample=False) aggregate with a database backend that falls within the affected release range.

Transaction handling

By default, Django starts a transaction when a database connection is first used and commits the result at the end of the request/response handling. The PostgreSQL backends normally operate the same as any other Django backend in this respect.

Autocommit mode

If your application is particularly read-heavy and doesn’t make many database writes, the overhead of a constantly open transaction can sometimes be noticeable. For those situations, if you’re using the postgresql_psycopg2 backend, you can configure Django to use “autocommit” behavior for the connection, meaning that each database operation will normally be in its own transaction, rather than having the transaction extend over multiple operations. In this case, you can still manually start a transaction if you’re doing something that requires consistency across multiple database operations. The autocommit behavior is enabled by setting the autocommit key in the DATABASE_OPTIONS setting:

DATABASE_OPTIONS = {
    "autocommit": True,
}

In this configuration, Django still ensures that delete() and update() queries run inside a single transaction, so that either all the affected objects are changed or none of them are.

This is database-level autocommit

This functionality is not the same as the topics-db-transactions-autocommit decorator. That decorator is a Django-level implementation that commits automatically after data changing operations. The feature enabled using the DATABASE_OPTIONS settings provides autocommit behavior at the database adapter level. It commits after every operation.

If you are using this feature and performing an operation akin to delete or updating that requires multiple operations, you are strongly recommended to wrap you operations in manual transaction handling to ensure data consistency. You should also audit your existing code for any instances of this behavior before enabling this feature. It’s faster, but it provides less automatic protection for multi-call operations.

MySQL に関する注意

Django はデータベースがトランザクションや参照の一貫性 (referential integrity)、 Unicode (UTF-8 エンコーディング) をサポートしていることを想定 して書かれています。好運なことに、 MySQL バージョン 3.23 以降でこれらの機 能全てをサポートしています。従って、 3.23 や 4.0 をバックエンドとして使うの は可能なのですが、 4.1 や 5.0 を使った方がトラブルに巻き込まれにくいでしょ う。

MySQL 4.1

MySQL 4.1 では、文字セットのサポートを大幅に改良しています。 4.1 では、 データベース全体から、テーブル毎、カラム毎にいたるまで個別にデフォルトの文 字セットを指定できます。以前のバージョンでは、サーバ全体に対する文字セット の設定しかできませんでした。また、 4.1 になってはじめてオンザフライで文字セッ トを変更できるようになりました。 4.1 にはビューのサポートもありますが、 Django はまだこの機能をサポートしていません。

MySQL 5.0

MySQL 5.0 では、全てのデータベーススキーマに関する詳細なデータの入った information_schema というデータベースが追加されました。 information_schema が存在すると、 Django はこのデータベースに対して inspectdb 機能を適用します。 5.0 ではまた、ストアドプロシジャのサポート も追加されましたが、 Django はまだこの機能をサポートしていません。

ストレージエンジン

MySQL は複数の ストレージエンジン (以前はテーブルタイプ: table type と呼 ばれていたもの) を選択できます。デフォルトのストレージエンジンはサーバ設定 で変更できます。

デフォルトのストレージエンジンは MyISAM [1] です。 MyISAM の短所は、現状 ではトランザクションや外部キーをサポートしていないという点です。一方、 MyISAM は、現状で、全文インデクスの生成や全文検索をサポートしている唯一のス トレージエンジンでもあります。

InnoDB エンジンは完全なトランザクション機能と外部キー参照をサポートしてい ます。

BDB エンジンは InnoDB と同様、完全なトランザクション機能を外部キー参照をサ ポートしていますが、やや時代送れになりつつあるようです。

SolidDBFalcon といった その他のストレージエンジン まだまだ圏外の話です。現状では、おそらく InnoDB が最良の選択でしょう。

[1]お使いの MySQL パッケージでデフォルトが変更されていない場合。 Windows Community Server 向けのインストーラは、デフォルトのストレージエ ンジンを InnoDB にしているという報告があります。
MySQLdb

MySQLdb は Python から MySQL にアクセスするためのインタフェースです。 Django から利用できる MySQL の全ての機能を使うには、 バージョン 1.2.1p2 以 降が必要です。

Note

MySQLdb を Django から使おうとして ImportError: cannot import name ImmutableSet が出る場合は、おそらく MySQLdb に古い sets.py ファイルが入っていて、 Python 2.4 の同名の組 み込みモジュールと衝突しています。この問題を回避するには、 1.2.1p2 以降 の MySQLdb をインストールしてください。上書きインストールした場合には、 MySQLdb のインストールディレクトリを調べ、以前のバージョンの sets.py が入っていれば除去してください。

データベースを作成する

コマンドラインツールを使って、以下の SQL を発行すれば データベースを作成 できます:

CREATE DATABASE <dbname> CHARACTER SET utf8;

これで、全てのテーブルとカラムがデフォルトで UTF-8 を使うようになります。

コレーションに関する設定

カラムのコレーション設定は、データの保存方法や、文字列の等価性の定義を制御 しています。コレーションはデータベース全体でも、テーブル単位でも、カラム単 位でも設定できます。コレーションの詳細は MySQL のドキュメントで 詳しく解説されています 。いずれの場合でも、 コレーションの設定は直接データベーステーブルに対して行ってください。 Django はモデル定義でコレーションを設定する方法を提供していません。

デフォルトの構成では、 MySQL は UTF-8 のデータベースに対して utf8_general_ci_swedish コレーションを使います。この設定では、全ての文 字列の等値比較が 大小文字を区別 せず行われます。つまり、 "Fred""freD" はデータベースレベルでは同じ値だとみなされるのです。そのため、デ フォルトのコレーションを使っていると、フィールドに unique 制約をかけた ときに、 "aa""AA" は等しいとみなされ (一意性が破れるので) 同じ カラムに入れられなくなります。

大抵のケースでは、デフォルトの設定はさして問題を起こしません。しかし、特定 のカラムやテーブルで大小文字を区別させたいなら、そのカラムやテーブルに utf8_bin コレーションを指定せねばなりません。その場合、注意すべきなのは、 MySQLdb 1.2.2 を使っていると、 Django のデータベースバックエンドが、データ ベースから取り出した文字列フィールドの値として (unicode 文字列ではなく) bytestring を返すということです。このふるまいは、 常に unicode を返す、と いう Django の通常のやりかたから大きくかけ離れています。コレーションを utf8_bin にして、 bytestring を受け取ったときの扱いは、開発者に委ねられ ています。 Django 自体はこのカラムを問題なく扱えますが、一貫性をもってデー タを処理したければ、 django.utils.encoding.smart_unicode() を何度も 呼び出すことになるでしょう。(データベースバックエンドレイヤとモデルの操作レ イヤは内部的に分離しているため、変換が必要かどうかをデータベースレイヤでは 判断できないので) Django はこの変換に関知しないのです。

MySQLdb 1.2.1p2 を使っているなら、コレーションを utf8_bin にしても、 CharField は unicode 文字列を返します。しかし、 今度は TextField が (Python 標準モジュール array の) array.array を返します。データをデータベースから読み出す ときに、変換に必要な情報が手にはいらないので、 Django 側ではどうしようもあ りません。この問題は MySQLdb 1.2.2 で解決済み なので、 itf8_bin コレーションで TextField を使いたければ、バージョンを 1.2.2 に上げて、バイト文字列として扱うよう勧め ます (それほど難しくはありません)。

MySQLdb 1.2.1p2 で utf8_bin コレーションの設定されたテーブルを使うのな ら、 django.contrib.sessions.models.Session のテーブル (通常は django_session) や、 django.contrib.admin.models.LogEntry のテーブル (通常は django_admin_log) のコレーションに utf8_collation_ci_swedish (デフォルトのコレーション) を使わねばなりませ ん。これらは標準の Django のテーブルのうち、内部的に TextField を使っているからです。

データベースに接続する

設定に関するドキュメント を参照してください。

接続に関する設定は、以下の順に適用されます:

別の言い方をするなら、 DATABASE_OPTIONS 内にデータベースの名前を 設定すると、その内容は DATABASE_NAME よりも優先順位が高くなり、 さらに DATABASE_NAMEMySQL のオプション設定ファイル の内容 をオーバライドするということです。

MySQL のオプション設定ファイルを使う例を以下に示します:

# settings.py
DATABASE_ENGINE = "mysql"
DATABASE_OPTIONS = {
    'read_default_file': '/path/to/my.cnf',
}

# my.cnf
[client]
database = DATABASE_NAME
user = DATABASE_USER
password = DATABASE_PASSWORD
default-character-set = utf8

この他にも、MySQLdb の接続オプションには、 ssl, use_unicode, init_command, sql_mode といった便利なものがあります。詳しくは MySQLdb のドキュメント を参照してください。

テーブルを作成する

Django はスキーマを作成する際にストレージエンジンを指定しません。そのため、 テーブルは常にサーバに設定されたデフォルトのストレージエンジンで作成されま す。作成されるテーブルを特定のタイプにしたければ、データベースサーバのデフォ ルトストレージエンジンを Django で使いたいストレージエンジンに合わせるのが 一番簡単です。

ホスティングサービスを使っていて、サーバのデフォルトのストレージエンジンを 変更できない場合、二つの選択肢があります。

  • テーブルが作成された後に、以下のようなクエリを発行して、ストレージ エンジンを (InnoDB) などに変更します:

    ALTER TABLE <tablename> ENGINE=INNODB;
    

    テーブルが沢山ある場合には、これは相当骨がおれることでしょう。

  • あるいは、テーブルを作成する前に、 MySQLdb の init_command オプショ ンを使います:

    DATABASE_OPTIONS = {
       "init_command": "SET storage_engine=INNODB",
    }
    

    このように設定しておくと、接続時にデフォルトのストレージエンジンが変更 されます。ただし、テーブルが全て作成され、運用環境で動き始めたら、この オプションを外しておかねばなりません。

  • syncdb 時にストレージエンジンを変更するもう一つの方法は、 Wiki の AlterModelOnSyncDB に記載されています。

フィールドタイプごとの注意
BooleanField

MySQL には直接的な BOOLEAN カラム型がないので、 Django は BooleanField の値を TINYINT カラムを使って 0 または 1 で保存します。詳しくはモデルフィールドのドキュメントを参照してくだ さい。ただし、フィールドの値を出力したり、値が TrueFalse でなけ ればならないような場合を除いて、特に問題はありません。

Character fields

Any fields that are stored with VARCHAR column types have their max_length restricted to 255 characters if you are using unique=True for the field. This affects CharField, SlugField and CommaSeparatedIntegerField.

Furthermore, if you are using a version of MySQL prior to 5.0.3, all of those column types have a maximum length restriction of 255 characters, regardless of whether unique=True is specified or not.

SQLite に関する注意

SQLite provides an excellent development alternative for applications that are predominantly read-only or require a smaller installation footprint. As with all database servers, though, there are some differences that are specific to SQLite that you should be aware of.

String matching for non-ASCII strings

SQLite doesn’t support case-insensitive matching for non-ASCII strings. Some possible workarounds for this are documented at sqlite.org, but they are not utilised by the default SQLite backend in Django. Therefore, if you are using the iexact lookup type in your queryset filters, be aware that it will not work as expected for non-ASCII strings.

Version 3.5.9

The Ubuntu “Intrepid Ibex” (8.10) SQLite 3.5.9-3 package contains a bug that causes problems with the evaluation of query expressions. If you are using Ubuntu “Intrepid Ibex”, you will need to update the package to version 3.5.9-3ubuntu1 or newer (recommended) or find an alternate source for SQLite packages, or install SQLite from source.

At one time, Debian Lenny shipped with the same malfunctioning SQLite 3.5.9-3 package. However the Debian project has subsequently issued updated versions of the SQLite package that correct these bugs. If you find you are getting unexpected results under Debian, ensure you have updated your SQLite package to 3.5.9-5 or later.

The problem does not appear to exist with other versions of SQLite packaged with other operating systems.

Version 3.6.2

SQLite version 3.6.2 (released August 30, 2008) introduced a bug into SELECT DISTINCT handling that is triggered by, amongst other things, Django’s DateQuerySet (returned by the dates() method on a queryset).

You should avoid using this version of SQLite with Django. Either upgrade to 3.6.3 (released September 22, 2008) or later, or downgrade to an earlier version of SQLite.

Using newer versions of the SQLite DB-API 2.0 driver

For versions of Python 2.5 or newer that include sqlite3 in the standard library Django will now use a pysqlite2 interface in preference to sqlite3 if it finds one is available.

This provides the ability to upgrade both the DB-API 2.0 interface or SQLite 3 itself to versions newer than the ones included with your particular Python binary distribution, if needed.

“Database is locked” errors

SQLite is meant to be a lightweight database, and thus can’t support a high level of concurrency. OperationalError: database is locked errors indicate that your application is experiencing more concurrency than sqlite can handle in default configuration. This error means that one thread or process has an exclusive lock on the database connection and another thread timed out waiting for the lock the be released.

Python’s SQLite wrapper has a default timeout value that determines how long the second thread is allowed to wait on the lock before it times out and raises the OperationalError: database is locked error.

If you’re getting this error, you can solve it by:

  • Switching to another database backend. At a certain point SQLite becomes too “lite” for real-world applications, and these sorts of concurrency errors indicate you’ve reached that point.

  • Rewriting your code to reduce concurrency and ensure that database transactions are short-lived.

  • Increase the default timeout value by setting the timeout database option option:

    DATABASE_OPTIONS = {
        # ...
       "timeout": 20,
        # ...
    }
    

    This will simply make SQLite wait a bit longer before throwing “database is locked” errors; it won’t really do anything to solve them.

Oracle に関する注意

Django はバージョン 9i 以降の Oracle データベースサーバ をサポートしてい ます。 Django の regex および iregex クエリオペレータを使うには、 バージョン 10g 以降の Oracle を使う必要があります。 バージョン 4.3.1 以降の cx_Oracle ドライバが必要です。

Note that due to a Unicode-corruption bug in cx_Oracle 5.0, that version of the driver should not be used with Django; cx_Oracle 5.0.1 resolved this issue, so if you’d like to use a more recent cx_Oracle, use version 5.0.1.

Oracle で python manage.py syncdb コマンドを動かすには、データベースユー ザに以下のコマンドを実行できる権限が必要です:

  • CREATE TABLE
  • CREATE SEQUENCE
  • CREATE PROCEDURE
  • CREATE TRIGGER

Django のテストスイートを実行させるには、 さらに 以下の権限が必要です:

  • CREATE USER
  • DROP USER
  • CREATE TABLESPACE
  • DROP TABLESPACE
  • CONNECT WITH ADMIN OPTION
  • RESOURCE WITH ADMIN OPTION
データベースへの接続

Oracle を使う場合、 Django の settings.py は以下のように設定します:

DATABASE_ENGINE = 'oracle'
DATABASE_NAME = 'xe'
DATABASE_USER = 'a_user'
DATABASE_PASSWORD = 'a_password'
DATABASE_HOST = ''
DATABASE_PORT = ''

tnsnames.ora ファイルや、 SID として扱われる名前 (上の例では “xe”) を使わない場合は、以下のように DATABASE_HOST および DATABASE_PORT を設定してください:

DATABASE_ENGINE = 'oracle'
DATABASE_NAME = 'xe'
DATABASE_USER = 'a_user'
DATABASE_PASSWORD = 'a_password'
DATABASE_HOST = 'dbprod01ned.mycompany.com'
DATABASE_PORT = '1540'

DATABASE_HOSTDATABASE_PORT は、両方とも指定するか、 両方とも空にするかどちらかにしてください。

テーブルスペース

Oracle ベースのシステムでパフォーマンス向上に使われているパラダイムとして、 「 テーブルスペース (tablespace)」によるディスクレイアウトの構築がありま す。 db_tablespace オプションを MetaField クラスに追加する と、 Oracle バックエンドはテーブルスペースを利用します (バックエンドがテー ブルスペースをサポートしなければ、 Django はこのオプションを無視します)。

モデルのテーブルにテーブルスペースを指定するには、モデルの内部クラス Metadb_tablespace オプションを指定します。モデル全体とは別のテー ブルスペースをフィールドのカラムインデクスに指定したければ、フィールドのコ ンストラクタに db_tablespace を指定します。カラムごとにインデクスを生成 しない場合には、 db_tablespace オプションは無視されます:

class TablespaceExample(models.Model):
    name = models.CharField(max_length=30, db_index=True, db_tablespace="indexes")
    data = models.CharField(max_length=255, db_index=True)
    edges = models.ManyToManyField(to="self", db_tablespace="indexes")

    class Meta:
        db_tablespace = "tables"

上の例では、 TablespaceExample モデルの生成するテーブル (モデルテーブルと多対多のリレーションのテーブル) は、 tables という名前 のテーブルスペースに保存されます。 name フィールドと、多対多リレーショ ンテーブルのインデクスは indexes テーブルスペースに保存されます。 data フィールドもインデクスを生成しますが、このインデクスのテーブルスペー スは指定されていないので、デフォルトの挙動としてテーブルスペース tables に保存されます。

db_tablespace オプションのデフォルト値を指定するには、 DEFAULT_TABLESPACE および DEFAULT_INDEX_TABLESPACE 設 定を使います。これらの設定は、組み込みの Django アプリケーションや、ソース コードをいじれないアプリケーションに対してテーブルスペースを指定する場合に 便利です。

Django 自体にはテーブルスペースを作成する機能はありません。 テーブルスペースの作成や管理の方法は、 Oracle のドキュメント を参照して ください。

名前に関する制約

Oracle は名前の長さを 30 文字以下に制限しています。この制限に合わせるために、 バックエンドは識別子名を切り詰めて、最後の 4 文字を MD5 のハッシュ値で置き 換えます。

NULL 値よび空文字列

Django は通常、 NULL ではなく空文字列を使うようにしていますが、 Oracle はこ れらを別々のものとして扱います。この問題を回避するには、 Oracle バックエン ドは空文字列を値として受け入れるフィールドに null=Ture オプションを 強制的に付加します。データベースから値を取り出すとき、フィールドの値が NULL であれば、そのフィールドの値は実際には空文字列であるとみなし、値も暗黙のう ちに空文字列に変換されます。

TextField への制限

Oracle バックエンドは TextFieldNCLOB カラム形式で保存します。 Oracle は、一般に LOB カラムに以下の制約を課しています:

  • LOB カラムは主キーにできません。
  • LOB カラムはインデクス化に使えません。
  • LOB カラムは SELECT DISTINCT できません。従って、Oralce バックエン ドを使っていて、 TextField カラムを含むモデルに対して QuerySet.distinct を行うとエラーを引き起こします。このエラーを避け るには、 distinct() クエリの対象モデルから TextField を除去し、 TextField を持つ他のモデルを定義しておいてリレーションを張ってくだ さい。

Using a 3rd-party database backend

In addition to the officially supported databases, there are backends provided by 3rd parties that allow you to use other databases with Django:

The Django versions and ORM features supported by these unofficial backends vary considerably. Queries regarding the specific capabilities of these unofficial backends, along with any support queries, should be directed to the support channels provided by each 3rd party project.

django-admin.py と manage.py

revision-up-to:11321 (1.1) unfinished

django-admin.py は Django の管理タスクを行うためのコマンドライン ユーティリティです。このドキュメントでは django-admin.py の全ての 機能について説明します。

また、各 Django プロジェクトには manage.py が自動的に生成されます。 manage.pydjango-admin.py に対する薄いラッパで、 django-admin.py に仕事を引き渡す前に以下の二つの処理を行います:

  • プロジェクトのパッケージを sys.path に追加します。
  • DJANGO_SETTINGS_MODULE 環境変数がプロジェクトの settings.py を指すように設定します。

Django を setup.py ユーティリティでインストールしていれば、 django-admin.py スクリプトはシステムパス上にあるはずです。システム パス上にない場合、 Python インストールディレクトリ上の site-packages/django/bin を探せば見つかるでしょう。 /usr/local/bin のようなパス上のどこかにシンボリックリンクを張って おくように勧めます。

Windows を使っていて、シンボリックリンクを張れない場合には、パスの通った場 所に django-admin.py をコピーするか、 PATH の設定値を ( マイコンピュータ(右クリック) - プロパティ - 詳細設定 - 環境変数 - システム環境変数 で) django-admin.py のインストールされ ている場所を指すように変更してください。

一般論として、一つの Django プロジェクトだけで作業しているなら、 manage.py を使う方が簡単といえるでしょう。 django-admin.pyDJANGO_SETTINGS_MODULE--settings コマンドラインオプション を使えば、複数の Django 設定ファイルを切替えて操作できます。

このドキュメント内でのコマンドライン例では、一貫して django-admin.py を 使っていますが、実際には manage.py を使ってもかまいません。

使い方

django-admin.py <subcommand> [options]
manage.py <subcommand> [options]

subcommand には、このドキュメントで挙げているいずれかのサブコマンド を指定します。 options は省略可能で、このドキュメントで挙げている ゼロ個から複数個の利用可能なオプションをサブコマンドに与えます。

ランタイムヘルプを取得する
--help

django-admin.py help を実行すると、利用できる全てのサブコマンドを出力し ます。 django-admin.py help <subcommand> を実行すると、指定のサブコマン ドで利用できるオプションの詳細なリストを出力します。

アプリケーションの名前

多くのサブコマンドが appname のリストを引数にとります。 appname はモデルの入ったパッケージの名前です。例えば INSTALLED_APPSmysite.blog を追加している場合、このアプリケーションの appnameblog です。

バージョンを表示する
--version

django-admin.py --version を実行すると、使用しているDjangoのバージョンを表示します。

表示例:

0.95
0.96
0.97-pre-SVN-6069
デバッグ出力を表示する
--verbosity <amount>

django-admin.py の通知情報やデバッグ情報のコンソールへの出力量を指定する には --verbosity を使います。

  • 0 だと、何も出力しません。
  • 1 だと、通常の出力 (デフォルト) です。
  • 2 だと、詳細に出力します。

利用可能なサブコマンド

cleanup

cron によるジョブとして実行したり、直接実行したりして、データベースから 古いデータ (現時点では、有効期限の切れたセッションのみ) を消去します。

compilemessages
1.0 以前は “bin/compile-message.py” コマンドでした。

makemessages で作成した .po ファイルをコンパイルして、組み込みの gettext サポートで使えるようにします。詳しくは topics-i18n を参照し てください。

–locale

処理したいロケールを指定するには --locale または -l オプションを使 います。指定しなければ、全てのロケールを処理します。

使い方:

django-admin.py compilemessages --locale=br_PT
createcachetable
django-admin.py createcachetable <tablename>

データベースキャッシュバックエンドで使うための、 tablename という 名前のキャッシュテーブルを生成します。詳しくは Django のキャッシュフレームワーク を参照し てください。

createsuperuser
django-admin.py createsuperuser

スーパユーザアカウント (全てのパーミッションを保有するユーザ) を作成します。 初期スーパユーザを syncdb の実行時以外の場所で作成したい場合や、プログ ラム上でスーパユーザアカウントを生成したい場合に便利です。

対話的に実行すると、 django-admin.py コマンドはスーパユーザアカウントの パスワードを入力するよう促します。非対話的に実行した場合、パスワードは設定 されず、パスワードを手動で設定するまで、作成されたスーパユーザはログインで きません。

--username
--email

新たに作成するアカウントのユーザ名と e-mail アドレスは、それぞれ コマンドラインの --username および --email 引数で指定できます。 どちらの引数も指定しなければ、 createsuperuser は対話モードでの実行時に 入力を促します。

このコマンドは Django の 認証システム (django.contrib.auth) がインストールされている時にのみ利用可能です。

dbshell
django-admin.py dbshell

DATABASE_ENGINE 設定に指定されたデータベースエンジンに対し、 DATABASE_USER および DATABASE_PASSWORD 等の設定に従ってコマンドライ ンクライアントを起動します。

  • PostgreSQL の場合には psql を実行します。
  • MySQL の場合には mysql を実行します。
  • SQLite の場合には sqlite3 を実行します。

このコマンドはプログラムが PATH 上にあると想定しているので、単純に プログラム名で呼び出したとき (psql, mysql, sqlite3) に見つかる プログラムを使います。プログラムの場所を手動で指定する方法はありません。

diffsettings
django-admin.py diffsettings

現在の設定ファイルと Django のデフォルト設定との差分を表示します。

デフォルト設定にない設定の末尾には "###" を追加します。例えば、 デフォルト設定には ROOT_URLCONF 変数がないので、 diffsettings の出力中では ROOT_URLCONF の末尾に "###" が付きます。

デフォルト設定の完全なリストを見たければ、 django/conf/global_settings.py にある Django のデフォルト設定を参照して ください。

dumpdata
django-admin.py dumpdata <appname appname appname.Model ...>

指定したアプリケーション (複数指定可) に関係した全てのデータをデータベース から取り出し、標準出力に出力します。

アプリケーション名を指定しなかった場合、インストール済みのアプリケーション 全てのデータをダンプします。

dumpdata の出力は loaddata の入力に使えます。

dumpdata は、ダンプするレコードを取り出すときに、モデルのデフォルトマネ ジャを使います。デフォルトマネジャに カスタムマネジャ を使っていて、カスタムマネジャ内 でレコードの一部をフィルタしていると、一部のオブジェクトがダンプされなくな るので注意してください。

--exclude

出力から、特定のアプリケーションに関するコンテンツを除外します。例えば、 auth アプリケーションのコンテンツを出力から除外したければ、以下のように 実行します:

django-admin.py dumpdata --exclude=auth

複数のアプリケーションを除外したければ、複数回 --exclude ディレクティブ を使います:

django-admin.py dumpdata --exclude=auth --exclude=contenttype
--format <fmt>

デフォルトでは、 dumpdata は JSON 形式でデータを出力しますが、 --format オプションを使って別の形式を指定することもできます。現在サ ポートしているフォーマットは シリアライズの形式 に列挙されて います。

--indent <num>

デフォルトでは、 dumpdata はすべてのデータを1行で出力します。これは 人間にとって読みやすくありません。出力を整形するためのインデント幅のス ペース数の指定に --indent オプションを使えます。

In addition to specifying application names, you can provide a list of individual models, in the form of appname.Model. If you specify a model name to dumpdata, the dumped output will be restricted to that model, rather than the entire application. You can also mix application names and model names.

flush
django-admin.py flush

データベースを syncdb 直後の状態に戻します。全てのデータがデータベースから 除去され、同期直後に呼び出される全てのハンドラが再度実行されます。また、 initial_data フィクスチャも再インストールされます。

--noinput

ユーザプロンプトでの “Are you sure?” のような確認メッセージの出力の抑制 には --noinput オプションを使います。対話を必要とせずに django-admin.py を実行する自動化されたスクリプトで役に立ちます。

inspectdb
django-admin.py inspectdb

DATABASE_NAME 設定で指定されたデータベース上のテーブルに対するイントロ スペクションを行い、Django モデルモジュール (models.py) を標準出力に出 力します。

古いデータベースを持っていて、それを Django で使いたい場合に使ってくだ さい。スクリプトはデータベースを調べ、データベース内の各テーブルに対す るモデルを生成します。

想像の通り、生成されるモデルは、テーブルの各フィールド名に対応する属性 を持ちます。 inspectdb はフィールド名の出力に際して以下のようないく つかの特殊なケースを持っているので注意して下さい:

  • inspectdb があるカラムの型に対して適切なモデルのフィールド型 を決定できなかった場合、 TextField が使われ、生成されたモデ ルの該当するフィールド名の次の行に、 'This field type is a guess.' というコメントが入ります。
  • データベースのカラム名が Python の予約語 ('pass', 'class', 'for' など) の場合、 inspectdb は属性名の後ろに '_field' を追加します。例えば、テーブルに 'for' という名前のフィールドがあ れば、生成されるモデルは 'for_field' という名前のフィールドを持ち、 このフィールドの db_column 属性は 'for' になります。 inspectdb はフィールド名の次の行に、 'Field renamed because it was a Python reserved word.' というコメ ントを追加します。

この機能は単に手間を省くためのもので、しっかりしたモデル生成を行うため のものではありません。実行した後に生成されたモデルを自分で確かめてカス タマイズを行うことになるでしょう。具体的には、他のモデルを参照しているよう なモデルが正しい順番で並ぶようにします。

PostgreSQL や MySQL を使っている場合、イントロスペクションで主キーを自動的 に決定し、必要な場所に primary_key=True を追加します。

inspectdb は PostgreSQL, MySQL および SQLite で動作します。外部キー の検出は PostgreSQL と一部の MySQL テーブル形式でのみ有効です。

loaddata <fixture fixture ...>

名前付きのフィクスチャ (fixture) を探し、その中身をデータベースにロードします。

フィクスチャとは

フィクスチャ とは、データベースに入れるデータをシリアライズして 格納したファイル群を指します。各フィクスチャファイルには固有の名前を付けら れますが、ある名前のフィクスチャを複数のディレクトリに入れても構いませんし、 複数のアプリケーション内に配置してもかまいません。

Django は以下の 3 種類の場所からフィクスチャを探します:

  1. インストール済みの各アプリケーションの fixtures ディレクトリ
  2. FIXTURE_DIRS 設定に指定したディレクトリ
  3. fixture に直接指定したパス

Django は上記の場所に見つかった全てのフィクスチャファイルの中から、指定した フィクスチャ名と一致するファイルをロードします。

フィクスチャ名にファイル拡張子を指定すると、指定した型のフィクスチャだけが ロードされます。例えば:

django-admin.py loaddata mydata.json

のようにすると、 mydata という名前の JSON フィクスチャだけがロードされ ます。フィクスチャの拡張子は、 (jsonxml のように) シリアライザ の登録名に対応していなければな りません。

拡張子を省略すると、 Django は全ての形式にフィクスチャを対象にフィクスチャ ファイルを検索します。例えば:

django-admin.py loaddata mydata

のようにすると、 mydata という名前の全てのフィクスチャを探します。フィ クスチャディレクトリに mudata.json という名前のファイルがあれば、 JSON 形式のフィクスチャとしてロードされます。

フィクスチャの名前にはディレクトリ名を入れても構いません。ディレクトリ部分 を指定すると、各検索パスに追加されます。例えば:

django-admin.py loaddata foo/bar/mydata.json

とすると、インストール済みの各アプリケーションのディレクトリ <appname> について <appname>/fixtures/foo/bar/mydata.json を、 FIXTURE_DIRS の各ディレクトリ <dirname> について <dirname>/foo/bar/mydata.json を、そして相対パス foo/bar/mydata.json を探します。

フィクスチャファイルを処理する際、データはデータベースにそのまま保存され、 モデルごとに定義した save メソッドや pre_save シグナルは呼び出され ません。

フィクスチャファイルの処理順は決まっていませんが、全てのフィクスチャのイン ストールは単一のトランザクションで行われるため、あるフィクスチャが別のフィ クスチャに対する参照を持っていてもかまいません。データベースバックエンドが 行レベルの制約 (row-level constraint) をサポートしているばあい、制約はトラ ンザクションの最後にチェックされます。

dumpdata コマンドを使うと、 loaddata の入力データを生成できます。

Compressed fixtures

Fixtures may be compressed in zip, gz, or bz2 format. For example:

django-admin.py loaddata mydata.json

would look for any of mydata.json, mydata.json.zip, mydata.json.gz, or mydata.json.bz2. The first file contained within a zip-compressed archive is used.

同じ名前で別のフィクスチャ形式のものが見つかった場合 (例えば、 mydata.jsonmydata.xml.gz が同じディレクトリ下にあった場合)、フィ クスチャのインストールは中止され、それまでに loaddata によってロードさ れたデータは全てデータベースから削除されます。

MySQL とフィクスチャ

残念ながら、MySQL は Django のフィクスチャに関する全ての機能を利用でき るわけではありません。 MyISAM を使っている場合、 MySQL はトランザクショ ンや制約をサポートしていないので、複数のフィクスチャファイルに対するロー ルバックを行えず、フィクスチャデータの検証も行えません。一方、 InnoDB を使っている場合、データファイル間で前方参照を行えません。 MySQL は行制 約のチェックをトランザクションコミット直前まで遅延するためのメカニズム を備えていないからです。

makemessages
1.0 より前のバージョンでは、 bin/make-messages.py コマンドでした。

現在のディレクトリ以下にあるソースツリー全体を走査して、翻訳対象にマークさ れている文字列全てを取り出します。django のソースツリー上で行った場合には conf/locale 下に、プロジェクトやアプリケーションのソースツリー上で行っ た場合には locale 下にメッセージファイルを作成します。メッセージファイ ルに変更があった場合、 compilemessages でファイルをコンパイルして、組み 込みの gettext サポートで利用できるようにしてください。詳しくは i18n のドキュメント を参照してください。

–all

全ての言語のメッセージファイルを更新するには --all または -a を使っ てください。

使い方:

django-admin.py makemessages --all
–extension

メッセージを取り出す対象に含めるファイルの拡張子を指定するには --extension または -e オプションを使います(デフォルトは ”.html” で す)。

使い方:

django-admin.py makemessages --locale=de --extension xhtml

複数の拡張子を指定するには、カンマで区切るか、 --extension-e を複数使います:

django-admin.py makemessages --locale=de --extension=html,txt --extension xml
–locale

処理したいロケールを指定するには --locale または -l オプションを使 います。

使い方:

django-admin.py makemessages --locale=br_PT
–domain

メッセージファイルのドメインを変更するには --domain または -d オプ ションを使ってください。

現在サポートしているのは、以下のドメインです:

  • django: *.py ファイルと *.html ファイル (デフォルト)
  • djangojs: *.js ファイル
reset <appname appname ...>

指定した appname に対して sqlreset と同じ操作を実行します。

–noinput

ユーザプロンプトでの “Are you sure?” のような確認メッセージの出力の抑制には --noinput オプションを使います。対話を必要とせずに django-admin.py を実行する自動化されたスクリプトで役に立ちます。

runfcgi [options]

FastCGI プロトコルをサポートする Web サーバ向けの一連の FastCGI プロセス群 を起動します。詳しくは FastCGI による運用 を参照してください。 Python の FastCGI インタフェースモジュールである flup が必要です。

runserver
django-admin.py runserver [port or ipaddr:port]

ローカルマシン上に軽量な開発用ウェブサーバを立ち上げます。デフォルトでは、 サーバは IP アドレス 127.0.0.1、ポート番号 8000 で動作します。 IP アドレス やポート番号は明示的に指定できます。

このスクリプトを通常ユーザの権限下で実行した場合 (そうするように勧めます)、 ポート番号を低い値にできないかもしれません。値の低いポート番号はスーパユー ザ (root) 用に予約されているからです。

開発用サーバをプロダクションサーバとして使ってはなりません。 開発用サー バはセキュリティ検査もパフォーマンステストも行われていません(我々が目指して いるのは Web フレームワークの開発であり、このサーバを改良して運用環境でも利 用できるようにするのは Django プロジェクトの目的とするところではありません。)

開発サーバはリクエストを受け付ける度に、必要に応じて自動的に Python コード をリロードします。このため、コードの変更を反映させるためにいちいちサーバを 際起動しなくてもよくなっています。

サーバの起動時や、サーバの稼働中に Python コードを変更した場合、開発用サー バはインストールされている全てのモデルを自動的に検証します (後述の validate オプションを参照してください)。検証時にエラーが見つかった場合、 エラーは標準出力に出力されますが、サーバは停止しません。

ポート番号を別々にしているかぎりいくつでもサーバを起動できます。 django-admin.py runserver を複数回起動するだけです。

デフォルトの IP アドレスである 127.0.0.1 は、ネットワーク上の他のマシンから は利用できません。開発サーバをネットワーク上の他のマシンから見えるようにす るには、サーバホスト固有の IP アドレス (例えば 192.168.2.1) または 0.0.0.0 を使って下さい。

--adminmedia

Django 管理インタフェース用の CSS や JavaScript ファイルを探す場所を Django に 教えるには --adminmedia オプションを使います。通常、これらのファイルは Django のソースツリーから探索されて配信されるようになっていますが、自作のサイト 用に変更を加えた CSS や JavaScript を指定したい場合には、このオプションを使いま す。

使用例:

django-admin.py runserver --adminmedia=/tmp/new-admin-style/
--noreload

自動リロード機能の使用を無効にするには --noreload オプションを使います。 これが意味するところは、サーバの稼働中にいかなる Python コードの変更も検知 せず 既にメモリ上に読み込まれている Python モジュールが利用されます。

使用例:

django-admin.py runserver --noreload
異なる IP アドレスとポート番号を使用する例

IP アドレス 127.0.0.1、ポート番号 8000:

django-admin.py runserver

IP アドレス 1.2.3.4、ポート番号 8000:

django-admin.py runserver 1.2.3.4:8000

IP アドレス 127.0.0.1、ポート番号 7000:

django-admin.py runserver 7000

IP アドレス 1.2.3.4、ポート番号 7000:

django-admin.py runserver 1.2.3.4:7000
開発用サーバで静的なファイルを提供する

デフォルトでは、開発用サーバはサイト用の静的ファイル (CSSファイル、画像、 MEDIA_URL 下のファイルなど) を全く提供しません。 Django に静的メディ アを提供させたければ、 静的なファイルの提供方法 を参照してください。

shell

Python の対話インタプリタを起動します。

IPython がインストールされている場合、Django は IPython を使おうとします。 IPython がインストールされていて、かつ「普通の」インタプリタを使いたいのな ら、以下のように --plain オプションを使って下さい:

django-admin.py shell --plain
sql <appname appname ...>

指定した appname の CREATE TABLE SQL 文を出力します。

sqlall <appname appname ...>

指定した appname の CREATE TABLE および初期カスタム SQL の発行、データ入力 のための SQL 文を出力します。

初期カスタム SQL の指定方法は sqlcustom の説明を参照してください。

sqlclear <appname appname ...>

指定した appname の DROP TABLE SQL 文を出力します。

sqlcustom <appname appname ...>

指定した appname のカスタム SQL 文を出力します。

このコマンドは、指定した各アプリケーションのモデルについて、 <appname> をアプリケーションの名前、 <modelname> をモデルの名前を全て小文字にした 文字列として、 <appname>/sql/<modelname>.sql という名前のファイルを探し ます。例えば、 news というアプリケーションで Story というモデルが定 義されていれば、 sqlcustomnews/sql/story.sql というファイルを探 して読みだし、その内容をこのコマンドの出力の末尾に追加します。

各 SQL ファイルには、有効な SQL を入れることになっています。 SQL ファイルの 内容は、モデルのテーブル生成文を全て実行した後に、データベースに直接パイプ されます。テーブルに対して変更を加えたり、 SQL 関数をデータベースに組み込む には、この SQL フックを使ってください。

SQL ファイルの処理順には決まりがありません。

sqlflush

flush コマンドによって実行されるのと等価な SQL 文を出力します。

sqlindexes <appname appname ...>

指定したアプリケーションに対する CREATE INDEX SQL 文を出力します。

sqlreset <appname appname ...>

指定した appname に対する DROP TABLE SQL 文を出力し、 その後で CREATE TABLE SQL 文を出力します。

sqlsequencereset <appname appname ...>

指定した appname のシークエンスをリセットするためのSQL 文を出力します。

Sequences are indexes used by some database engines to track the next available number for automatically incremented fields.

Use this command to generate SQL which will fix cases where a sequence is out of sync with its automatically incremented field data.

startapp <appname>

現在のディレクトリに、 appname に指定した名前の Django アプリケーショ ンディレクトリ階層を作成します。

startproject <projectname>

現在のディレクトリに、 projectname に指定した名前の Django プロジェク トディレクトリ階層を作成します。

--settings オプションを指定して django-admin.py を呼び出したときや、 環境変数 DJANGO_SETTINGS_MODULE が指定されていると、このコマンドを使え ません。 startproject を使いたければ、 --settings オプションを外し、 DJANGO_SETTINGS_MODULE を unset してください。

syncdb

INSTALLED_APPS に登録されており、まだテーブルを作成していないアプリケー ション全てのテーブルを作成します。

このコマンドは、新たなアプリケーションをプロジェクトに追加し、データベース にインストールしたい場合に使って下さい。アプリケーションには、 Django に付 属しているアプリケーションで、デフォルトで INSTALLED_APPS に入っている ものも含みます。新たなプロジェクトを開始する際には、このコマンドを実行して デフォルトのアプリケーションをインストールする必要があります。

syncdb は既存のテーブルを置き換えません

syncdb は、インストールされていないモデルのテーブルしか作成しません。 すでにインストールされているモデルクラスに変更を行っても、それに合わせる ように ALTER TABLE を発行することは 決してありません 。モデルクラ スやデータベーススキーマに対する変更には、何らかの形であいまいな部分があ るものです。そのあいまいな部分に対して、 Django どのように変更を適用すべ きか正しく判断せねばならないとすれば、変更の過程で重要なデータが失われる というリスクが生まれてしまいます。

モデルに変更を適用した後、変更に合わせてデータベーステーブルも置き換えた いのなら、 sql コマンドを使って新たな SQL を出力し、既存のテーブルス キーマと比較して、手動で変更を適用してください。

django.contrib.auth アプリケーションをインストールした場合には、 syncdb はスーパユーザを作成するか尋ねます。

syncdb はまた、 initial_data という名前で、適切な拡張子 (jsonxml など) のフィクスチャを探してインストールします。フィクスチャデー タファイルの詳細は loaddata のドキュメントを参照してください。

–noinput

ユーザプロンプトでの “Are you sure?” のような確認メッセージの出力の抑制には --noinput オプションを使います。対話を必要とせずに django-admin.py を実行する自動化されたスクリプトで役に立ちます。

test

インストールされている全てのモデルについてテストを実行します。 詳しくは Django アプリケーションのテスト を参照して ください。

–noinput

ユーザプロンプトでの “Are you sure?” のような確認メッセージの出力の抑制には --noinput オプションを使います。対話を必要とせずに django-admin.py を実行する自動化されたスクリプトで役に立ちます。

testserver <fixture fixture ...>

指定したフィクスチャを使って、 (runserver と同様に) 開発用サーバを起動 します。

例えば、次のコマンド:

django-admin.py testserver mydata.json

を実行すると、以下のようなステップを実行します:

  1. Djangoアプリケーションのテスト 手順に従って、テストデータベース を生成します。
  2. 指定したフィクスチャを使ってテストデータベースに値を入れます (フィク スチャの説明は loaddata ドキュメントを参照してください)。
  3. 生成したテストデータベースを使って (runserver と同様に) 開発サー バを実行します。

testserver が便利な局面はいくつかあります:

  • 特定のフィクスチャデータに対するビューの動作を調べるための ユニットテスト を書いている際に、ブラウザでの 表示を手動で調べるのに testserver を使えます。
  • Django アプリケーションを開発していて、「無垢の状態の」データベースを 使って操作してみたいとしましょう。データベースを (前述の dumpdata コマンドを使って) フィクスチャとしてダンプしておき、 testserver を使って Web アプリケーションを実行すれば、アプリケーション上でどんな 操作を行っても、変更はテストデータベースにしか加えられないので、好き にデータベースを「汚せ」ます。

runserver は動作中に Python のソースコード上に加えられた変更を自動的に 検出しますが、 testserver は検出しません。ただし、テンプレートへの変更 は検出します。

–addrport [port number or ipaddr:port]

IP アドレスやポート番号を 127.0.0.1:8000 から変更するには、 --addrport を使います。この値は、 runserver サブコマンドの引数と同じ形式で指定し、 意味も同じです。

テストサーバをポート 7000 で起動し、 fixture1 および fixture2 のテ ストを実施するには、以下のようにします:

django-admin.py testserver --addrport 7000 fixture1 fixture2
django-admin.py testserver fixture1 fixture2 --addrport 7000

(上の二つのコマンドは互いに等価です。オプションはフィクスチャを指定するため の引数の前にきても後ろに来てもかまいません。)

test フィクスチャを 1.2.3.4:7000 で実行するには、以下のようにします:

django-admin.py testserver --addrport 1.2.3.4:7000 test
validate

インストールされている (INSTALLED_APPS に登録されている) 全てのモ デルを検証 (validate) し、エラーがあれば標準出力に出力します。

デフォルトのオプション

各々のサブコマンドの独自のオプションの他に、以下の共通のオプションがありま す:

–pythonpath

使用例:

django-admin.py syncdb --pythonpath='/home/djangoprojects/myproject'

指定したファイルシステムパスを Python の import 検索パス に追加 します。このオプションを指定しない場合、 django-admin.py は環境変 数 PYTHONPATH を使います。

manage.py は Python パスをきちんと設定してくれるので、このオプション は必要ありません。

–settings

使用例:

django-admin.py init --settings=mysite.settings

管理対象のプロジェクトの設定モジュールを明示的に指定します。設定モジュー ルは Python のパッケージ表現構文、すなわち “mysite.settings” のような形式で 指定します。このオプションを指定しない場合、 django-admin.py は環境変数 DJANGO_SETTINGS_MODULE を使います。

manage.py はデフォルトで現在のプロジェクトの settings.py を使うので、 通常はこのオプションは必要ありません。

–traceback

使用例:

django-admin.py syncdb --traceback

デフォルトでは、 django-admin.py はエラーが起きるたびに簡単なエラーメッ セージを表示します。 --traceback を指定すると django-admin.py は 例外が送出された際に完全なスタックトレースを出力します。

–verbosity

django-admin.py のメッセージの通知やデバッグ情報のコンソールへの出力量を 指定するには --verbosity を使います。

  • 0 だと、何も出力しません。
  • 1 だと、通常の出力 (デフォルト) です。
  • 2 だと、詳細に出力します。

使用例:

django-admin.py loaddata --verbosity=2

その他のからくり

シンタクスの色づけ

SQL 文を標準出力に出力する django-admin.py / manage.py コマンドは、 端末が ANSI カラー出力をサポートする場合にはコードを色づけして表示します。 ただし、出力を別のプログラムにパイプしている場合には色づけを行いません。

bash での補完

bash シェルを使っているのなら、 Django の bash 補完スクリプトのインストール を検討してみてください。スクリプトは Django 配布物の extras/django_bash_completion にあります。 bash 補完機能を使うと、 django-admin.py および manage.py コマンドをタブ補完できるようになり ます。例えば:

  • django-admin.py とタイプします。
  • [TAB] を押すと、利用可能な全てのオプションを表示します。
  • sql とタイプして [TAB] を押すと、 sql で始まる全てのオプショ ンを表示します。

アクションを自作するには、 アクションを自作する を参照し てください。

ファイル操作 API リファレンス

revision-up-to:11321 (1.1)

File オブジェクト

revision-up-to:11321 (1.1)
class File(file_object)
属性とメソッド

Django の File 型は、以下の属性とメソッドを備えています:

File.name

MEDIA_ROOT からの相対パスを含む、ファイルの名前です。

File.path

ローカルのファイルシステムにおけるファイルの絶対パスです。

カスタムのファイルストレージシステム の場合、必ずしもローカルにファイルを保存しません。ローカルにファイルを 保存しないシステムでは、 pathNone です。

File.url

ファイルを取得できる URL です。 templates で 使う場合に便利です。例えば、ファイル topics-filesCar の例で、車の写真を表示するテンプレートは以下のように書けます:

<img src='{{ car.photo.url }}' alt='{{ car.name }}' />
File.size

バイト単位のファイルサイズです。

File.open(mode=None)

ファイルをオープンまたは再オープン (かつ File.seek(0)) します。 mode 引数には、 Python の標準の関数 open() と同じ引数を指定でき ます。

ファイルを再オープンした場合、 mode は最初にオープンしたときのファ イルモードをオーバライドします。 None を指定すると、最初のモードと 同じモードを使います。

File.read(num_bytes=None)

ファイルからコンテンツを読み出します。オプションの num_bytes は読み出すデータの長さです。指定しなければ、末尾まで読み出します。

File.__iter__()

ファイルを一度に一行づつ繰り返して読み出します。

File.chunks(chunk_size=None)

ファイルを chunk_size に指定したサイズのチャンク (“chunk”) づつ繰り 返して読み出します。 chunk_size のデフォルトサイズは 64KB です。

このメソッドは、ファイル全体をメモリに保存しなくても、ディスクからスト リーム読み出しできるので、巨大なファイルを読むときに便利です。

File.multiple_chunks(chunk_size=None)

ファイルが大きくて、長さ chunk_size のチャンクに分けて複数回アクセ スできる場合に True を返します。

File.write(content)

content に指定した文字列をファイルに書き込みます。背後にあるストレー ジシステムによっては、 close() を呼ぶまで content がコミットさ れない場合があります。

File.close()

ファイルを閉じます。

ImageField 固有の属性
File.width

画像の幅です。

File.height

画像の高さです。

オブジェクトに結び付いているファイル特有のメソッド

(Car.photo のように) オブジェクトに結び付いてる File には、 以下の二つのメソッドがあります:

File.save(name, content, save=True)

ファイル名 name とコンテンツ content を使って新たなファイルを生 成し、保存します。このメソッドは既存のファイルを置き換えるのではなく、 新たなファイルを作成して、オブジェクトがそのファイルを指すようにします。 saveTrue にすると、ファイルが保存されたときに save() メ ソッドを呼び出します。すなわち、以下の 2 行:

>>> car.photo.save('myphoto.jpg', contents, save=False)
>>> car.save()

は、以下の 1 行と同じです:

>>> car.photo.save('myphoto.jpg', contents, save=True)

content 引数は File またはそのサブクラスのインスタンスでな ければなりません。

File.delete(save=True)

ファイルをモデルインスタンスから除去して、背後にあるファイルも削除しま す。 save 引数は上のメソッドと同じです。

ファイルストレージ API

revision-up-to:11321 (1.1)
Storage.exists(name)

name に指定した名前のファイルが存在する場合に True を返します。

Storage.path(name)

ローカルファイルシステム上のパスです。このパスは、 Python 標準の open() で開けます。ストレージシステムにローカルファイルシステム経由でアクセスでき ない場合、この関数は NotImplementedError を送出します。

Storage.size(name)

名前が name のファイルのサイズをバイト単位で返します。

Storage.url(name)

名前が name のファイルのコンテンツにアクセスするための URL を返します。

Storage.open(name, mode='rb')

名前が name のファイルを開きます。このメソッドが返すオブジェクトは必ず File クラスまたはサブクラスであると保証されていますが、リモートのファイ ルストレージにアクセスするサブクラスの場合、読み書きが極めて遅くなるかもし れないので注意してください。

Storage.save(name, content)

ストレージシステムを使って name に指定した名前の新たなファイルを保存し ます。 name と同じ名前のファイルがすでに存在する場合、ストレージシステ ムはファイル名を変更して、一意な名前に付け変えます。実際に作成されたファイ ルの名前を返します。

content 引数は、 django.db.files.File クラスかサブクラスの インスタンスでなければなりません。

Storage.delete(name)

名前が name のファイルを削除します。ファイルが存在しなくても、例外を送 出しません。

フォーム API

revision-up-to:11321 (1.1)

フォーム API のリファレンスです。フォームの解説は、 フォームの操作 を参照してください。

フォーム API

revision-up-to:11321 (1.1) unfinished

このドキュメントについて

このドキュメントでは、 Django のフォーム API の細かい部分を解説していま す。まずは フォーム処理入門 を先に読んでく ださい。

束縛フォームと非束縛フォーム

フォームのインスタンスには、何らかのデータの集まりが結び付いた 束縛 (bound) フォーム と、そうでない 非束縛 (unbound) フォーム があ ります。

  • データと 結び付いている フォームは、データを検証機能する機能と、 フォームを HTML にレンダリングするときにデータを HTML 形式で表示する 機能をあわせ持っています。
  • データと 結び付いていない フォームには検証機能はありません (検証 すべきデータがないから当然ですね!) が、空のフォームを HTML としてレン ダリングする機能は備えています。

非束縛フォームのインスタンスを生成するには、単にフォームクラスのインスタン ス化を行います:

>>> f = ContactForm()

フォームにデータを結び付けるには、データの入った辞書をフォームクラスのコン ストラクタの第一引数に渡します:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)

この辞書の中では、キーは各フィールドの名前であり、フォームクラスの各属性に 対応しています。値は検証すべきデータです。通常、値は文字列にしますが、必ず しも文字列でなくてかまいません。値にどんなデータ型を指定指定できるかは、フィー ルドの型に依存します。

Form.is_bound

実行時に束縛フォームと非束縛フォームを区別したければ、フォームの is_bound 属性を調べてください:

>>> f = ContactForm()
>>> f.is_bound
False
>>> f = ContactForm({'subject': 'hello'})
>>> f.is_bound
True

空の辞書を渡すと、空のデータの入った 束縛フォーム を返します:

>>> f = ContactForm({})
>>> f.is_bound
True

束縛フォームのインスタンスに入っているデータに何らかの変更を加えたい場合や、 束縛フォームを変換して、何らかのデータの入った非束縛フォームにしたい場合に は、新たにフォームインスタンスを生成してください。フォームインスタンス内の データを変更する方法はありません。一度フォームインスタンスを生成したら、デー タの有無に関わらず、インスタンス内のデータは変更不能だと考えてください。

フォームを使ってデータを検証する
Form.is_valid()

フォームオブジェクトの主要な役割はデータの検証です。束縛フォームのインスタ ンスに対して is_valid() メソッドを呼び出すと、データの検証を 行って、その結果をブール値で返します:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True

無効なデータを入れてみましょう。例えば、 subject を空にしてみます (フィールドは全てデフォルトで必須なためエラーになります)。また、 sender に不正なメールアドレス情報を入れてみます:

>>> data = {'subject': '',
...         'message': 'Hi there',
...         'sender': 'invalid e-mail address',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
Form.errors

errors という属性にアクセスすると、エラーメッセージの入った辞 書を参照できます:

>>> f.errors
{'sender': [u'Enter a valid e-mail address.'], 'subject': [u'This field is required.']}

この辞書では、フィールド名がキーに、エラーメッセージを表す Unicode 文字列のリ ストが値になっています。エラーメッセージがリストになっているのは、一つのフィー ルドに対して複数のエラーが存在し得るからです。

is_valid() を呼ばなくても errors にはアクセスで きます。 is_valid() を呼び出すか、 errors に最 初にアクセスした時点で、フォームのデータが自動的に検証されます。

errorsis_valid() に何度アクセスしても、検証 のルーチンはたった一度しか呼ばれません。別の見方をすれば、検証の処理には副 作用があり、その副作用はたった一度しか呼び出されないということです。

非束縛フォームの動作

データを含まないフォームに対して “cleaned” を実行しても無意味でしかありませ んが、参考までに非束縛フォームに対して行ったときの動作を示しておきます:

>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}
Dynamic initial values
Form.initial

Use initial to declare the initial value of form fields at runtime. For example, you might want to fill in a username field with the username of the current session.

To accomplish this, use the initial argument to a Form. This argument, if given, should be a dictionary mapping field names to initial values. Only include the fields for which you’re specifying an initial value; it’s not necessary to include every field in your form. For example:

>>> f = ContactForm(initial={'subject': 'Hi there!'})

These values are only displayed for unbound forms, and they’re not used as fallback values if a particular value isn’t provided.

Note that if a Field defines initial and you include initial when instantiating the Form, then the latter initial will have precedence. In this example, initial is provided both at the field level and at the form instance level, and the latter gets precedence:

>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial='class')
...     url = forms.URLField()
...     comment = forms.CharField()
>>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="instance" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
「クリーニング済み」のデータにアクセスする

フォームクラスの各フィールドには、データの検証だけでなく、「クリーニング」 を行う役割もあります。データのクリーニングとは、データを一貫性のある書式に 正規化することです。データのクリーニングはとても素晴らしい機能で、クリーニ ングを行うと、ユーザがフィールドに色々な形式でデータを入力しても、常に一貫 性を持った出力を得られます。

例えば、 DateField はデータを Python の datetime.date オブジェクト に正規化します。フィールドの値は、 '1994-07-15' のような形式の文字列で も、 datetime.date オブジェクトでも、その他の形式でも、 DateField は有効なデータであるかぎり、常に出力を datetime.date オブジェクトで正規 化します。

データセットの入ったフォームインスタンスを生成して検証を行うと、 cleaned_data 属性を介してクリーニング済みのデータにアクセスできるようにな ります:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
cleaned_data 属性は、以前のリリースでは clean_data と呼ばれてい ました。

CharFieldEmailField のようなテキストベースのフィールドは、常に 入力を Unicode 文字列に変換します。エンコーディングに関する解説は、このドキュ メントの後の方でカバーする予定です。

データが まだ検証されていない 場合、フォームインスタンスには cleaned_data 属性がありません:

>>> data = {'subject': '',
...         'message': 'Hi there',
...         'sender': 'invalid e-mail address',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
>>> f.cleaned_data
Traceback (most recent call last):
...
AttributeError: 'ContactForm' object has no attribute 'cleaned_data'

フォームを生成するときに追加の値を渡した場合でも、 cleaned_data の中に 入るキーは、フォーム内で定義されているフィールド だけ です。以下の例でも、 ContactForm のコンストラクタに追加のフィールドデータを渡していますが、 cleaned_data が返すのは ContactForm で定義されているフィールドだけで す:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True,
...         'extra_field_1': 'foo',
...         'extra_field_2': 'bar',
...         'extra_field_3': 'baz'}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}

cleaned_data には、 Form 内で定義されている 全ての フィールドのキー と値が入ります。フォームに渡したデータに、必須でないフィールドの値が入って いない場合でもです。下の例では、データ辞書には nick_name フィールドの値 が入っていませんが、 cleaned_data には空の値が入っています:

>>> class OptionalPersonForm(Form):
...     first_name = CharField()
...     last_name = CharField()
...     nick_name = CharField(required=False)
>>> data = {'first_name': u'John', 'last_name': u'Lennon'}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}

この例で、 cleaned_data の中の nick_name は空文字列なのは、 nick_nameCharField であり、 CharField は空の値を空文字列と みなすからです。各フィールドタイプは「空の」値が設定されています。例えば、 DateField の場合、空の値は空文字列ではなく None になります。 空の値を持ったフィールドの詳しい挙動は、「組み込みフィールドクラス」の節の 各フィールドの説明中の「空のフォームデータに対する値」の項目を参照してくだ さい。

個別のフォームフィールド (フィールド名ごと) やフォーム全体 (複数フィールド の組み合わせ) に対してバリデーションを実現するコードを書けます。詳しくは、 フォームやフィールドのバリデーション を参照してください。

フォームを HTML として出力する

フォームオブジェクトの二つ目の仕事は、フォームの HTML へのレンダリングです。 フォームを HTML として出力するには、フォームをインスタンス化して、 print で出力します:

>>> f = ContactForm()
>>> print f
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>

束縛フォームの場合、フォームのデータは適切な形で HTML 出力されます。例えば、 フィールドが <input type="text"> で表される場合、データは value 属 性の中に出力されます。フィールドが <input type="checkbox"> であれば、 必要に応じて checked="checked" が入ります:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> print f
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" value="foo@example.com" /></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" checked="checked" /></td></tr>

デフォルトの出力は 2 カラムの HTML テーブルになり、各フィールドが一つの <tr> タグの中に収まります。以下の点に注意してください:

  • 柔軟性をもたせるために、出力中には <table></table> タグが 入っていません。また、 <form></form> や、 <input type="submit"> もありません。これらのタグは自分で入れる必 要があります。
  • 各フィールドタイプには、それぞれデフォルトの HTML 表現があります。 CharFieldEmailField<input type="text"> で表され、 BooleanField<input type="checkbox"> になります。とはいえ、 これらは便利なデフォルト値にすぎません。ウィジェット (widget) を使え ば、フィールドの表現にどのような HTML を使うかを指定できます。これに ついては後で説明する予定です。
  • 各タグの name 属性は ContactForm クラスの属性名から直接取り出 して使われます。
  • 'Subject:', 'Message:', 'Cc myself:' といった各フィール ドのテキストラベルは、フィールド名のアンダースコアを全てスペースに変 換し、先頭の文字を大文字にして生成します。これもまたデフォルト値にす ぎず、手動でもラベルを設定できるようになっています。
  • 各テキストラベルは HTML の <label> タグで囲われています。このタグ には for 属性が付いていて、対応するフォームフィールドの id 属 性に対応しています。属性の値はフィールド名の前に 'id_' を付けたも のになります。 id 属性や <label> タグはフォーム生成の定石に従っ て組み込まれているものですが、この振舞は自分で変更できます。

テーブル組みによる出力は print した時に出力されるデフォルトで、他にもい くつか出力スタイルがあります。各スタイルはフォームオブジェクトのメソッドと して利用でき、各々のレンダリングメソッドは Unicode オブジェクトを返すように なっています。

as_p()

Form.as_p() はフォームを一連の <p> タグの集まりで組みます。各 <p> タグの中に一つのフィールドが入ります:

>>> f = ContactForm()
>>> f.as_p()
u'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>'
>>> print f.as_p()
<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
as_ul()

Form.as_ul() はフォームを一連の <li> タグで組みます。各 <li> タ グの中に一つのフィールドが入ります。 as_ul()<ul></ul> を出力に 含めません 。これは、ユーザが <ul> タグの HTML 属性を好きに 指定できるようにするためです:

>>> f = ContactForm()
>>> f.as_ul()
u'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>'
>>> print f.as_ul()
<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>
<li><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></li>
<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>
as_table()

最後に、 Form.as_table() はフォームを <table> で組みます。これは print で出力したときに使われる形式と同じです。実際、フォームオブジェク トを print すると、背後では as_table() が呼び出されるようになってい ます:

>>> f = ContactForm()
>>> f.as_table()
u'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>'
>>> print f.as_table()
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="text" name="sender" id="id_sender" /></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>
<label> タグの出力設定

<label> タグは、あるラベルテキストがどのフォーム要素に対応づけられてい るかを知らせるタグです。 <label> タグがあると、フォームの利便性が増し、 入力補助デバイスで操作しやすくなります。 <label> タグは常に使うようにし ておくよう勧めます。

デフォルトでは、フォームのレンダリングメソッドを呼び出すと、各フォーム要素 に id 属性が追加され、ラベルを <label> タグで囲って出力します。 id 属性の値はフォームのフィールド名の前に id_ を付けたものになりま す。とはいえ、 id 属性の命名規則を変えたり、そもそも <label> を出力 したくない人のために、この仕様は設定変更できるようになっています。

<label> タグや id の挙動を変更するには、 Form コンストラクタの auto_id 引数を使います。この引数は TrueFalse 、文字列のいず れかで指定せねばなりません。

auto_idFalse にすると、フォーム出力に <label> タグや id 属性が含まれなくなります:

>>> f = ContactForm(auto_id=False)
>>> print f.as_table()
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" /></td></tr>
<tr><th>Sender:</th><td><input type="text" name="sender" /></td></tr>
<tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr>
>>> print f.as_ul()
<li>Subject: <input type="text" name="subject" maxlength="100" /></li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="text" name="sender" /></li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
>>> print f.as_p()
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
<p>Message: <input type="text" name="message" /></p>
<p>Sender: <input type="text" name="sender" /></p>
<p>Cc myself: <input type="checkbox" name="cc_myself" /></p>

auto_idTrue の場合、フォームの出力には <label> タグが入り、 各フォームフィールドの id 属性の値にはフィールド名をそのまま使います:

>>> f = ContactForm(auto_id=True)
>>> print f.as_table()
<tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" /></td></tr>
<tr><th><label for="sender">Sender:</label></th><td><input type="text" name="sender" id="sender" /></td></tr>
<tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="cc_myself" /></td></tr>
>>> print f.as_ul()
<li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="message">Message:</label> <input type="text" name="message" id="message" /></li>
<li><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></li>
<li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></li>
>>> print f.as_p()
<p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="message">Message:</label> <input type="text" name="message" id="message" /></p>
<p><label for="sender">Sender:</label> <input type="text" name="sender" id="sender" /></p>
<p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself" /></p>

auto_id がフォーマット文字 '%s' を含む文字列になっている場合、フォー ム出力は <label> タグを含むようになり、タグの id 属性はフォーマット 文字列に従って生成されます。例えば、フォーマット文字列が field_%s の場 合、 subject という名前のフィールドの id'field_subject' に なります。出力例は以下のようになります:

>>> f = ContactForm(auto_id='id_for_%s')
>>> print f.as_table()
<tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" /></td></tr>
<tr><th><label for="id_for_sender">Sender:</label></th><td><input type="text" name="sender" id="id_for_sender" /></td></tr>
<tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></td></tr>
>>> print f.as_ul()
<li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></li>
<li><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></li>
<li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
>>> print f.as_p()
<p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></p>
<p><label for="id_for_sender">Sender:</label> <input type="text" name="sender" id="id_for_sender" /></p>
<p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></p>

auto_id がこれ以外の偽でない値、つまり %s を含まない文字列のような 値の場合、 auto_idTrue に設定されたものとみなされます。

デフォルトでは、 auto_id'id_%s' に設定されています。

通常、フォームのレンダ時には、ラベル名の直後にコロン (:) が付加されます。 このコロンを他の文字に変更したり、文字を出力しないようにするには、 label_suffix パラメタを使います:

>>> f = ContactForm(auto_id='id_for_%s', label_suffix='')
>>> print f.as_ul()
<li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" /></li>
<li><label for="id_for_sender">Sender</label> <input type="text" name="sender" id="id_for_sender" /></li>
<li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
>>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->')
>>> print f.as_ul()
<li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subject" maxlength="100" /></li>
<li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" /></li>
<li><label for="id_for_sender">Sender -></label> <input type="text" name="sender" id="id_for_sender" /></li>
<li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>

ラベルの付加は、ラベルの最後の文字が区切り文字 (., !, ?, : のいずれか) でない場合にのみ行われます。

フィールドの並び順について

as_p()as_ul(), as_table() ショートカットを使うと、各フィー ルドは Form クラス内で定義された順に出力されます。例えば、上の ContactForm の例では、フィールドの並び順は subject, message, sender, cc_myself です。 HTML 出力の中でフィールドの並び順を変更し たければ、クラス定義内でのフィールドの並び順を変更してください。

エラーの出力方法

束縛フォームオブジェクトをレンダすると、フォームの検証がまだであればレンダ リング操作の中で自動的に検証が行われ、エラーがあれば HTML 出力中の該当フィー ルドの付近に <ul class=errorlist> でエラー内容が表示されます。エラーメッ セージ中の具体的なエラー表示位置は、どのメソッドでフォームをレンダしている かによります:

>>> data = {'subject': '',
...         'message': 'Hi there',
...         'sender': 'invalid e-mail address',
...         'cc_myself': True}
>>> f = ContactForm(data, auto_id=False)
>>> print f.as_table()
<tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" /></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" value="Hi there" /></td></tr>
<tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul><input type="text" name="sender" value="invalid e-mail address" /></td></tr>
<tr><th>Cc myself:</th><td><input checked="checked" type="checkbox" name="cc_myself" /></td></tr>
>>> print f.as_ul()
<li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" /></li>
<li>Message: <input type="text" name="message" value="Hi there" /></li>
<li><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul>Sender: <input type="text" name="sender" value="invalid e-mail address" /></li>
<li>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></li>
>>> print f.as_p()
<p><ul class="errorlist"><li>This field is required.</li></ul></p>
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
<p>Message: <input type="text" name="message" value="Hi there" /></p>
<p><ul class="errorlist"><li>Enter a valid e-mail address.</li></ul></p>
<p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
エラーリストの出力形式をカスタマイズする

デフォルトでは、バリデーション時エラーの出力内容は、 django.forms.util.ErrorList を使ってフォーマットされます。エラーの表 示に他のクラスを使いたければ、以下のようにフォームの生成時に指定します:

>>> from django.forms.util import ErrorList
>>> class DivErrorList(ErrorList):
...     def __unicode__(self):
...         return self.as_divs()
...     def as_divs(self):
...         if not self: return u''
...         return u'<div class="errorlist">%s</div>' % ''.join([u'<div class="error">%s</div>' % e for e in self])
>>> f = ContactForm(data, auto_id=False, error_class=DivErrorList)
>>> f.as_p()
<div class="errorlist"><div class="error">This field is required.</div></div>
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
<p>Message: <input type="text" name="message" value="Hi there" /></p>
<div class="errorlist"><div class="error">Enter a valid e-mail address.</div></div>
<p>Sender: <input type="text" name="sender" value="invalid e-mail address" /></p>
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
より細かな出力調整

as_p()as_ul(), as_table() といったメソッドは、単に面倒臭が りの開発者むけに用意されているショートカットでしかなく、他のやり方でもフォー ムを表示できます。

フォーム中のあるフィールドの HTML を表示するには、フォームを辞書のように扱 い、フィールドの名前をキーにして参照し、その値を出力します:

>>> f = ContactForm()
>>> print f['subject']
<input id="id_subject" type="text" name="subject" maxlength="100" />
>>> print f['message']
<input type="text" name="message" id="id_message" />
>>> print f['sender']
<input type="text" name="sender" id="id_sender" />
>>> print f['cc_myself']
<input type="checkbox" name="cc_myself" id="id_cc_myself" />

フィールドを引数にして str()unicode() を呼び出すと、レンダ結果 の HTML をそれぞれ string 型や Unicode 型のオブジェクトで返します:

>>> str(f['subject'])
'<input id="id_subject" type="text" name="subject" maxlength="100" />'
>>> unicode(f['subject'])
u'<input id="id_subject" type="text" name="subject" maxlength="100" />'

フォームオブジェクトには独自の __iter__() メソッドが定義されており、 各々のフィールドにわたってループ処理できます:

>>> f = ContactForm()
>>> for field in f: print field
<input id="id_subject" type="text" name="subject" maxlength="100" />
<input type="text" name="message" id="id_message" />
<input type="text" name="sender" id="id_sender" />
<input type="checkbox" name="cc_myself" id="id_cc_myself" />

フィールド固有の出力を行った場合でも、フォームオブジェクトの auto_id 設 定は有効です:

>>> f = ContactForm(auto_id=False)
>>> print f['message']
<input type="text" name="message" />
>>> f = ContactForm(auto_id='id_%s')
>>> print f['message']
<input type="text" name="message" id="id_message" />

あるフィールドに関するエラーのリストを取得するには、フィールドの errors 属性にアクセスします。このフィールドはリストライクなオブジェクトで、 HTML として出力すると <ul class="errorlist"> のリストになります:

>>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
>>> f = ContactForm(data, auto_id=False)
>>> print f['message']
<input type="text" name="message" />
>>> f['message'].errors
[u'This field is required.']
>>> print f['message'].errors
<ul class="errorlist"><li>This field is required.</li></ul>
>>> f['subject'].errors
[]
>>> print f['subject'].errors

>>> str(f['subject'].errors)
''
アップロードされたファイルをフォームに結びつける

FileFieldImageField といったフィールドの入ったフォームの扱いは、 通常のフォームより少しだけ複雑です。

まず、フォームからファイルをアップロードさせるには、 <form> エレメント で enctype"multipart/form-data" に設定されていなければなりませ ん:

<form enctype="multipart/form-data" method="post" action="/foo/">

次に、フォームを使う場合、ファイルデータをフォームに結びつけなければ なりません。ファイルデータは通常のフォームデータとは分けて扱われるので、 フォームに FileFieldImageField が入っている場合、束縛フォームを 作るには、第2引数にファイルデータを渡さねばなりません。ContactForm に mugshot という名前の ImageField を組み込んだ場合、下記のようにして、 顔写真 (mugshot) のファイルデータをフォームに結びつけます:

# 画像ファイルフィールドつきの束縛フォーム
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': 'foo@example.com',
...         'cc_myself': True}
>>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)}
>>> f = ContactFormWithMugshot(data, file_data)

実践的には、 request.FILES をファイルデータのソースとして指定することに なるでしょう (request.POST をフォームデータのソースにするのと同様です):

# 画像ファイルフィールドにリクエストからデータを渡す
>>> f = ContactFormWithMugshot(request.POST, request.FILES)

非束縛フォームの構築は通常通りで、フォームデータとファイルデータの 両方 を省略します:

# ImageField の入った非束縛フォームを生成
>>> f = ContactFormWithMugshot()
マルチパート形式のフォームをテストする

再利用可能なビューやテンプレートを書いているのなら、フォームがマルチパー ト形式であるかどうか前もって分からない場合もあるでしょう。 is_multipart() メソッドを使うと、フォームがマルチパート形式でエンコード されたデータの提出を要求しているかどうかを調べられます:

>>> f = ContactFormWithMugshot()
>>> f.is_multipart()
True

テンプレートの中では、以下のようにして使います:

{% if form.is_multipart %}
    <form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
    <form method="post" action="/foo/">
{% endif %}
{{ form }}
</form>
フォームのサブクラス化

同じフィールドを持つようなフォームクラスをいくつも作りたい場合、サブクラス 化を用いると冗長性を排除できます。

フォームクラスをサブクラス化すると、できたフォームクラスには親クラスの全て のフィールドが入っています。サブクラスで定義したフィールドは親クラスのフィー ルドの後に続きます。

以下の例では、 ContactFormWithPriority には ContactForm の全てのフィー ルドと、 priority という追加のフィールドが入っています。 ContactForm のフィールドは先に表示されます:

>>> class ContactFormWithPriority(ContactForm):
...     priority = forms.CharField()
>>> f = ContactFormWithPriority(auto_id=False)
>>> print f.as_ul()
<li>Subject: <input type="text" name="subject" maxlength="100" /></li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="text" name="sender" /></li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
<li>Priority: <input type="text" name="priority" /></li>

複数のフォームを親クラスにしたサブクラス化も可能です。この場合、親クラスの フォームは「混ぜ込み (mix-in)」クラスのように扱われます。以下の例では、 BeatleFormPersonFormInstrumentForm を (この順番で) サブクラス化しています。フィールドのリストには、親クラスのフィールドが順番 に表示されます:

>>> class PersonForm(Form):
...     first_name = CharField()
...     last_name = CharField()
>>> class InstrumentForm(Form):
...     instrument = CharField()
>>> class BeatleForm(PersonForm, InstrumentForm):
...     haircut_type = CharField()
>>> b = BeatleForm(auto_id=False)
>>> print b.as_ul()
<li>First name: <input type="text" name="first_name" /></li>
<li>Last name: <input type="text" name="last_name" /></li>
<li>Instrument: <input type="text" name="instrument" /></li>
<li>Haircut type: <input type="text" name="haircut_type" /></li>
フォームのプレフィクス
Form.prefix

Django のフォームは、一つの <form> タグの中に複数入れられます。各々の フォームに独自の名前空間を持たせるには、 prefix キーワード引数を使いま す:

>>> mother = PersonForm(prefix="mother")
>>> father = PersonForm(prefix="father")
>>> print mother.as_ul()
<li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" /></li>
<li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" /></li>
>>> print father.as_ul()
<li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" /></li>
<li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>

フォームフィールド

revision-up-to:11321 (1.1) unfinished
class Field(**kwargs)

フォームクラスの作成で一番重要なのは、フォームの各フィールドの定義です。各 フィールドには固有のデータ検証ロジックと、いくつかのフックが備わっています。

Field.clean(value)

フィールドクラスの主な用途はフォームクラスにおけるフィールド定義ですが、フィー ルドクラスは直接インスタンス化して使えるので、フィールドの動作を理解する役 に立つはずです。各フィールドインスタンスは clean() メソッドを備えており、 単一の引数を取って検証を行い、その結果に応じて django.newforms.ValidationError を送出するか、クリーニング済みの値を返 します:

>>> from django import forms
>>> f = forms.EmailField()
>>> f.clean('foo@example.com')
u'foo@example.com'
>>> f.clean(u'foo@example.com')
u'foo@example.com'
>>> f.clean('invalid e-mail address')
Traceback (most recent call last):
...
ValidationError: [u'Enter a valid e-mail address.']
フィールドの主な引数

各フィールドクラスのコンストラクタは、少なくとも以下に示す引数を取ります。 フィールドクラスによっては他にもフィールド固有の引数をとりますが。ここに示 す引数はどのフィールドクラスでも 常に 指定できる引数です:

required
Field.required

デフォルトでは、フィールドクラスはフィールドが必須 (reqired) であると仮定し ています。従って、フィールドに空の値、すなわち None や空文字列 ("") を渡すと、 clean()VaridationError 例外を送出します:

>>> f = forms.CharField()
>>> f.clean('foo')
u'foo'
>>> f.clean('')
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean(None)
Traceback (most recent call last):
...
ValidationError: [u'This field is required.']
>>> f.clean(' ')
u' '
>>> f.clean(0)
u'0'
>>> f.clean(True)
u'True'
>>> f.clean(False)
u'False'

必須で ない フィールドにするには、フィールドのコンストラクタに required=False を指定します:

>>> f = forms.CharField(required=False)
>>> f.clean('foo')
u'foo'
>>> f.clean('')
u''
>>> f.clean(None)
u''
>>> f.clean(0)
u'0'
>>> f.clean(True)
u'True'
>>> f.clean(False)
u'False'

required=False のフィールドの clean() に空の値を渡して呼び出すと、 clean()VaridationError を送出する代わりに 正規化された 空の値 を返します。例えば CharField の場合なら、 Unicode の空文字列になります。 その他のフィールドクラスでは None になるはずです (フィールドによって異 なります)。

label
Field.label

label 引数を使うと、フィールドに「人間に優しい」ラベルを指定できます。 このラベルはフォーム内でフィールドを表示するときに使われます。

フィールドのデフォルトのラベルはフィールド名のアンダースコアを除去して、頭 文字を大文字にしたものです。デフォルトのラベル命名規則で期待通りのラベルが 出力されない場合には、この引数を指定してください。

label を指定したフォームの例を以下に示します。出力を短くするために auto_id=False にしています:

>>> class CommentForm(forms.Form):
...     name = forms.CharField(label='Your name')
...     url = forms.URLField(label='Your Web site', required=False)
...     comment = forms.CharField()
>>> f = CommentForm(auto_id=False)
>>> print f
<tr><th>Your name:</th><td><input type="text" name="name" /></td></tr>
<tr><th>Your Web site:</th><td><input type="text" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
initial
Field.initial

initial 引数を使うと、非束縛フォーム内でフィールドをレンダするときの初 期値を指定できます。

初期値を動的に設定したいなら、 Form.initial パラメタの解説を参照し てください。

この引数を使うケースは、例えば以下のように、「空の」フォームの各フィールド を特定の値で初期化して表示したい場合です:

>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial='Your name')
...     url = forms.URLField(initial='http://')
...     comment = forms.CharField()
>>> f = CommentForm(auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url" value="http://" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>

こんなことをしなくても、フォームに初期データの入った辞書を渡せばいいのにと 思うかもしれませんね。しかし、フォームにデータを渡して束縛フォームにすると、 データを表示する際に検証がトリガされてしまい、 HTML 出力にバリデーションエ ラーが入ってしまいます:

>>> class CommentForm(forms.Form):
...     name = forms.CharField()
...     url = forms.URLField()
...     comment = forms.CharField()
>>> default_data = {'name': 'Your name', 'url': 'http://'}
>>> f = CommentForm(default_data, auto_id=False)
>>> print f
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
<tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="text" name="url" value="http://" /></td></tr>
<tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" /></td></tr>

このため、非束縛フォームの場合に限って initial に指定した値が出力される ようになっているのです。束縛フォームの場合、出力は常に束縛済みのデータです。

また、 initial の指定値は、フィールドの値が指定されなかった場合の「フォー ルバック用の」値には ならない ので注意が必要です。 initial の値は初期 値の入ったフォームの表示 だけ に用いられます:

>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial='Your name')
...     url = forms.URLField(initial='http://')
...     comment = forms.CharField()
>>> data = {'name': '', 'url': '', 'comment': 'Foo'}
>>> f = CommentForm(data)
>>> f.is_valid()
False
# フォームの値は初期値にフォールバック *しません。*
>>> f.errors
{'url': [u'This field is required.'], 'name': [u'This field is required.']}

Instead of a constant, you can also pass any callable:

>>> import datetime
>>> class DateForm(forms.Form):
...     day = forms.DateField(initial=datetime.date.today)
>>> print DateForm()
<tr><th>Day:</th><td><input type="text" name="day" value="12/23/2008" /><td></tr>

The callable will be evaluated only when the unbound form is displayed, not when it is defined.

widget
Field.widget

widget 引数を使うと、フィールドをレンダリングするときの Widget クラ スを指定できます。詳しくは ref-forms-widgets を参照してください。

help_text
Field.help_text

help_text 引数を使うと、フィールドに説明文をつけられます。 help_text を指定した場合、フォームを (as_ul() のような) フォームメ ソッドでレンダした時に、該当フィールドの隣に表示されます。

以下に、 help_text を使ったフォームの例を示します。この例では、フォーム の二つのフィールドに help_text を指定しています。出力を単純にするために、 auto_id=False を指定しています:

>>> class HelpTextContactForm(forms.Form):
...     subject = forms.CharField(max_length=100, help_text='100 characters max.')
...     message = forms.CharField()
...     sender = forms.EmailField(help_text='A valid e-mail address, please.')
...     cc_myself = forms.BooleanField(required=False)
>>> f = HelpTextContactForm(auto_id=False)
>>> print f.as_table()
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" /><br />100 characters max.</td></tr>
<tr><th>Message:</th><td><input type="text" name="message" /></td></tr>
<tr><th>Sender:</th><td><input type="text" name="sender" /><br />A valid e-mail address, please.</td></tr>
<tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself" /></td></tr>
>>> print f.as_ul()
<li>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
>>> print f.as_p()
<p>Subject: <input type="text" name="subject" maxlength="100" /> 100 characters max.</p>
<p>Message: <input type="text" name="message" /></p>
<p>Sender: <input type="text" name="sender" /> A valid e-mail address, please.</p>
<p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
error_messages
Field.error_messages

error_messages 引数を使うと、フィールドが送出するデフォルトのメッセージ をオーバライドできます。オーバライドしたいメッセージに対応する文字列をキー とし、メッセージを値に持つ辞書を渡してください。例えば、デフォルトのメッセー ジが以下のようだったとします:

>>> generic = forms.CharField()
>>> generic.clean('')
Traceback (most recent call last):
  ...
ValidationError: [u'This field is required.']

カスタムのエラーメッセージは以下のようにして設定します:

>>> name = forms.CharField(error_messages={'required': 'Please enter your name'})
>>> name.clean('')
Traceback (most recent call last):
  ...
ValidationError: [u'Please enter your name']

各フィールドで定義されているエラーメッセージのキーは、後述の 組み込みフォームフィールドクラス の節で定義しています。

組み込みフォームフィールドクラス

通常、 forms ライブラリには、一般的なバリデーション機能を備えたフィー ルドクラスのセットがついてきます。この節では、そうした組み込みフィールドに ついて述べます。

各フィールドについて、 widget パラメタを指定しなかったときのデフォルト のウィジェット型について説明しています。また、データが空の値だったとき (前述の requied の節を参照してください) に返される値についても定義して います。

BooleanField
class BooleanField(**kwargs)
  • デフォルトのウィジェット: CheckboxInput
  • 空のフォームデータに対する値: False
  • Python データへの正規化: Python の True または False
  • required=True の場合、チェックボックスがチェックされているか (値 が True であるか) 検証します。
  • エラーメッセージのキー: required
CheckboxInput (および標準の BooleanField) に空の値を指定した場合 のデフォルト値が None から False に変更されました。

Note

全てのフィールドのサブクラスにデフォルトで required=True が設定され るようになったので、バリデーション条件の設定は重要です。チェックされる 場合とされない場合のあるチェックボックスをフォームに含めたい場合は、 BooleanField を生成する際に required=False を忘れずに指定せねば なりません。

CharField
class CharField(**kwargs)
  • デフォルトのウィジェット: TextInput
  • 空のフォームデータに対する値: '' (空文字列)
  • Python データへの正規化: Unicode 文字列オブジェクト
  • max_length または min_length が指定された場合、文字列長を検証 します。それ以外の場合、どのような入力も valid とみなします。
  • エラーメッセージのキー: required, max_length, min_length

オプションの引数が 2 つあります:

CharField.max_length
CharField.min_length

これらの引数を指定すると、文字列長が最大、あるいは最小値の条件を満たし ているか検証します。

ChoiceField
class ChoiceField(**kwargs)
  • デフォルトのウィジェット: Select
  • 空のフォームデータに対する値: '' (空文字列)
  • Python データへの正規化: Unicode 文字列オブジェクト
  • 入力値が選択肢内にある値かどうか検証します。
  • エラーメッセージのキー: required, invalid_choice

必須の引数を一つとります:

ChoiceField.choices

イテレーション可能オブジェクト (たとえばリストやタプルなど) で、各要素 はフィールドの選択肢として使える 2 要素のタプルでなければなりません。

TypedChoiceField
class TypedChoiceField(**kwargs)

ChoiceField に似ていますが、 TypedChoiceField には coerce 引数があります。

  • デフォルトのウィジェット: Select
  • 空のフォームデータに対する値: empty_value の指定値
  • Python データへの正規化: coerce 引数の戻り値
  • 入力値が選択肢内にある値かどうか検証します。
  • エラーメッセージのキー: required, invalid_choice

以下の追加の引数をとります:

TypedChoiceField.coerce

引数を一つとり、型強制した値を返す関数を指定します。例えば、組み込みの int, float, bool などです。等値関数がデフォルト値として設定 されています。

TypedChoiceField.empty_value

「空の入力」を示すのに使う値です。デフォルト値は空文字列です。 None も良く使う値です。

DateField
class DateField(**kwargs)
  • デフォルトのウィジェット: DateInput
  • 空のフォームデータに対する値: None
  • Python データへの正規化: Python datetime.date オブジェクト
  • 入力値が datetime.datedatetime.datetime オブジェクト、ま たは特定の日付フォーマットの形式に従っているか検証します。
  • エラーメッセージのキー: required, invalid

以下のオプションの引数をとります:

DateField.input_formats

文字列から有効な datetime.date オブジェクトへの変換を試みるために使 われるフォーマット文字列からなるリストです。

input_formats を指定しない場合、デフォルトで以下の入力フォーマットをサ ポートします:

'%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
'%b %d %Y', '%b %d, %Y',            # 'Oct 25 2006', 'Oct 25, 2006'
'%d %b %Y', '%d %b, %Y',            # '25 Oct 2006', '25 Oct, 2006'
'%B %d %Y', '%B %d, %Y',            # 'October 25 2006', 'October 25, 2006'
'%d %B %Y', '%d %B, %Y',            # '25 October 2006', '25 October, 2006'
The DateField previously used a TextInput widget by default. It now uses a DateInput widget.
DateTimeField
class DateTimeField(**kwargs)
  • デフォルトのウィジェット: DateTimeInput
  • 空のフォームデータに対する値: None
  • Python データへの正規化: Python datetime.datetime オブジェクト
  • 入力値が datetime.datedatetime.datetime オブジェクト、ま たは特定の日付フォーマットの形式に従っているか検証します。
  • エラーメッセージのキー: required, invalid

以下のオプションの引数をとります:

DateTimeField.input_formats

文字列から有効な datetime.datetime オブジェクトへの変換を試みるため に使われるフォーマット文字列からなるリストです。

input_formats を指定しない場合、デフォルトで以下の入力フォーマットをサ ポートします:

'%Y-%m-%d %H:%M:%S',     # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M',        # '2006-10-25 14:30'
'%Y-%m-%d',              # '2006-10-25'
'%m/%d/%Y %H:%M:%S',     # '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M',        # '10/25/2006 14:30'
'%m/%d/%Y',              # '10/25/2006'
'%m/%d/%y %H:%M:%S',     # '10/25/06 14:30:59'
'%m/%d/%y %H:%M',        # '10/25/06 14:30'
'%m/%d/%y',              # '10/25/06'
DateTimeField はデフォルトで TextInput を使っていましたが、変更 されました。
DecimalField
class DecimalField(**kwargs)
  • デフォルトのウィジェット: TextInput
  • 空のフォームデータに対する値: None
  • Python データへの正規化: Python の decimal オブジェクト
  • 値が 10 進小数に変換可能か検証します。文字列の先頭および末尾の空白文 字は除去されます。
  • エラーメッセージのキー: required, invalid, max_value, min_value, max_digits, max_decimal_places, max_whole_digits

4 つのオプション引数を取ります:

DecimalField.max_value
DecimalField.min_value

それぞれ、フィールドの値のとり得る最大/最小値です。

DecimalField.max_digits

最大の桁数 (先頭のゼロ詰め桁を除いた上での小数点前後の桁数の合計) です。

DecimalField.decimal_places

decimal_places は小数部の最大桁数です。

EmailField
class EmailField(**kwargs)
  • デフォルトのウィジェット: TextInput
  • 空のフォームデータに対する値: '' (空文字列)
  • Python データへの正規化: Unicode 文字列オブジェクト
  • やや複雑な正規表現を使って、入力値が有効なメールアドレスであるか検証 します。
  • エラーメッセージのキー: required, invalid

オプションの引数として、 max_lengthmin_length の二つをとれます。 これらの引数を指定すると、文字列長が最大、あるいは最小値の条件を満たしてい るか検証します。

FileField
class FileField(**kwargs)
  • デフォルトのウィジェット: FileInput
  • 空のフォームデータに対する値: None
  • Python データへの正規化: ファイルコンテンツとファイル名を一つのオブジェ クトとしてラップする UploadedFile オブジェクト。
  • フォームに結びつけられているファイルデータが空でないか検証します。
  • エラーメッセージのキー: required, invalid, missing, empty

UploadedFile オブジェクトの詳細は ファイルアップロードのドキュメント を参照して ください。

FileField をフォームで使う場合、 フォームにファイルデータを束縛する のを忘れ ないようにしてください。

FilePathField
class FilePathField(**kwargs)
  • デフォルトのウィジェット: Select
  • 空のフォームデータに対する値: None
  • Python データへの正規化: unicode オブジェクト
  • 入力値が選択肢内にある値かどうか検証します。
  • エラーメッセージのキー: required, invalid_choice

このフィールドを使うと、あるディレクトリの下にあるファイルを選択できます。 フィールドは以下の 3 つの引数を追加で取り、 path のみ必須の引数です:

FilePathField.path

ファイルの一覧を表示したいディレクトリの絶対パスです。実在するディレク トリを指定せねばなりません。

FilePathField.recursive

False (デフォルト値) の場合、 path の直下にあるファイルのみを選 択肢として表示します。 True にすると、 path 以下の全てのファイ ルを再帰的に探索して選択肢にします。

FilePathField.match

正規表現です。この引数を指定すると、正規表現にマッチしたファイル名だけ を選択肢として表示します。

FloatField
  • デフォルトのウィジェット: TextInput
  • 空のフォームデータに対する値: None
  • Python データへの正規化: Python の float 型
  • 指定された値が浮動小数点数を表すかどうか検証します。 Python の float() 関数と同じく、前後に空白があってもかまいません。
  • エラーメッセージのキー: required, invalid, max_value, min_value

オプションの引数として、 max_value および min_value をとります。こ れらの値は、入力値のとりえる値域の調整に使われます。

ImageField
class ImageField(**kwargs)
  • デフォルトのウィジェット: FileInput
  • 空のフォームデータに対する値: None
  • Python データへの正規化: ファイルコンテンツとファイル名を一つのオブジェ クトとしてラップする UploadedFile オブジェクト。
  • 空でないファイルデータがフォームに結びつけられていて、かつその内容が PIL で扱えるファイル形式であるか検証します。
  • エラーメッセージのキー: required, invalid, missing, empty, invalid_image

ImageField を使いたい場合、 Python Imaging Library をインストールしてお かねばなりません。

ImageField をフォームで使う場合、 フォームにファイルデータを束縛する のを忘れないようにしてください。

IntegerField
class IntegerField(**kwargs)
  • デフォルトのウィジェット: TextInput
  • 空のフォームデータに対する値: None
  • Python データへの正規化: Python 整数型または長整数型
  • 入力値が整数であるか検証します。 Python の int() 関数と同様、先頭 や末尾に空白があってもかまいません。
  • エラーメッセージのキー: required, invalid, max_value, min_value

以下の二つの引数をとります:

IntegerField.max_value
IntegerField.min_value

フィールドのとり得る値の最大値および最小値です。

IPAddressField
class IPAddressField(**kwargs)
  • デフォルトのウィジェット: TextInput
  • 空のフォームデータに対する値: '' (空の文字列)
  • Python データへの正規化: Unicode オブジェクト
  • 正規表現を使って、値が正しい IPv4 アドレス形式であるか検証します。
  • エラーメッセージのキー: required, invalid
MultipleChoiceField
class MultipleChoiceField(**kwargs)
  • デフォルトのウィジェット: SelectMultiple
  • 空のフォームデータに対する値: [] (空のリスト)
  • Python データへの正規化: Unicode 文字列オブジェクトのリスト
  • 入力値のリスト中の全ての値が選択肢内の値であるかどうか検証します。
  • エラーメッセージのキー: required, invalid_choice, invalid_list

追加の引数として choices をとります。 choices の意味は ChoiceFieldchoices と同じです。

NullBooleanField
class NullBooleanField(**kwargs)
  • デフォルトのウィジェット: NullBooleanSelect
  • 空のフォームデータに対する値: None
  • Python データへの正規化: True, False または None
  • バリデーションを実行しません (VaridationError を送出しません)。
RegexField
class RegexField(**kwargs)
  • デフォルトのウィジェット: TextInput
  • 空のフォームデータに対する値: '' (空文字列)
  • Python データへの正規化: Unicode 文字列オブジェクト
  • 入力値が特定の正規表現にマッチするかどうか検証します。
  • エラーメッセージのキー: required, invalid

追加の引数を一つ持っています:

RegexField.regex

regex は正規表現を表す文字列またはコンパイル済みの正規表現オブジェ クトです。

CharField と同様、 max_length および min_length をとります。

以前のバージョンとの互換性のため、オプション引数 error_message も指定で きるようになっています。エラーメッセージを指定したければ、 error_messages を使って、 'invalid' をキーにしたメッセージを指定す るよう薦めます。

TimeField
class TimeField(**kwargs)
  • デフォルトのウィジェット: TextInput
  • 空のフォームデータに対する値: None
  • Python データへの正規化: Python datetime.time オブジェクト
  • 入力値が datetime.time オブジェクトまたは特定の日付フォーマットの 形式に従っているか検証します。
  • エラーメッセージのキー: required, invalid

オプションの引数を一つ持っています:

TimeField.input_formats

文字列から有効な datetime.time オブジェクトへの変換を試みるために使 われるフォーマット文字列からなるリストです。

input_formats を指定しない場合、デフォルトで以下の入力フォーマットをサ ポートします:

'%H:%M:%S',     # '14:30:59'
'%H:%M',        # '14:30'
URLField
class URLField(**kwargs)
  • デフォルトのウィジェット: TextInput
  • 空のフォームデータに対する値: '' (空文字列)
  • Python データへの正規化: Unicode 文字列オブジェクト
  • 入力値が有効な URL であるかどうか検証します。
  • エラーメッセージのキー: required, invalid, invalid_link

以下のオプションの引数をとります:

URLField.max_length
URLField.min_length

CharField.max_lengthCharField.min_length と同じです。

URLField.verify_exists

True にすると、バリデータが指定された URLをロードできるか調べ、該当 ページの HTTP レスポンスが 404 のときに ValidationError を送出しま す。デフォルト値は False です。

URLField.validator_user_agent

URL が存在するか確かめるときに使うユーザエージェントを表す文字列です。 デフォルト値は URL_VALIDATOR_USER_AGENT 設定の値です。

やや複雑な組み込みフィールドクラス

以下のフィールドはまだドキュメント化されていません。

class ComboField(**kwargs)
class MultiValueField(**kwargs)
class SplitDateTimeField(**kwargs)
  • Default widget: SplitDateTimeWidget
  • Empty value: None
  • Normalizes to: A Python datetime.datetime object.
  • Validates that the given value is a datetime.datetime or string formatted in a particular datetime format.
  • Error message keys: required, invalid

Takes two optional arguments:

SplitDateTimeField.input_date_formats

A list of formats used to attempt to convert a string to a valid datetime.date object.

If no input_date_formats argument is provided, the default input formats for DateField are used.

SplitDateTimeField.input_time_formats

A list of formats used to attempt to convert a string to a valid datetime.time object.

If no input_time_formats argument is provided, the default input formats for TimeField are used.

The SplitDateTimeField previously used two TextInput widgets by default. The input_date_formats and input_time_formats arguments are also new.
リレーションを扱うフィールド

モデル間のリレーションを表現するために、二つのフィールドが提供されています。 これらのフィールドは、選択肢を QuerySet から取り出します:

class ModelChoiceField(**kwargs)
class ModelMultipleChoiceField(**kwargs)

これらのフィールドは、入力に応じて、フォームの cleaned_data 辞書内にモ デルオブジェクトをいれます。どちらのフィールド型にも必須の引数が一つありま す:

ModelChoiceField.queryset

フィールドが選択肢として表示するモデルオブジェクトの QuerySet です。 また、フィールドはこの QuerySet を使って、ユーザの選択値が QuerySet 内に含まれているかを検証します。

ModelChoiceField

モデルオブジェクト一つを選択できるフィールドです。外部キーを表現するのに適 しています。

フィールドの選択肢として表示される文字列の取得には、モデルオブジェクトの __unicode__ メソッドを使います。表示をカスタマイズしたければ、 ModelChoicefield をサブクラス化して、 label_for_instance メソッドを オーバライドしてください。このメソッドはモデルオブジェクトを引数にとり、表 示に適した文字列を返さねばなりません:

class MyModelChoiceField(ModelChoiceField):
    def label_from_instance(self, obj):
        return "My Object #%i" % obj.id
ModelChoiceField.empty_label

By default the <select> widget used by ModelChoiceField will have a an empty choice at the top of the list. You can change the text of this label (which is "---------" by default) with the empty_label attribute, or you can disable the empty label entirely by setting empty_label to None:

# A custom empty label
field1 = forms.ModelChoiceField(queryset=..., empty_label="(Nothing)")

# No empty label
field2 = forms.ModelChoiceField(queryset=..., empty_label=None)

Note that if a ModelChoiceField is required and has a default initial value, no empty choice is created (regardless of the value of empty_label).

ModelMultipleChoiceField

複数のモデルオブジェクトを選択できるフィールドです。多対多のリレーションを 表現するのに向いています。 ModelChoiceField と同様、オブジェクトの表示 を変更するには label_from_instance メソッドをオーバライドしてください。

カスタムフィールドの作成

組み込みのフィールドクラスが用途に合わなくても、カスタムのフィールドクラス は簡単に作成できるので大丈夫です。カスタムのフィールドクラスは django.forms.Field をサブクラス化して作成します。 フィールドクラスを定義する際の制約は、 clean() メソッドを実装すること、 __init__() メソッドにコアの引数 (required, label, initial, widget, help_text) を持たせることだけです。

ウィジェット

revision-up-to:17812 (1.4) unfinished

ウィジェットとは、Django で HTML の入力エレメントを表現するためのオブジェク トです。ウィジェットは、 HTML のレンダリングや、個々のウィジェットに対応す るデータをGET/POST 辞書から抽出する処理を行います。

ウィジェットの指定

フォームに何らかのフィールドを作成する場合、 Django は表示するデータの型に 応じて適切なデフォルトのウィジェットを使います。どのフィールドがどのウィ ジェットを使っているかは、 組み込みフィールドクラス のドキュメントを参照してください。

とはいえ、デフォルトとは違うウィジェットを使いたい場合もあるでしょう。その 場合には、以下の例のように、フィールドを定義する際に widget 引数を指定します:

from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField(widget=forms.Textarea)

上のコードでは、 comment フィールドにデフォルトの TextInput ウィジェッ トではなく、より大きな Textarea ウィジェットを使うように指定しています。

ウィジェットに引数を設定する

多くのウィジェットにはオプションの追加引数があり、それらはフィールドの ウィジェットを定義する際に設定できます。次の例では、 years 属性が SelectDateWidget に設定されます:

from django.forms.fields import DateField, ChoiceField, MultipleChoiceField
from django.forms.widgets import RadioSelect, CheckboxSelectMultiple
from django.forms.extras.widgets import SelectDateWidget

BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
GENDER_CHOICES = (('m', 'Male'), ('f', 'Female'))
FAVORITE_COLORS_CHOICES = (('blue', 'Blue'),
                            ('green', 'Green'),
                            ('black', 'Black'))

class SimpleForm(forms.Form):
    birth_year = DateField(widget=SelectDateWidget(years=BIRTH_YEAR_CHOICES))
    gender = ChoiceField(widget=RadioSelect, choices=GENDER_CHOICES)
    favorite_colors = forms.MultipleChoiceField(required=False,
        widget=CheckboxSelectMultiple, choices=FAVORITE_COLORS_CHOICES)

どのようなウィジェットが利用可能で、それらがどの引数を受け付けるかについては、 組み込みウィジェット を参照してください。

Select ウィジェットを継承するウィジェット

Select ウィジェットを継承するウィジェットは選択肢を扱います。これらは 選ぶことのできるオプション一覧をユーザに提示します。ウィジェットによって オプション一覧の提示方法は異なります。 Select ウィジェットは HTML の <select> を、 RadioSelect はラジオボタンを使う、という具合です。

Select ウィジェットはデフォルトで ChoiceField フィールド によって使われます。このウィジェットは表示する選択肢を ChoiceField から継承しており、 ChoiceField.choices を変更すると Select.choices も更新されます。例えば:

>>> from django import forms
>>> CHOICES = (('1', 'First',), ('2', 'Second',)))
>>> choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
>>> choice_field.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices = ()
>>> choice_field.choices = (('1', 'First and only',),)
>>> choice_field.widget.choices
[('1', 'First and only')]

choices 属性を持つウィジェットは、実は選択肢を扱わないフィールド – 例えば CharField – に対して使うことも可能ですが、本質的にその 選択肢がモデル由来であり、かつ表示目的だけのウィジェットでもないならば、 ChoiceField ベースのフィールドに対して使うことを推奨します。

ウィジェットインスタンスのカスタマイズ

ウィジェットを HTML としてレンダリングする際、 Django は最小限の HTML しか 出力しません。すなわち、クラス定義やウィジェット固有の属性は一切付加しない のです。従って、例えばページ上にまったく同じ見栄えの TextInput ウィジェットが並ぶわけです。

ウィジェットごとに見栄えを変えたいのなら、各々のウィジェットに属性を指定し てやる必要があります。ウィジェットを指定するときに、レンダリング後の HTML に付加したい属性のリストを指定できます。

例えば、以下のような簡単なフォームを考えましょう:

from django import forms

class CommentForm(forms.Form):
    name = forms.CharField()
    url = forms.URLField()
    comment = forms.CharField()

このフォームは 3 つの TextInput ウィジェットからなり、デフォルトの レンダリングでは CSS クラスや属性は指定されていません。従って、各ウィジェットは 全く同じ入力ボックスとしてレンダリングされます:

>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>

現実の Web ページでは、全ウィジェットが同じに見えるような見栄えを期待しない でしょう。コメント欄をもうちょっと大きな入力ボックスにしたかったり、 'name' ウィジェットに特別な CSS クラスを指定したかったりするかもしれま せん。そうするには、ウィジェット作成時に Widget.attrs 属性を使用します:

例えば:

class CommentForm(forms.Form):
    name = forms.CharField(
                widget=forms.TextInput(attrs={'class':'special'}))
    url = forms.URLField()
    comment = forms.CharField(
               widget=forms.TextInput(attrs={'size':'40'}))

これで、 Django はレンダリング結果に追加の属性を組み込むようになります:

>>> f = CommentForm(auto_id=False)
>>> f.as_table()
<tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
組み込みウィジェット

Django は、基本的な HTML ウィジェットすべてと、よく使われるウィジェットグルー プを提供しています:

Widget
class Widget

この抽象クラスはレンダリングできませんが、基本の属性 attrs を提供します。

attrs

レンダリングされるウィジェットに設定される HTML 属性を含んだ辞書です。

>>> name = forms.TextInput(attrs={'size': 10, 'title': 'Your name',})
>>> name.render('name', 'A name')
u'<input title="Your name" type="text" name="name" value="A name" size="10" />'
TextInput
class TextInput

テキスト入力: <input type='text' ...> です。

PasswordInput
class PasswordInput

パスワードテキスト入力: <input type='password' ...> です。

オプションの引数を一つ取ります。

render_value

検証エラー後にウィジェットが再表示される際、値が記入されるかどうかを 決定します (デフォルトは False です)。

render_value のデフォルト値は True から False に変更されました。
HiddenInput
class HiddenInput

hidden ウィジェット: <input type='hidden' ...> です。

MultipleHiddenInput
class MultipleHiddenInput

複数の hidden ウィジェット: <input type='hidden' ...> です。

複数の値を持つフィールド用に、複数の hidden ウィジェットを使うウィジェット です。

choices

この属性は、フィールドに choices 属性が無い場合には 指定する必要はありません。もし属性がある場合、 Fieldchoices 属性が更新されると、ここでの指定は上書きされます。

FileInput
class FileInput

ファイルアップロード: <input type='file' ...> です。

ClearableFileInput
class ClearableFileInput
リリースノートを参照してください

フィールドが入力必須ではなく、かつ初期データがある場合に、フィールドの値を クリアするためのチェックボックスを備えたファイルアップロード入力: <input type='file' ...> です。

DateInput
class DateInput

単純なテキストボックスで表現された、日付用の入力ウィジェット: <input type='text' ...> です。

オプションの引数を一つ取ります:

format

フィールド初期値の表示に使う書式。

format 引数が指定されない場合、デフォルトの書式は DATE_INPUT_FORMATS で最初に見つかった書式になり、かつ 書式ローカライズ が適用されます。

DateTimeInput
class DateTimeInput

単純なテキストボックスで表現された、日付/時刻用の入力ウィジェット: <input type='text' ...> です。

オプションの引数を一つ取ります:

format

フィールド初期値の表示に使う書式。

format 引数が指定されない場合、デフォルトの書式は DATETIME_INPUT_FORMATS で最初に見つかった書式になり、かつ 書式ローカライズ が適用されます。

TimeInput
class TimeInput

単純なテキストボックスで表現された、時刻用の入力ウィジェット: <input type='text' ...> です。

オプションの引数を一つ取ります:

format

フィールド初期値の表示に使う書式。

format 引数が指定されない場合、デフォルトの書式は TIME_INPUT_FORMATS で最初に見つかった書式になり、かつ 書式ローカライズ が適用されます。

Textarea
class Textarea

テキストエリア: <textarea>...</textarea> です。

CheckboxInput
class CheckboxInput

チェックボックス: <input type='checkbox' ...> です。

オプションの引数を一つ取ります:

check_test

CheckboxInput の値を受け取り、チェックボックスにチェックを入れるべき ならば True を返す呼び出し可能オブジェクト。

Select
class Select

セレクタ: <select><option ...>...</select> です。

choices

この属性は、フィールドに choices 属性が無い場合には 指定する必要はありません。もし属性がある場合、 Fieldchoices 属性が更新されると、ここでの指定は上書きされます。

NullBooleanSelect
class NullBooleanSelect

「不明」, 「はい」, 「いいえ」 を選択肢とするセレクタです。

SelectMultiple
class SelectMultiple

Select と似ていますが、複数選択が可能なセレクタ: <select multiple='multiple'>...</select> です。

RadioSelect
class RadioSelect

Select と似ていますが、 <li> タグを使ったラジオボタンのリスト としてレンダリングされます:

<ul>
  <li><input type='radio' ...></li>
  ...
</ul>
リリースノートを参照してください

生成されるマークアップをもっと細かくコントロールしたければ、テンプレート内で ラジオボタンに対してループを回すことができます。仮に myform という フォームがあり、そこに RadioSelect をウィジェットに指定した beatles というフィールドがあると仮定すると:

{% for radio in myform.beatles %}
<div class="myradio">
    {{ radio }}
</div>
{% endfor %}

これは次の HTML を生成します:

<div class="myradio">
    <label><input type="radio" name="beatles" value="john" /> John</label>
</div>
<div class="myradio">
    <label><input type="radio" name="beatles" value="paul" /> Paul</label>
</div>
<div class="myradio">
    <label><input type="radio" name="beatles" value="george" /> George</label>
</div>
<div class="myradio">
    <label><input type="radio" name="beatles" value="ringo" /> Ringo</label>
</div>

<label> タグに囲まれていますね。さらに細かくコントロールしたければ、 ラジオボタンごとの tagchoice_label 属性を使えます。例えば このテンプレート...

{% for radio in myform.beatles %}
    <label>
        {{ radio.choice_label }}
        <span class="radio">{{ radio.tag }}</span>
    </label>
{% endfor %}

...は次の HTML になります:

<label>
    John
    <span class="radio"><input type="radio" name="beatles" value="john" /></span>
</label>
<label>
    Paul
    <span class="radio"><input type="radio" name="beatles" value="paul" /></span>
</label>
<label>
    George
    <span class="radio"><input type="radio" name="beatles" value="george" /></span>
</label>
<label>
    Ringo
    <span class="radio"><input type="radio" name="beatles" value="ringo" /></span>
</label>

もしラジオボタンに対してループを回さない – つまり単純にテンプレートで {{ myform.beatles }} と書く – と決めたなら、上に記した通り、 それらは <li> タグを使った <ul> の中に出力されることになるでしょう。

CheckboxSelectMultiple
class CheckboxSelectMultiple

SelectMultiple と似ていますが、チェックボックスのリストとして レンダリングされます:

<ul>
  <li><input type='checkbox' ...></li>
  ...
</ul>
MultiWidget
class MultiWidget

複数のウィジェットをラップするウィジェットです。おそらく MultiValueField と共に使いたくなるでしょう。

これの render() メソッドは、どうやって一つの値を複数のウィジェットで 表示するかを決める必要があるため、他のウィジェットのものとは異なります。

これのサブクラスは format_output メソッドを独自に実装しているかも しれません。 format_output メソッドは、レンダリングされたウィジェットの リストを受け取って、それらを自由に書式化し、 HTML の文字列を返します (訳注: format_output メソッドはウィジェットのレンダリング結果をカスタマイズする フックです)。

レンダリング時に使われる引数 value は次の 2 つのいずれかになります:

  • 一つの list
  • 値の list を「圧縮」表現した一つの値 (例えば文字列) 。

2 つ目の場合 – すなわちリスト ではない 場合 – render() はまず レンダリングする前に値を list に展開します。これは、 MultiWidget のサブクラスが実装しなければならない decompress() メソッドを呼ぶことで行われます。このメソッドは一つの「圧縮」された値を 受け取り、list を返します。一例として、 SplitDateTimeWidget がどうやって datetime の値を 日付と時刻という 2 つの値に分離したリストに変換しているかを挙げましょう:

class SplitDateTimeWidget(MultiWidget):

    # ...

    def decompress(self, value):
        if value:
            return [value.date(), value.time().replace(microsecond=0)]
        return [None, None]

render() が HTML レンダリングを実行するとき、リスト中の各値は対応する ウィジェットを使ってレンダリングされます – 最初の値は最初のウィジェットで、 2 つ目の値は 2 つ目のウィジェットで、という具合です。

MultiWidget は 1 つ指定必須の引数があります:

widgets

必要なウィジェットを含んだイテレーション可能オブジェクト。

SplitDateTimeWidget
class SplitDateTimeWidget

日付用の DateInput と、時刻用の TimeInput を、 MultiWidget を使ってラップしたものです。

SplitDateTimeWidget には 2 つオプションの属性があります:

date_format

DateInput.format と似ています。

time_format

TimeInput.format と似ています。

SplitHiddenDateTimeWidget
class SplitHiddenDateTimeWidget

SplitDateTimeWidget と似ていますが、 HiddenInput を日付と時間の両方に使用します。

SelectDateWidget
class SelectDateWidget

年・月・日それぞれ用の Select ウィジェット 3 つをラッピングしたウィジェットです。なおこのウィジェットは標準の ウィジェットとは異なるファイルで提供されていますので注意してください。

オプションの引数を一つ取ります。

years

オプションの、”year” セレクタで使用する年のリストまたはタプルです。 デフォルトでは現在の年から 9 年先までを含んだリストになります。

フォームやフィールドのバリデーション

revision-up-to:11321 (1.1) unfinished

フォームのバリデーションは、データのクリーニングを行ったときに実行されます。 この挙動をカスタマイズしたければ、目的に応じていくつかの手法から選択するこ とになります。フォームの処理では、 3 つのデータクリーニング過程があります。 これらの過程は通常、フォームの is_valid() メソッドを呼び出したときに実 行されます。データのクリーニングとバリデーションをトリガする要素は他にもあ ります (errors 属性へのアクセスや、 full_clean() の呼び出し) が、 通常は直接用いることはありません。

一般に、データクリーニングのメソッドは、処理中のデータに何らかの問題がある 場合、 ValidationError 例外を送出し、その際 ValidationError のコン ストラクタにエラーメッセージを渡すことになっています。 ValidationError を送出しない場合、クリーニングメソッドはクリーニング済み (正規化済み) のデー タを Python オブジェクトとして返さねばなりません。

クリーニング処理中に複数のエラーを検出し、全てのエラーをフォームのユーザに 提示したければ、 ValidationError のコンストラクタにエラーのリストを渡せ ます。

クリーニングメソッドとは、以下の 3 つです:

  • フィールドサブクラスの clean() メソッド。このメソッドは、該当フィー ルドクラスのインスタンスに共通して必要なクリーニングを行う役割を担いま す。例えば、 FloatField の clean() メソッドは、データを Python の float オブジェクトに変換するか、 ValidationError を送出します。

  • フォームサブクラスの clean_<fieldname>() (<fieldname> はフォー ムフィールドを指す属性名) メソッド。このメソッドは特定の属性名のフィー ルドに対するクリーニングを行います。フィールドの型は問いません。この メソッドはパラメタ無しで呼び出されます。フィールドの値は self.cleaned_data を介して参照せねばならず、値はこの段階ではフォー ムとして提出された元の文字列ではなく、Python オブジェクトであることに 注意してください。(cleaned_data に入るのは、上記の clean() メ ソッドが既にデータを一度クリーニングしているからです。)

    例えば、 serialnumber という名前の CharField の中身が一意な値 になるようバリデーションを行いたければ、 clean_serialnumber() を 使うのが適切です。特定のフィールド (実際には CharField) 向けでは なく、フォーム上のフィールド固有のバリデーションや、データのクリーニ ング、正規化はここで行いましょう。

    Just like the general field clean() method, above, this method should return the cleaned data, regardless of whether it changed anything or not.

  • フォームのサブクラスの clean() メソッド。このメソッドは、フォーム 上の複数のフィールドに一度にアクセスする必要があるようなバリデーショ ンを実行できます。「フィールド A に値が入っている時に、フィールド B には有効なメールアドレスが入っていなければならない」といったバ リデーションにはこのメソッドを使います。このメソッドの返すデータは、 フォームの cleaned_data 属性の最終的な値になるので、このメソッド をオーバライドする場合は必ず全てのクリーニング済みデータを返すように してください (デフォルトでは、 Form.clean()self.cleaned_data をそのまま返します)。

    オーバライドされた Form.clean() の送出するエラーは、フォームの いずれかのフィールドではなく、(__all__ という名の) 特殊な「フィー ルド」に関連づけられます。エラーは non_field_errors() でアクセス できます。エラーをフォームの特定のフィールドに関連付けたいのなら、 後で解説 する、フォームの _errors 属性にアクセスする必要があります。

上に挙げたメソッドは、各フィールドごとに一度づつ、上に挙げた順に呼び出され ます。すなわち、フォームの各フィールドについて、 (フォーム定義で宣言した順 に) まず Field.clean() メソッドを呼び出し、次いで cleaned_<fieldname>() 、を呼びます。最後に、 Form.clean() メソッド (オーバライドされていればそれを) を呼び出します。

Examples of each of these methods are provided below.

先程も書いた通り、上記のメソッドは VaridationError を送出することがあり ます。個々のフィールドで、 Field.clean() メソッドが ValidationError を送出した場合、フォーム上のフィールドごとのクリーニングメソッドは呼び出さ れません。ただし、残りの全てのフィールドに対するクリーニング処理は最後まで 行われます。

フォームクラスやサブクラスに対する clean() メソッドは常に実行されます。 このメソッドが VaridationError を送出する場合、 cleaned_data は空の 辞書になります。

前の段落の意味するところは、 Form.clean() をオーバライドする場合、 self.cleaned_data.items() の各要素を調べ、さらにフォームの _errors 属性も考慮して、どのフィールドが個別のバリデーション用件を満たしているかを 調べる必要があるということです。

Form subclasses and modifying field errors

Sometimes, in a form’s clean() method, you will want to add an error message to a particular field in the form. This won’t always be appropriate and the more typical situation is to raise a ValidationError from Form.clean(), which is turned into a form-wide error that is available through the Form.non_field_errors() method.

When you really do need to attach the error to a particular field, you should store (or amend) a key in the Form._errors attribute. This attribute is an instance of a django.forms.util.ErrorDict class. Essentially, though, it’s just a dictionary. There is a key in the dictionary for each field in the form that has an error. Each value in the dictionary is a django.forms.util.ErrorList instance, which is a list that knows how to display itself in different ways. So you can treat _errors as a dictionary mapping field names to lists.

If you want to add a new error to a particular field, you should check whether the key already exists in self._errors or not. If not, create a new entry for the given key, holding an empty ErrorList instance. In either case, you can then append your error message to the list for the field name in question and it will be displayed when the form is displayed.

There is an example of modifying self._errors in the following section.

What’s in a name?

You may be wondering why is this attribute called _errors and not errors. Normal Python practice is to prefix a name with an underscore if it’s not for external usage. In this case, you are subclassing the Form class, so you are essentially writing new internals. In effect, you are given permission to access some of the internals of Form.

Of course, any code outside your form should never access _errors directly. The data is available to external code through the errors property, which populates _errors before returning it).

Another reason is purely historical: the attribute has been called _errors since the early days of the forms module and changing it now (particularly since errors is used for the read-only property name) would be inconvenient for a number of reasons. You can use whichever explanation makes you feel more comfortable. The result is the same.

Using validation in practice

The previous sections explained how validation works in general for forms. Since it can sometimes be easier to put things into place by seeing each feature in use, here are a series of small examples that use each of the previous features.

Form field default cleaning

メールアドレスをカンマ区切りで入力させるフォームフィールドを作ってみましょ う。少なくとも一つアドレスが入っているかどうかも検証します。簡単のため、 個々のメールアドレスの検証は is_valid_email() という関数で行っているこ とにします。クラスの全体像は以下のようになります:

from django import forms

class MultiEmailField(forms.Field):
    def clean(self, value):
        """
        フィールドに一つ以上のメールアドレスがカンマ区切りで入っている
        かチェックして、メールアドレス文字列のリストに正規化する
        """
        if not value:
            raise forms.ValidationError('Enter at least one e-mail address.')
        emails = value.split(',')
        for email in emails:
            if not is_valid_email(email):
                raise forms.ValidationError('%s is not a valid e-mail address.' % email)

        # 常にクリーニング済みのデータを返す
        return emails

Every form that uses this field will have this clean() method run before anything else can be done with the field’s data. This is cleaning that is specific to this type of field, regardless of how it is subsequently used.

Let’s create a simple ContactForm to demonstrate how you’d use this field:

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField()
    sender = forms.EmailField()
    recipients = MultiEmailField()
    cc_myself = forms.BooleanField(required=False)

Simply use MultiEmailField like any other form field. When the is_valid() method is called on the form, the MultiEmailField.clean() method will be run as part of the cleaning process.

Cleaning a specific field attribute

Continuing on from the previous example, suppose that in our ContactForm, we want to make sure that the recipients field always contains the address "fred@example.com". This is validation that is specific to our form, so we don’t want to put it into the general MultiEmailField class. Instead, we write a cleaning method that operates on the recipients field, like so:

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean_recipients(self):
        data = self.cleaned_data['recipients']
        if "fred@example.com" not in data:
            raise forms.ValidationError("You have forgotten about Fred!")

        # Always return the cleaned data, whether you have changed it or
        # not.
        return data
Cleaning and validating fields that depend on each other

Suppose we add another requirement to our contact form: if the cc_myself field is True, the subject must contain the word "help". We are performing validation on more than one field at a time, so the form’s clean() method is a good spot to do this. Notice that we are talking about the clean() method on the form here, whereas earlier we were writing a clean() method on a field. It’s important to keep the field and form difference clear when working out where to validate things. Fields are single data points, forms are a collection of fields.

By the time the form’s clean() method is called, all the individual field clean methods will have been run (the previous two sections), so self.cleaned_data will be populated with any data that has survived so far. So you also need to remember to allow for the fact that the fields you are wanting to validate might not have survived the initial individual field checks.

There are two way to report any errors from this step. Probably the most common method is to display the error at the top of the form. To create such an error, you can raise a ValidationError from the clean() method. For example:

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = self.cleaned_data
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject:
            # Only do something if both fields are valid so far.
            if "help" not in subject:
                raise forms.ValidationError("Did not send for 'help' in "
                        "the subject despite CC'ing yourself.")

        # Always return the full collection of cleaned data.
        return cleaned_data

In this code, if the validation error is raised, the form will display an error message at the top of the form (normally) describing the problem.

The second approach might involve assigning the error message to one of the fields. In this case, let’s assign an error message to both the “subject” and “cc_myself” rows in the form display. Be careful when doing this in practice, since it can lead to confusing form output. We’re showing what is possible here and leaving it up to you and your designers to work out what works effectively in your particular situation. Our new code (replacing the previous sample) looks like this:

from django.forms.util import ErrorList

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = self.cleaned_data
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject and "help" not in subject:
            # We know these are not in self._errors now (see discussion
            # below).
            msg = u"Must put 'help' in subject when cc'ing yourself."
            self._errors["cc_myself"] = ErrorList([msg])
            self._errors["subject"] = ErrorList([msg])

            # These fields are no longer valid. Remove them from the
            # cleaned data.
            del cleaned_data["cc_myself"]
            del cleaned_data["subject"]

        # Always return the full collection of cleaned data.
        return cleaned_data

As you can see, this approach requires a bit more effort, not withstanding the extra design effort to create a sensible form display. The details are worth noting, however. Firstly, earlier we mentioned that you might need to check if the field name keys already exist in the _errors dictionary. In this case, since we know the fields exist in self.cleaned_data, they must have been valid when cleaned as individual fields, so there will be no corresponding entries in _errors.

Secondly, once we have decided that the combined data in the two fields we are considering aren’t valid, we must remember to remove them from the cleaned_data.

In fact, Django will currently completely wipe out the cleaned_data dictionary if there are any errors in the form. However, this behaviour may change in the future, so it’s not a bad idea to clean up after yourself in the first place.

汎用ビュー

revision-up-to:11321 (1.1) unfinished

Web アプリケーションの作成は、同じパターンを何度も何度も繰り返し書くことに なるため、退屈なものです。 Django では、そんなパターンの中でもっとも共通す る部分を「汎用ビュー (generic view) 」という形で抽象化しています。汎用ビュー を使えば、オブジェクトを操作するためによく使うビューを、 Python コードを一 切書かずに作成できます。

汎用ビューの全般的な解説は、 汎用ビューの概要 にあります。

This reference contains details of Django’s built-in generic views, along with a list of all keyword arguments that a generic view expects. Remember that arguments may either come from the URL pattern or from the extra_context additional-information dictionary.

Most generic views require the queryset key, which is a QuerySet instance; see クエリを生成する for more information about QuerySet objects.

「簡単な」汎用ビュー

django.views.generic.simple モジュールには、簡単なビューが入っていて、 ビューロジックの必要がないときのレンダリングと、リダイレクトの発行という よくある二つのケースを処理できるようになっています:

django.views.generic.simple.direct_to_template

解説:

指定のテンプレートにテンプレート変数 {{ params }} を指定してレンダリン グします。 {{ params }} は URL から取り出したパラメタの辞書になります。

必須の引数:

  • template: 使用するテンプレートの完全な名前です。

オプションの引数:

  • extra_context: テンプレートコンテキストに追加したい値を入れた辞書 です。辞書内の値が呼び出し可能オブジェクトの場合、ビューはテンプレー トのレンダリング直前にオブジェクトを呼び出します。
  • mimetype: 出力結果のドキュメントの MIME タイプです。 デフォルト値は DEFAULT_CONTENT_TYPE 設定の値です。

例題:

例えば、以下のような URL パターンを指定したとしましょう:

urlpatterns = patterns('django.views.generic.simple',
    (r'^foo/$',
        'direct_to_template', {'template': 'foo_index'}),
    (r'^foo/(?P<id>\d+)/$',
        'direct_to_template', {'template': 'foo_detail'}),
)

/foo/ へのリクエストは、 foo_index.html テンプレートを使ったレンダ リングになります。一方、 /foo/15/ へのリクエストは foo_detail.html テンプレートを使ったレンダリングになりますが、このときのコンテキスト変数 {{ params.id }}15 になります。

django.views.generic.simple.redirect_to

解説:

指定の URL へリダイレクトします。

URL を指定する文字列には、辞書スタイルの文字列フォーマットを含めてもよく、 その場合、 URL 中の該当パラメタで補完されます。Because keyword interpolation is always done (even if no arguments are passed in), any "%" characters in the URL must be written as "%%" so that Python will convert them to a single percent sign on output.

URL に None を指定すると、 HttpResponseGone (410) を発行します。

必須の引数:

  • url: リダイレクト先の URL を表す文字列です。 None にすると HTTP 410 エラー (Gone) を送出します。

Optional arguments:

  • permanent: Whether the redirect should be permanent. The only difference here is the HTTP status code returned. If True, then the redirect will use status code 301. If False, then the redirect will use status code 302. By default, permanent is True.
The permanent keyword argument is new in Django 1.1.

例題:

以下の例では、 /foo/<id>//bar/<id>/ にパーマネントリダイレクト (HTTP 状態コード301) します:

urlpatterns = patterns('django.views.generic.simple',
    ('^foo/(?P<id>\d+)/$', 'redirect_to', {'url' : '/bar/%(id)s/'}),
)

This example issues a non-permanent redirect (HTTP status code 302) from /foo/<id>/ to /bar/<id>/:

urlpatterns = patterns('django.views.generic.simple',
    ('^foo/(?P<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/', 'permanent': False}),
)

以下の例では、 /bar/ へのリクエストに対して HTTP 410 エラーを返します:

urlpatterns = patterns('django.views.generic.simple',
    ('^bar/$', 'redirect_to', {'url': None}),
)

This example shows how "%" characters must be written in the URL in order to avoid confusion with Python’s string formatting markers. If the redirect string is written as "%7Ejacob/" (with only a single %), an exception would be raised:

urlpatterns = patterns('django.views.generic.simple',
    ('^bar/$', 'redirect_to', {'url': '%%7Ejacob.'}),
)

日付ベースの汎用ビュー

日付ベースの汎用ビュー (date-based generic view, django.views.generic.date_based モジュール) は、日付ベースのデータを絞 り込めるページを表示するビューです。

django.views.generic.date_based.archive_index

解説:

「新着 (“latest”)」オブジェクトを日付順で表示するトップレベルのインデクスペー ジです。 allow_futureTrue にしない限り、 未来の 日付のオブジェ クトは表示しません。

必須の引数:

  • queryset: アーカイブを提供するオブジェクトの QuerySet です。
  • date_field: QuerySet に指定したモデルの DateField または DateTimeField 型のフィールド名です。日付ベースのアーカイブで、ペー ジに掲載するオブジェクトを決定するために使います。

オプションの引数:

  • num_latest: 最近のオブジェクトとしてテンプレートコンテキストに送 り込まれるオブジェクトの数です。デフォルトは 15 です。
  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。
  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。
  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。
  • allow_empty: オブジェクトがない場合にページを表示するかどうかを示 すブール値です。 False の場合、表示するべきオブジェクトが存在しな ければ、空のインデクスページを表示する代わりに 404 エラーを送出します。 デフォルトは True です。
  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。
  • mimetype: 出力結果のドキュメントに適用する MIME タイプです。 デフォルトの値は DEFAULT_CONTENT_TYPE の設定値になります。
  • allow_future: 「未来の」オブジェクトをページに表示するかどうかを 制御するブール値です。「未来の」オブジェクトとは、 date_field に 指定したフィールドの値が現在の日/時よりも大きいようなオブジェクトで す。デフォルトでは False です。
  • template_object_name: テンプレートコンテキストをテンプレート変数 として渡すときの名前です。デフォルト値は 'latest' です。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_archive.html を使います。ここで:

  • <model_name> はモデル名を全て小文字にしたものです。例えば StaffMember というモデルの場合は staffmember になります。
  • <app_label> はモデルアプリケーションへの Python パスの最も右側の 部分になります。例えば、モデルが apps/blog/models.py に入っていれ ば blog になります。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • date_list: queryset を介してオブジェクトを取得できる年を表す datetime.date オブジェクトのリストです。リストは逆順に並んでいま す。 queryset.dates(date_field, 'year')[::-1] と等価です。
template_object_name に応じて動作が変わるようになりました。
  • latest: date_field の順に並んだ num_latest 個のオブジェク トです。例えば、 num_latest10 であれば、 latestqueryset 内のオブジェクトのうち、最新の 10 個からなるリストです。

    変数の名前は template_object_name パラメタで変更できます。デフォ ルト値は 'latest' です。例えば、 template_object_name'foo' にしたときの変数名は foo です。

django.views.generic.date_based.archive_year

解説:

指定年でオブジェクトのある月のリストを表示する、年ごとのアーカイブページで す。 allow_futureTrue にしない限り、 未来の 日付のオブジェク トは表示しません。

必須の引数:

  • year: アーカイブを提供する年の 4 桁の年号です。
  • queryset: アーカイブを提供するオブジェクトの QuerySet です。
  • date_field: QuerySet に指定したモデルの DateField または DateTimeField 型のフィールド名です。日付ベースのアーカイブで、ペー ジに掲載するオブジェクトを決定するために使います。

オプションの引数:

  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。
  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。
  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。
  • allow_empty: オブジェクトがない場合にページを表示するかどうかを示 すブール値です。 False の場合、表示するべきオブジェクトが存在しな ければ、空のインデクスページを表示する代わりに 404 エラーを送出します。 デフォルトは False です。
  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。
  • template_object_name: テンプレートコンテキスト中で使うテンプレー ト変数の名前を指定します。デフォルトでは 'object' です。ビューは このパラメタに '_list' を追加した値を変数名に使います。
  • make_object_list: 指定年の全てのオブジェクトのリストを取得してテ ンプレートに渡すかどうかを決めるブール値です。 True にすると、オ ブジェクトのリストを object_list という変数で利用できます (object_list は別の名前になるかもしれません。後述の「テンプレート コンテキスト」の節の object_list の説明を参照してください)。 デフォルトでは False になっています。
  • mimetype: 出力結果のドキュメントに適用する MIME タイプです。 デフォルトの値は DEFAULT_CONTENT_TYPE の設定値になります。
  • allow_future: 「未来の」オブジェクトをページに表示するかどうかを 制御するブール値です。「未来の」オブジェクトとは、 date_field に 指定したフィールドの値が現在の日/時よりも大きいようなオブジェクトで す。デフォルトでは False です。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_archive_year.html を使います。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • date_list: 指定年内で queryset を介してオブジェクトを取得でき る月を表す datetime.date オブジェクトのリストです。リストは昇順に 並んでいます。

  • year: 指定年の年号を表す 4 桁の文字列です。

  • object_list: make_object_list パラメタを True にした場合、 この値は指定年内のオブジェクトを日付フィールドで並べたリストになりま す。この変数の名前は template_object_name パラメタの設定に依存し ます。 template_object_name のデフォルト値は 'object' で、例 えば template_object_name の値が 'foo' であれば、変数名は foo_list になります。

    make_object_listFalse の場合、 object_list は空のリス トとしてテンプレートに渡されます。

django.views.generic.date_based.archive_month

解説:

指定月の全てのオブジェクトのリストを表示する、月ごとのアーカイブページです。 allow_futureTrue にしない限り、 未来の 日付のオブジェクトは表 示しません。

必須の引数:

  • year: アーカイブを提供する年の 4 桁の年号 (の文字列) です。
  • month: アーカイブを提供する月のです。 month_format 引数に従っ てフォーマットされています。
  • queryset: アーカイブを提供するオブジェクトの QuerySet です。
  • date_field: QuerySet に指定したモデルの DateField または DateTimeField 型のフィールド名です。日付ベースのアーカイブで、ペー ジに掲載するオブジェクトを決定するために使います。

オプションの引数:

  • month_format: month パラメタで使っているフォーマットを指定す るためのフォーマット文字列です。この値は Python の time.strftime が受け取るのと同じ書法のフォーマット文字列を指定します。 (strftime のドキュメント 参照)。デフォルトでは "%b" に設定さ れており、これは 3 文字で省略して表した月名です。数字を使うように変え たければ "%m" を使って下さい。
  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。
  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。
  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。
  • allow_empty: オブジェクトがない場合にページを表示するかどうかを示 すブール値です。 False の場合、表示するべきオブジェクトが存在しな ければ、空のインデクスページを表示する代わりに 404 エラーを送出します。 デフォルトは False です。
  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。
  • template_object_name: テンプレートコンテキスト内で使うテンプレー ト変数名を示します。デフォルトでは 'object' になっています。ビュー はこの変数名に '_list' を追加して変数名を決定します。
  • mimetype: 出力結果のドキュメントに適用する MIME タイプです。 デフォルトの値は DEFAULT_CONTENT_TYPE の設定値になります。
  • allow_future: 「未来の」オブジェクトをページに表示するかどうかを 制御するブール値です。「未来の」オブジェクトとは、 date_field に 指定したフィールドの値が現在の日/時よりも大きいようなオブジェクトで す。デフォルトでは False です。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_archive_month.html を使います。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • month: 指定月を表す datetime.date オブジェクトです。
  • next_month: 次の月の最初の日を表す datetime.date オブジェクト です。次の月が未来の日付の場合には None になります。
  • previous_month: 前の月の最初の日を表す datetime.date オブジェクト です。 next_month と違い、決して None にはなりません。
  • object_list: 指定月内のオブジェクトからなるリストです。この変数の 名前は template_object_name パラメタの設定に依存します。 template_object_name のデフォルト値は 'object' で、例えば template_object_name の値が 'foo' であれば、変数名は foo_list になります。
django.views.generic.date_based.archive_week

解説:

指定週の全てのオブジェクトのリストを表示する、週ごとのアーカイブページです。 allow_futureTrue にしない限り、 未来の 日付のオブジェクトは表 示しません。

必須の引数:

  • year: アーカイブを提供する年の 4 桁の年号 (の文字列) です。
  • week: アーカイブを提供する週 (の文字列) です。週は日曜から始まり ます。
  • queryset: アーカイブを提供するオブジェクトの QuerySet です。
  • date_field: QuerySet に指定したモデルの DateField または DateTimeField 型のフィールド名です。日付ベースのアーカイブで、ペー ジに掲載するオブジェクトを決定するために使います。

オプションの引数:

  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。
  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。
  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。
  • allow_empty: オブジェクトがない場合にページを表示するかどうかを示 すブール値です。 False の場合、表示するべきオブジェクトが存在しな ければ、空のインデクスページを表示する代わりに 404 エラーを送出します。 デフォルトは False です。
  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。
  • template_object_name: テンプレートコンテキスト内で使うテンプレー ト変数名を示します。デフォルトでは 'object' になっています。ビュー はこの変数名に '_list' を追加して変数名を決定します。
  • mimetype: 出力結果のドキュメントに適用する MIME タイプです。 デフォルトの値は DEFAULT_CONTENT_TYPE の設定値になります。
  • allow_future: 「未来の」オブジェクトをページに表示するかどうかを 制御するブール値です。「未来の」オブジェクトとは、 date_field に 指定したフィールドの値が現在の日/時よりも大きいようなオブジェクトで す。デフォルトでは False です。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_archive_week.html を使います。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • week: 指定週を表す datetime.date オブジェクトです。
  • object_list: 指定週内のオブジェクトからなるリストです。この変数の 名前は template_object_name パラメタの設定に依存します。 template_object_name のデフォルト値は 'object' で、例えば template_object_name の値が 'foo' であれば、変数名は foo_list になります。
django.views.generic.date_based.archive_day

解説:

指定日の全てのオブジェクトのリストを表示する、日ごとのアーカイブページです。 allow_futureTrue にしない限り、 未来の 日付のオブジェクトを表 示させようとすると、該当するオブジェクトの有無にかかわらず 404 エラーを送出 します。

必須の引数:

  • year: アーカイブを提供する年の 4 桁の年号 (の文字列) です。
  • month: アーカイブを提供する月です。 month_format 引数に従って フォーマットされています。
  • day: アーカイブを提供する日です。 day_format 引数に従ってフォー マットされています。
  • queryset: アーカイブを提供するオブジェクトの QuerySet です。
  • date_field: QuerySet に指定したモデルの DateField または DateTimeField 型のフィールド名です。日付ベースのアーカイブで、ペー ジに掲載するオブジェクトを決定するために使います。

オプションの引数:

  • month_format: month パラメタで使っているフォーマットを指定す るためのフォーマット文字列です。この値は Python の time.strftime が受け取るのと同じ書法のフォーマット文字列を指定します。 (strftime のドキュメント 参照)。デフォルトでは "%b" に設定さ れており、これは 3 文字で省略して表した月名です。数字を使うように変え たければ "%m" を使って下さい。
  • day_format: month_format に似ていますが、 day パラメタ用 です。デフォルト値は "%d" (日付を 01-31 の 2 桁の 10 進数で表した もの) です。
  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。
  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。
  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。
  • allow_empty: オブジェクトがない場合にページを表示するかどうかを示 すブール値です。 False の場合、表示するべきオブジェクトが存在しな ければ、空のインデクスページを表示する代わりに 404 エラーを送出します。 デフォルトは False です。
  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。
  • template_object_name: テンプレートコンテキスト内で使うテンプレー ト変数名を示します。デフォルトでは 'object' になっています。ビュー はこの変数名に '_list' を追加して変数名を決定します。
  • mimetype: 出力結果のドキュメントに適用する MIME タイプです。 デフォルトの値は DEFAULT_CONTENT_TYPE の設定値になります。
  • allow_future: 「未来の」オブジェクトをページに表示するかどうかを 制御するブール値です。「未来の」オブジェクトとは、 date_field に 指定したフィールドの値が現在の日/時よりも大きいようなオブジェクトで す。デフォルトでは False です。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_archive_day.html を使います。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • day: 指定日を表す datetime.date オブジェクトです。
  • next_day: 次の日を表す datetime.date オブジェクトです。次の 日が未来の日付の場合には None になります。
  • previous_day: 前の日を表す datetime.date オブジェクトです。 next_day と違い、決して None にはなりません。
  • object_list: 指定月内のオブジェクトからなるリストです。この変数の 名前は template_object_name パラメタの設定に依存します。 template_object_name のデフォルト値は 'object' で、例えば template_object_name の値が 'foo' であれば、変数名は foo_list になります。
django.views.generic.date_based.archive_today

解説:

今日 の全てのオブジェクトを表示する日ごとアーカイブページです。このページ は archive_day と全く同じで、 year/month/day といった引数を とらず、今日の日付を使う点だけが違います。

django.views.generic.date_based.object_detail

解説:

個々のオブジェクトを表現するページです。オブジェクトに設定された時刻が未来 を表す値の場合、 allow_futureTrue にしない限り、このビューはデフォ ルトで 404 エラーを送出します。

必須の引数:

  • year: オブジェクトの日付の年部分で、 4 桁の年号 (の文字列) です。

  • month: オブジェクトの日付の月部分で、 month_format 引数に従っ てフォーマットされています。

  • day: オブジェクトの日付の日部分で、 day_format 引数に従って フォーマットされています。

  • queryset: オブジェクトの入っている QuerySet です。

  • date_field: QuerySet に指定したモデルの DateField または DateTimeField 型のフィールド名です。汎用ビューが year, month, day に応じてオブジェクトを照合するために使います。

  • object_id または (slug slug_field) が必要です。

    object_id を使う場合、ページに表示するオブジェクトの主キーとなる フィールドの値を指定せねばなりません。

    そうでない場合には、 slug にオブジェクトの slug を、 slug_fieldQuerySet に指定したモデルの slug フィールド名を 指定せねばなりません。 slug_field のデフォルト値は 'slug' で す。

オプションの引数:

  • month_format: month パラメタで使っているフォーマットを指定す るためのフォーマット文字列です。この値は Python の time.strftime が受け取るのと同じ書法のフォーマット文字列を指定します。 (strftime のドキュメント 参照)。デフォルトでは "%b" に設定さ れており、これは 3 文字で省略して表した月名です。数字を使うように変え たければ "%m" を使って下さい。

  • day_format: month_format に似ていますが、 day パラメタ用 です。デフォルト値は "%d" (日付を 01-31 の 2 桁の 10 進数で表した もの) です。

  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。

  • template_name_field: オブジェクトの表示に使うテンプレート名が入っ たフィールドの名前です。このパラメタを使うと、データ中にテンプレート 名を保存しておけます。 例えば、オブジェクトに 'the_template' という名前のフィールドがあ り、その値が 'foo.html' という文字列の場合、 template_name_field'the_template' に指定しておくと、汎用 ビューはオブジェクトの表示に 'foo.html' を使おうとするわけです。

    ちょっと首を捻りたくなるような機能ですが、場合によってはとても便利な 機能です。

  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。

  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。

  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。

  • template_object_name: テンプレートコンテキスト内で使うテンプレー ト変数名を示します。デフォルトでは 'object' になっています。ビュー はこの変数名に '_list' を追加して変数名を決定します。

  • mimetype: 出力結果のドキュメントに適用する MIME タイプです。 デフォルトの値は DEFAULT_CONTENT_TYPE の設定値になります。

  • allow_future: 「未来の」オブジェクトをページに表示するかどうかを 制御するブール値です。「未来の」オブジェクトとは、 date_field に 指定したフィールドの値が現在の日/時よりも大きいようなオブジェクトで す。デフォルトでは False です。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_detail.html を使います。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • object: オブジェクトです。この変数変の名前は template_object_name パラメタの値に依存し、そのデフォルト値は 'object' です。 template_object_name'foo' の場合、変 数名は foo になります。

リスト/詳細形式の汎用ビュー

リスト-詳細 (list/detail) 形式の汎用ビューフレームワーク (django.views.generic.list_detail モジュール) は、日付ベースの汎用ビュー に似ていますが、オブジェクトのリストと個々のオブジェクトのページという二つ のビューしか持ちません。

django.views.generic.list_detail.object_list

解説:

オブジェクトのリストを表現するページです。

必須の引数:

  • queryset: オブジェクトの入っている QuerySet です。

オプションの引数:

  • paginate_by: ページあたり何個のオブジェクトを表示するかを指定する 整数です。この引数を指定すると、ビューはオブジェクトをページあたり paginate_by 個のオブジェクトに分割します。ビューは (GET を介 して渡される) クエリ文字列パラメタか、 URLconf で指定した変数 page を引数にとります。詳しくは下記の 「 pagination に関する注意 」を参照してください。
  • page: 現在のページ番号を指定する 1 から始まる整数値か、文字列 'last' です。詳しくは下記の「 pagination に関する注意 」を参照 してください。
  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。
  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。
  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。
  • allow_empty: オブジェクトがない場合にページを表示するかどうかを示 すブール値です。 False の場合、表示するべきオブジェクトが存在しな ければ、空のインデクスページを表示する代わりに 404 エラーを送出します。 デフォルトは True です。
  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。
  • template_object_name: テンプレートコンテキスト内で使うテンプレー ト変数名を示します。デフォルトでは 'object' になっています。ビュー はこの変数名に '_list' を追加して変数名を決定します。
  • mimetype: 出力結果のドキュメントに適用する MIME タイプです。 デフォルトの値は DEFAULT_CONTENT_TYPE の設定値になります。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_list.html を使います。

テンプレートコンテキスト:

paginator および page_obj が追加されました。

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • object_list: オブジェクトのリストです。この変数の名前は template_object_name パラメタの設定に依存します。 template_object_name のデフォルト値は 'object' で、例えば template_object_name の値が 'foo' であれば、変数名は foo_list になります。
  • is_paginated: 表示結果がページ分割されているかどうかを示すブール 値です。具体的には、オブジェクトの個数が paginate_by と等しいかそ れ以下の場合には False にセットされます。

表示結果がページ分割されている場合、コンテキストには以下の追加の変数が入り ます:

  • paginator: django.core.paginator.Paginator のインスタンスです。
  • page_obj: django.core.paginator.Page のインスタンスです。
ペジネーションに関する注意

paginate_by を指定した場合、 Django は結果をページ分割 (ペジネーション) します。 URL でページ番号を指定するには二つの方法があります:

  • URLconf で page パラメタをキャプチャします。例えば、 URLconf は以 下のようになるでしょう:

    (r'^objects/page(?P<page>[0-9]+)/$', 'object_list', dict(info_dict))
    
  • ページ番号をクエリ文字列パラメタ page に渡します。例えば URL は以 下のようになります:

    /objects/?page=3
    
  • 全てのページ番号にわたるループを実施したい場合は、 page_range を 使ってください。例えば、page_range にわたる反復処理を行って、 全てのページへのリンクを作成できます。

pagepage_range は 0 ではなく 1 から始まる数で指定します。従って 最初のページのページ番号は 1 です。

ペジネーションの詳細は、 Pagination のドキュメント を参照してください。

特別なケースとして、 page の値に last を使えます:

/objects/?page=last

このようにすると、いちいち総ページ数を数えなくても、最後のページにアクセス できます。

page の値は実在するページ番号か、 last でなければなりません。それ以 外の値を page に指定すると 404 エラーを引き起こします。

django.views.generic.list_detail.object_detail

個々のオブジェクトを表現するページです。

解説:

個々のオブジェクトを表現するページです。

必須の引数:

  • queryset: オブジェクトの入っている QuerySet です。

  • object_id または (slug slug_field) が必要です。

    object_id を使う場合、ページに表示するオブジェクトの主キーとなる フィールドの値を指定せねばなりません。

    そうでない場合には、 slug にオブジェクトの slug を、 slug_fieldQuerySet に指定したモデルの slug フィールド名を 指定せねばなりません。 slug_field のデフォルト値は 'slug' で す。

オプションの引数:

  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。

  • template_name_field: オブジェクトの表示に使うテンプレート名が入っ たフィールドの名前です。このパラメタを使うと、データ中にテンプレート 名を保存しておけます。 別の言い方をするなら、オブジェクトに 'the_template' という名前の フィールドがあり、その値が 'foo.html' という文字列の場合、 template_name_field'the_template' に指定しておくと、汎用 ビューはオブジェクトの表示に 'foo.html' を使おうとします。

    ちょっと首を捻りたくなるような機能ですが、場合によってはとても便利な 機能です。

  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。

  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。

  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。

  • template_object_name: テンプレートコンテキスト内で使うテンプレー ト変数名を示します。デフォルトでは 'object' になっています。ビュー はこの変数名に '_list' を追加して変数名を決定します。

  • mimetype: 出力結果のドキュメントに適用する MIME タイプです。 デフォルトの値は DEFAULT_CONTENT_TYPE の設定値になります。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_detail.html を使います。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • object: オブジェクトです。この変数変の名前は template_object_name パラメタの値に依存し、そのデフォルト値は 'object' です。 template_object_name'foo' の場合、変 数名は foo になります。

作成/更新/削除の汎用ビュー

django.views.generic.create_update モジュールには、オブジェクトの作成 (create)、編集 (edit, update)、削除 (delete) のための関数が入っています。

django.views.generic.create_update.create_objectdjango.views.generic.create_update.update_object は、 forms ライブラリ を使ってフォームを生成・表示す るようになりました。

django.views.generic.create_update.create_object

解説:

オブジェクト作成のためのフォームを表示し、オブジェクトを保存するためのペー ジです。検証エラーが生じた場合にはフォームを再表示します。

必須の引数:

  • form_class または model のいずれかを指定せねばなりません。

    form_class を指定する場合には、 django.forms.ModelForm クラスのサブクラスを指定します。この引数は、モデルのフォームをカスタ マイズしたいときに使います。詳しくは ModelForm のドキュメント を参照して ください。

    model には Django のモデルクラスを指定します。この場合、フォーム は model に対する標準の ModelForm で生成されます。

オプションの引数:

  • post_save_redirect: はオブジェクトを保存した後のビューのリダイレ クト先 の URL です。デフォルト値は object.get_absolute_url() です。

    post_save_redirect には、辞書を使う文字列フォーマット引数を含めら れます。辞書のキーはオブジェクトのフィールド名に解釈されます。例えば、 post_save_redirect="/polls/%(slug)s/" のように指定できます。

  • login_required: オブジェクトを編集し、変更を保存するため編集にロ グインが必要かどうかを指定するブール値です。 Django の 認証システム にフックをかけます。デフォルト値は False です。

    この値が True の場合、匿名ユーザがこのページを訪問したりフォーム を保存しようとしたりすると、 Django はリクエストを /accounts/login/ にリダイレクトします。

  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。

  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。

  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。

  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_form.html を使います。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • form: オブジェクトを編集するためのフォームを表現する django.forms.ModelForm インスタンスです。この変数を使うと、テ ンプレートシステム中でフォームフィールドを簡単に参照できます。

    例えば、モデルが nameaddress という二つのフィールドを持っ ている場合は、以下のように書けます:

    <form action="" method="post">
    <p>{{ form.name.label_tag }} {{ form.name }}</p>
    <p>{{ form.address.label_tag }} {{ form.address }}</p>
    </form>
    

    Form オブジェクトをテンプレート内で使う方法の詳しい説明は、 forms のドキュメント を参照してください。

django.views.generic.create_update.update_object

解説:

既存のオブジェクトを編集するためのフォームを表示し、オブジェクトを保存する ためのページです。検証エラーが生じた場合にはフォームを再表示します。

必須の引数:

  • form_class または model のいずれかを指定せねばなりません。

    form_class を指定する場合には、 django.forms.ModelForm クラスのサブクラスを指定します。この引数は、モデルのフォームをカスタ マイズしたいときに使います。詳しくは ModelForm のドキュメント を参照して ください。

    model には Django のモデルクラスを指定します。この場合、フォーム は model に対する標準の ModelForm で生成されます。

  • object_id または (slug slug_field) が必要です。

    object_id を使う場合、ページに表示するオブジェクトの主キーとなる フィールドの値を指定せねばなりません。

    そうでない場合には、 slug にオブジェクトの slug を、 slug_fieldQuerySet に指定したモデルの slug フィールド名を 指定せねばなりません。 slug_field のデフォルト値は 'slug' で す。

オプションの引数:

  • post_save_redirect: オブジェクトを保存した後のビューのリダイレ クト先 の URL です。デフォルト値は object.get_absolute_url() です。

    post_save_redirect には辞書を使う文字列フォーマット引数が入ります。 辞書のキーはオブジェクトのフィールド名に解釈されます。例えば、 post_save_redirect="/polls/%(slug)s/" のように指定できます。

  • login_required: オブジェクトを編集し、変更を保存するため編集にロ グインが必要かどうかを指定するブール値です。 Django の 認証システム にフックをかけます。デフォルト値は False です。

    この値が True の場合、匿名ユーザがこのページを訪問したりフォーム を保存しようとしたりすると、 Django はリクエストを /accounts/login/ にリダイレクトします。

  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。

  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。

  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。

  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。

  • template_object_name: テンプレートコンテキスト内で使うテンプレー ト変数名を示します。デフォルトでは 'object' になっています。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_form.html を使います。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • form: オブジェクトを編集するためのフォームを表現する django.oldforms.ModelForm インスタンスです。この変数を使うと、テ ンプレートシステム中でフォームフィールドを簡単に参照できます。

    例えば、モデルが nameaddress という二つのフィールドを持っ ている場合は、以下のように書けます:

    <form action="" method="post">
    <p>{{ form.name.label_tag }} {{ form.name }}</p>
    <p>{{ form.address.label_tag }} {{ form.address }}</p>
    </form>
    

    Form オブジェクトをテンプレート内で使う方法の詳しい説明は、 forms のドキュメント を参照してください。

  • object: オブジェクトです。この変数変の名前は template_object_name パラメタの値に依存し、そのデフォルト値は 'object' です。 template_object_name'foo' の場合、変 数名は foo になります。

django.views.generic.create_update.delete_object

解説:

既存のオブジェクトを削除するための確認ページを表示し、オブジェクトを削除する ためのページです。オブジェクトを削除するのはリクエストメソッドが POST であった場合だけです。このビューを GET で取得すると、同じ URL に対して POST を行うような確認ページを表示します。

必須の引数:

  • model: フォームで削除するオブジェクトの Django モデルクラス です。

  • object_id または (slug slug_field) が必要です。

    object_id を使う場合、ページに表示するオブジェクトの主キーとなる フィールドの値を指定せねばなりません。

    そうでない場合には、 slug にオブジェクトの slug を、 slug_fieldQuerySet に指定したモデルの slug フィールド名を 指定せねばなりません。 slug_field のデフォルト値は 'slug' で す。

  • post_delete_redirect: オブジェクトを削除した後のビューのリダイレ クト先 の URL です。

オプションの引数:

  • login_required: ページを表示し、変更を保存するため編集にログイン が必要かどうかを指定するブール値です。 Django の 認証システム にフックをかけます。デフォルト値は False です。

    この値が True の場合、匿名ユーザがこのページを訪問したりフォーム を保存しようとしたりすると、 Django はリクエストを /accounts/login/ にリダイレクトします。

  • template_name: ページのレンダリングに使うテンプレートの完全な名前 です。この変数を使うと、デフォルトのテンプレート名 (下記参照) をオー バライドできます。

  • template_loader: テンプレートのロードに使うテンプレートローダです。 デフォルトでは django.template.loader になっています。

  • extra_context: テンプレートコンテキストに追加する値からなる辞書で す。デフォルトでは、この辞書は空になっています。辞書内の値が呼び出し 可能オブジェクトの場合、汎用ビューはテンプレートのレンダリング直前に そのオブジェクトを呼び出します。

  • context_processors: ビューのテンプレートに適用するテンプレートコ ンテキストプロセッサのリストです。

  • template_object_name: テンプレートコンテキスト内で使うテンプレー ト変数名を示します。デフォルトでは 'object' になっています。

テンプレート名:

template_name を指定しない場合、ビューはデフォルトのテンプレートである <app_label>/<model_name>_confirm_delete.html を使います。

テンプレートコンテキスト:

extra_context の値に加え、テンプレートのコンテキストには以下の変数が入 ります:

  • object: オブジェクトです。この変数変の名前は template_object_name パラメタの値に依存し、そのデフォルト値は 'object' です。 template_object_name'foo' の場合、変 数名は foo になります。

ミドルウェア

revision-up-to:17812 (1.4)

このドキュメントでは、 Django に付属している全ミドルウェアコンポーネントに ついて解説しています。ミドルウェアの使い方や自作のミドルウェアの書き方は ミドルウェアの使い方ガイド を参照してくださ い。

利用できるミドルウェア

キャッシュミドルウェア
class UpdateCacheMiddleware
class FetchFromCacheMiddleware

サイト全体にわたるキャッシュを有効にします。キャッシュを有効にすると、 Django の管理下にあるページは CACHE_MIDDLEWARE_SECONDS 設定に定 義した時間のキャッシュされます。 キャッシュのドキュメント を参照してください。

コモンミドルウェア
class CommonMiddleware

リクエスト処理に完全主義者むけの便宜機能を追加するミドルウェアです:

  • DISALLOWED_USER_AGENTS に設定されたユーザエージェントから のアクセスを禁止します。 DISALLOWED_USER_AGENTS には文字列 のリストを指定します。

  • APPEND_SLASH および PREPEND_WWW に基づいて URL の書き換えを行います。

    APPEND_SLASHTrue の場合、リクエストの URL の末尾が スラッシュで終わっておらず、 URLconf 上でもマッチしなければ、 スラッ シュを付加した URL を作成して、 URLconf でマッチするか確かめます。マッ チすれば、スラッシュつきの URL にリダイレクトします。そうでなければ、 URL を通常の手順に従って処理します。

    例えば、 foo.com/bar に一致するパターンがなく、 foo.com/bar/ に一致するパターンが あればfoo.com/barfoo.com/bar/ にリダイレクトされます。

    PREPEND_WWWTrue であれば、先頭に, “www.” のない URL は先頭に”www.” を付けた URL にリダイレクトします。

    それぞれのオプションは URL を正規化するためのものです。これは、 URL (Uniform Resorce Location) がただひとつの、真にただひとつの場所 (Location) を表すべきであるという哲学に基づいています。技術的には、 foo.com/barfoo.com/bar/ とは別物です – 例えば、検索エン ジンはこの二つの URL を別々の URL として扱うかもしれません – ですか ら、 URL を正規化しておく方が得策なのです。

  • SEND_BROKEN_LINK_EMAILSTrue の場合、 MANAGERS にリンク切れ報告のメールを送信します。

  • USE_ETAGS 設定に基づいて ETag を処理します。 USE_ETAGSTrue に設定すると、 Django は各リクエスト ごとにページ内容の MD-5 ハッシュを計算して ETag にし、必要なら Not Modified 応答を返します。

ビューメタデータミドルウェア
class XViewMiddleware

INTERNAL_IPS 設定に定義されている IP アドレスから来た HEAD リク エストに対してカスタムの X-View HTTP ヘッダを送信します。このミドルウェ アはDjango の 自動ドキュメントシステム で使われています。 これは AuthenticationMiddleware に依存 しています。

GZip ミドルウェア
class GZipMiddleware

GZip 圧縮を受け付けるブラウザ (最近のほとんどのブラウザがそうです) 向けに、 コンテンツを圧縮して送ります。

このミドルウェアは、ミドルウェアリストの先頭に置くよう勧めます。なのでレスポンス コンテンツの圧縮は最後に行われます。

以下のいずれかの場合にはコンテンツを圧縮しません:

  • コンテンツボディーが 200 バイト長未満の場合。
  • レスポンスに Content-Encoding ヘッダがすでに設定されている場合。
  • (ブラウザの) リクエストが、 gzip を含む Accept-Encoding ヘッダーを 送らなかった場合。
  • Internet Explorer からのリクエストで、 Content-Type ヘッダが javascript か、 text/ 以外から始まるものを持っている場合。 IE の古いバージョンにあるバグを避けるためです。特定のコンテンツタイプで 実行されるべきではない解凍を引き起こすからです。

個別のビュー GZip 圧縮 を使いたい場合は gzip_page() デコレータを使いましょう。

条件付き GET ミドルウェア
class ConditionalGetMiddleware

条件付き GET 操作を処理します。レスポンスに ETag または Last-Modified ヘッダがあり、リクエストに If-None-Match または If-Modified-Since がある場合、レスポンスを HttpNotModified に置き換えます。

また、 Date および Content-Length ヘッダを設定します。

リバースプロキシミドルウェア
class SetRemoteAddrFromForwardedFor

このミドルウェアは Django 1.1 で廃止されました。詳細は リリースノート を 参照してください。

ロケールミドルウェア
class LocaleMiddleware

リクエストに基づいて言語の選択を行います。言語の選択によって、ユーザごとに 提供するコンテンツをカスタマイズできます。 国際化のドキュメント を参照してください。

メッセージミドルウェア
class MessageMiddleware
MessageMiddleware が追加されました。

クッキー、セッションベースのメッセージがサポートされました。 messages documentation を参照してください。

セッションミドルウェア
class SessionMiddleware

セッションのサポートを有効にします。 セッションのドキュメント も参照してください。

認証ミドルウェア
class AuthenticationMiddleware

入力される HttpRequest オブジェクト全てに、現在ログインしているユーザを 表す user 属性を追加します。 Web リクエストの認証 を参照してください。

CSRF 対策ミドルウェア
class CsrfViewMiddleware

POST フォームに隠しフォームフィールドを追加し、リクエストデータに正しい値が 設定されているかチェックすることによりクロスサイトリクエストフォージェリ (CSRF) を防ぎます。詳しくは クロスサイトリクエストフォージェリからの保護 を参 照してください。

トランザクションミドルウェア
class TransactionMiddleware

リクエスト/レスポンス処理フェイズに commit と rollback をバインドします。 あるビュー関数の実行に成功した場合に commit を、例外を送出して失敗した場合 には rollback を行わせます。

このミドルウェアでは、スタック中の順番が重要になります。このミドルウェアの 外で動作する他のミドルウェアモジュールは、Django のデフォルトの挙動、すなわ ち commit-on-save モードで動作します。このミドルウェアの内側にある (スタッ クの後ろに位置している) ミドルウェアは、ビュー関数と同じトランザクション制 御下に置かれます。

トランザクション管理のドキュメント を参照し てください。

X-Frame-Options middleware
class XFrameOptionsMiddleware
XFrameOptionsMiddleware が追加されました。

単純な X-Frame-Options ヘッダによるクリックジャッキング対策

モデル

revision-up-to:17812 (1.4)

モデルの API リファレンスです。モデルの解説は モデルの作成 を 参照してください。

モデルフィールドリファレンス

revision-up-to:17812 (1.4) unfinished

このドキュメントは、 Django が提供している フィールドのオプションフィールド型 の雑多で細かい解説です。

See also

組み込みのフィールド型で不足なことがあれば django.contrib.localflavor を試してみてください。これは特定の国や文化で便利に使えるコードの詰め合わせ になっています。また、 独自のカスタムモデルフィールドの作成 も簡単にできます。

Note

技術的には、モデルフィールドは django.db.models.fields モジュー ルで定義されていますが、便宜上、 django.db.models 内で import さ れています。モデルフィールドを使うときは、慣習的に from django.db import models として、 models.<Foo>Field のよう に参照します。

フィールドオプション

全てのフィールド型で、以下の引数を指定できます。これらの引数はすべてオプショ ンです。

null
Field.null

True にすると、 Django は空の値を NULL としてデータベースに入れます。 デフォルト値は False です。

空の文字列値は NULL ではなく空文字列として保存されることに注意して下さ い。 null=True が使えるのは、整数型やブール型、日付のような、文字列では ないフィールド型の場合だけです。 null はデータベースでの記録 操作にのみかかわるパラメタなので、フォーム上で空の値を入力できるようにした ければ blank=True も指定する必要があるでしょう (blank も 参照してください)。

特別な理由のない限り、 CharFieldTextField のような、 文字列ベースのフィールドには null を指定しないでください。 文字列ベースのフィールドが null=True であるということは、「データがない」 ことを表すのに NULL と空文字列という二つの値が存在することを示します。 多くの場合、「データがない」ことを表すのに二つのを取り得るのは冗長でしかあ りません。 Django の慣習では、データのない文字列フィールドの値は NULL ではなく空文字列です。

Note

Oracle バックエンドを使っている場合、データベースの制約のため、 空文字列を許すような文字列ベースのフィールドは、 null=True オプショ ンが強制的に付加され、 NULL は空の文字列を指します。

If you want to accept null values with BooleanField, use NullBooleanField instead.

blank
Field.blank

True にすると、フィールドの値を空白 (blank) にできます。デフォルト値は False です。

null とは違うことに注意してください。 null が 純粋にデータベース上の表現に関わる概念であるのに対し、 blank とは値の検証 (validation) に関わる概念です。あるフィールドに blank=True を指定すると、 Django の admin サイト上で、空の値のエントリを作成できます。 blank=False にすると、そのフィールドには必ず値を入れねばなりません。

choices
Field.choices

2 要素のタプルからなる iterable (リストまたはタプル) を、フィールドの値の選 択肢にします。

この値を指定すると、 Django の admin には標準的なテキストフィールドの代わり に選択ボックスが表示され、指定された選択肢だけをえらべます。

選択肢リストは以下のように指定します:

YEAR_IN_SCHOOL_CHOICES = (
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
)

各タプルの最初の要素は、データベースに実際に保存される値です。二つ目の値は 各オプションに対する人間可読な名前です。

選択肢リストは、モデルクラスの一部として定義できます:

class Foo(models.Model):
    GENDER_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female'),
    )
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)

また、モデルクラスの外でも定義できます:

GENDER_CHOICES = (
    ('M', 'Male'),
    ('F', 'Female'),
)
class Foo(models.Model):
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)

また、選択肢をグループごとに集めて、名前をつけられます:

MEDIA_CHOICES = (
    ('Audio', (
            ('vinyl', 'Vinyl'),
            ('cd', 'CD'),
        )
    ),
    ('Video', (
            ('vhs', 'VHS Tape'),
            ('dvd', 'DVD'),
        )
    ),
    ('unknown', 'Unknown'),
)

各タプルの最初の要素は、選択肢グループの名前です。二つ目の要素は、2 要素の タプルからなるイテレーション可能なオブジェクトです。各 2 要素タプルには、 選択肢の値と、人間可読な名前を指定します。(上の例の unknown オプション のように) グループ化されたオプションとされていないオプションを混ぜても構い ません。

choices セットを持つモデルフィールド各々について、 Django は 特殊なメソッドを追加し、フィールドの現在値を人間可読な形式で取得できるよう にします。データベース API ドキュメントの get_FOO_display() を参照してください。

最後に、 choices はリストやタプルでなくともよく、任意の iterable オブジェク トでかまわないことに注意してください。つまり、 choices は動的生成できるので す。とはいえ、 choices を動的生成するようなハックをするくら いなら、適当なデータベーステーブルを ForeignKey で参照した方がよい でしょう。というのも、 choices はあまり変更のない静的な選択 肢のためのオプションだからです。

db_column
Field.db_column

フィールドに使うデータベースカラム名です。この値を指定しなければ、 Django はフィールド名を使います。

データベースカラム名が SQL の予約語であったり、 Python で変数名として使えな い文字を含んでいる (よくあるのはハイフンです) 場合でも問題ありません。 舞台裏で Django はカラム名やテーブル名をクオートします。

db_index
Field.db_index

True にすると django-admin.py sqlindexes を実行した時に、フィールドに対して CREATE INDEX 文を出力します。

db_tablespace
Field.db_tablespace

フィールドをインデクス化する場合に、このインデクスを格納する データベースのテーブルスペース の名前です。デフォルトの値は、プロジェクトで設定されている DEFAULT_INDEX_TABLESPACE です。この値がなければ、モデルの db_tablespace を使います。データベースバックエンドが インデクス格納用テーブルスペースをサポートしていない場合、 このオプションは無視されます。

default
Field.default

フィールドのデフォルト値です。この値は、何らかの値でも、呼び出し可能オブジェ クトでもかまいません。呼び出し可能オブジェクトの場合、新たなオブジェクトが 生成されるたびに呼び出されます。

editable
Field.editable

False にすると、 admin 上や、モデルクラスから生成したフォームの上でフィー ルドの値を編集できなくなります。デフォルト値は True です。

error_messages
リリースノートを参照してください
Field.error_messages

The error_messages argument lets you override the default messages that the field will raise. Pass in a dictionary with keys matching the error messages you want to override.

Error message keys include null, blank, invalid, invalid_choice, and unique. Additional error message keys are specified for each field in the `Field types`_ section below.

help_text
Field.help_text

オブジェクトの admin フォームの下に表示される、追加の「ヘルプ」テキストです。 とはいえ、オブジェクトが admin のフォームを持っていなくてもドキュメントとし て有用でしょう。

この値は admin インタフェース上に表示されるときに HTML エスケープされ ない ので注意してください。必要ならば、下記の例のように help_text に HTML を含めてもかまいません:

help_text="Please use the following format: <em>YYYY-MM-DD</em>."

プレーンテキストを使って、 django.utils.html.escape() でHTML の特殊文字 をエスケープしてもかまいません。

primary_key
Field.primary_key

True に指定すると、フィールドをモデルの主キーにします。

モデルのどのフィールドにも primary_key=True を指定しなければ、Django は 自動的に IntegerField を追加して主キーを保存します。従って、デフォ ルトの主キーの振舞いを変更したいのでないかぎり、 primary_key=True をフィー ルドに指定しておく必要はありません。詳しくは 主キーフィールドの自動設定 を参照してください。

primary_key=True であるということは、 null=False かつ unique=True であることを指します。一つのオブジェ クトには一つしか主キーを指定できません。

unique
Field.unique

True であれば、フィールドはテーブル全体で一意の値を取らねばなりません。

この制約は、データベースレベルと Django の admin のレベルで適用されます。 重複した値を持つ unique フィールドを含んだモデルを保存しよう とすると、モデルの save() メソッドによって django.db.IntegrityError が送出されます。

このオプションは、 ManyToManyField 以外の全てのフィールドで利用で きます。

unique_for_date
Field.unique_for_date

DateFieldDateTimeField 型のフィールドの名前を指定して おくと、そのフィールドの日付に対して一意な値になるように制約します。

例えば、 title という名前のフィールドがあり、 unique_for_date="pub_date" が指定されていたとすると、 Django は同じ titlepub_date の値を持つようなエントリを受け入れません。

この制約は Django の admin フォームのレベルで適用され、データベースレベルで は適用されません。

unique_for_month
Field.unique_for_month

unique_for_date と同様ですが、フィールドの値が月ごとに一意で あるように制約します。

unique_for_year
Field.unique_for_year

unique_for_dateunique_for_month と同じで す。

verbose_name
Field.verbose_name

A human-readable name for the field. If the verbose name isn’t given, Django will automatically create it using the field’s attribute name, converting underscores to spaces. See Verbose field names.

validators
リリースノートを参照してください
Field.validators

A list of validators to run for this field. See the validators documentation for more information.

フィールド型
AutoField
class AutoField(**options)

IntegerField の一種で、利用可能な ID の中から自動的にインクリメン トしていきます。通常、このフィールドが直接必要になることはないでしょう。主 キーのフィールドは、特に指定しない限り自動的に追加されます。 主キーフィールドの自動設定 を参照してください。

BigIntegerField
リリースノートを参照してください
class BigIntegerField([**options])

A 64 bit integer, much like an IntegerField except that it is guaranteed to fit numbers from -9223372036854775808 to 9223372036854775807. The admin represents this as an <input type="text"> (a single-line input).

BooleanField
class BooleanField(**options)

真偽 (true/false) 値を表すフィールドです。

admin ではこのフィールドはチェックボックスとして表現されます。

If you need to accept null values then use NullBooleanField instead.

In previous versions of Django when running under MySQL BooleanFields would return their data as ints, instead of true bools. See the release notes for a complete description of the change.
CharField
class CharField(max_length=None[, **options])

文字列フィールドで、短い文字列からやや長いものに適しています。

大量のテキストを入れたい場合には TextField を使っ て下さい。

admin では <input type="text"> (一行の入力フィールド) で表現されます。

CharField 必須の引数があります:

CharField.max_length

フィールドの (文字数で表した) 最大長です。 max_length への制約はデー タベースと Django 内の検証の両方のレベルで行われます。

Note

If you are writing an application that must be portable to multiple database backends, you should be aware that there are restrictions on max_length for some backends. Refer to the database backend notes for details.

MySQL ユーザへの注意

MySQLdb 1.2.2 でこのフィールドを使っていて、コレーションを (デフォルト 設定 でない) utf8_bin に設定していると、いろいろと問題を引き起こ します。詳しくは MySQL データベースに関する注意 を参照してください。

CommaSeparatedIntegerField
class CommaSeparatedIntegerField(max_length=None[, **options])

カンマで区切った整数からなるフィールドです。 CharField と同じく、 max_length 引数が必要です。

DateField
class DateField([auto_now=False, auto_now_add=False, **options])

日付フィールドです。オプションの引数がいくつかあります:

DateField.auto_now

オブジェクトを保存する度に、その時の時刻を自動的に設定します。 “last-modified” タイムスタンプの実現に便利です。この値はオーバライドで きるデフォルト値ではなく、 常に 現在の日付になるので注意してください。

DateField.auto_now_add

オブジェクトを生成した時の時刻を自動的に設定します。タイムスタンプの生 成に便利です。この値はオーバライドできるデフォルト値ではなく、 常に 現在の日付になるので注意してください。

admin では、 JavaScript のカレンダーと 「今日」へのショートカットのついた <input type="text"> として表現されます。追加エラーメッセージのキー invalid_date を含みます。

Note

As currently implemented, setting auto_now or auto_now_add to True will cause the field to have editable=False and blank=True set.

DateTimeField
class DateTimeField([auto_now=False, auto_now_add=False, **options])

日付と時刻のフィールドです。 DateField と同じオプションを取ります。

admin では JavaScript のショートカットのついた <input type="text"> フィールドで表現されます。

DecimalField
class DecimalField(max_digits=None, decimal_places=None[, **options])

固定精度の 10 進小数です。 Python の Decimal 型インスタン スとして表現されます。 必須の 引数が 2 つあります:

DecimalField.max_digits

値を表現するのに使える最大桁数です。なお decimal_places が指定された場合、それ以上の値である必要があります。

DecimalField.decimal_places

小数部の保存に使われる桁数です。

例えば、小数部が 2 桁で、 999 までの数を表現できるようなフィールドを作成す るには、以下のようにします:

models.DecimalField(..., max_digits=5, decimal_places=2)

小数部の精度が 10 桁で、 10 億までの数を表現できるようにしたければ、以下の ようにします:

models.DecimalField(..., max_digits=19, decimal_places=10)

admin では、 <input type="text"> (一行のテキスト入力) で表現されます。

Note

For more information about the differences between the FloatField and DecimalField classes, please see FloatField vs. DecimalField.

EmailField
class EmailField([max_length=75, **options])

値が有効なメールアドレスであることをチェックする CharField です。

FileField
class FileField(upload_to=None[, max_length=100, **options])

ファイルアップロードのためのフィールドです。

Note

The primary_key and unique arguments are not supported, and will raise a TypeError if used.

必須の 引数を一つ持ちます:

FileField.upload_to

ローカルのファイルシステム上のパスです。このパスは MEDIA_ROOT に設定したパスの後ろにつけられ、 url 属性の値を決める際に使われます。

This path may contain strftime() formatting, which will be replaced by the date/time of the file upload (so that uploaded files don’t fill up the given directory).

upload_to には、関数のような呼び出し可能オブジェクトも指定できます。 呼び出し可能オブジェクトを指定すると、ファイル名を含むアップロードパス を決めるために呼び出されます。この呼び出し可能オブジェクトを定義する場 合、二つの引数をとり、 (スラッシュで始まる) Unix 形式のパスを返さねば なりません。返したパスはストレージシステムで使われます。二つの引数の説 明を以下に示します:

引数 説明
instance FileField を定義しているモデルのインス タンスです。もっと正確には、ファイルを添付 しようとしているインスタンスです。ほとんど の場合、このオブジェクトはまだデータベース に保存されていないので、デフォルトの AutoField を使っている場合、 まだ主キーフィールドの値が決まっていない ことがあります。
filename もともとファイルに付けられていたファイル名 です。最終的なファイルの保存パスを決めると きに考慮してもよいですし、しなくてもかまい ません。

また、オプションの引数を一つとります:

FileField.storage

省略可能です。ストレージの操作と、ファイルの取得を行うストレージ オブジェクトです。このオブジェクトの作り方については、 ファイルの管理 を参照してください。

admin では、 <input type="file"> (ファイルアップロードウィジェット) で表現されます。

モデル中で FileFieldImageField (下記参照) を使うには、 以下のようなステップが必要です:

  1. Django にアップロードされたファイルを保存させたい場所のフルパスを設 定ファイル中の MEDIA_ROOT に指定します。(パフォーマンス上 の理由から、アップロードされたファイルはデータベースに保存されませ ん。) 保存場所への公開 URL を MEDIA_URL に指定します。 ディレクトリが Web サーバのユーザアカウントによって書き込み可能であ るか確認してください。
  2. FileFieldImageField をモデルに定義します。この とき、 upload_to オプションを指定して、 MEDIA_ROOT 下のサブディレクトリのどこにアップロードされた ファイルを置くべきかを Django に教えます。
  3. データベースに保存されるのはファイルへのパス (MEDIA_ROOT からの相対) です。Django の提供している url を使うことになるでしょう。例えば、 mug_shot という名前の ImageField があれば、画像への絶対 パスは {{ object.get_mug_shot_url }} で取得できます。

例えば、 MEDIA_ROOT'/home/media' にして、 upload_to'photos/%Y/%m/%d' に設定したとします。 upload_to'%Y/%m/%d' の部分は strftime() と同じ フォーマット文字を使っています。すなわち、 '%Y' が 4 桁の年号、 '%m' が 2 桁の月、 '%d' が 2 桁の日を表します。従って、ファイルを 2007 年の 1 月 15 日にアップロードすると、 /home/media/photos/2007/01/15 に保存されます。

アップロードファイルのディスク上でのファイル名またはサイズを知りたい場合は、 それぞれ name, size 属性を使えます。利用可能な属性やメソッドの 詳細については File クラスのリファレンスと ファイルの管理 を参照してください。

Note

The file is saved as part of saving the model in the database, so the actual file name used on disk cannot be relied on until after the model has been saved.

The uploaded file’s relative URL can be obtained using the url attribute. Internally, this calls the url() method of the underlying Storage class.

ファイルのアップロードを処理するときには、常にアップロード先の場所やアップ ロードされるファイルに注意して、セキュリティホールを避けるようにしてくださ い。 アップロードされる全てのファイルをチェックして 、予想外のファイルが アップロードされないようにしましょう。例えば、バリデーションを行わずに Web サーバのドキュメントルート下へのファイルのアップロードを盲目的に受け入れる と、そこに誰かが CGI や PHP スクリプトをアップロードして、あなたのサイト上 の URL を訪問した人にスクリプトを実行させられてしまいます。そんなことを許し てはなりません。

Also note that even an uploaded HTML file, since it can be executed by the browser (though not by the server), can pose security threats that are equivalent to XSS or CSRF attacks.

デフォルトでは、 FileField インスタンスは varchar(100) カラム をデータベースに作成します。他のフィールドと同様、 max_length 引数を使って最大長を変更できます。

FileField and FieldFile

When you access a FileField on a model, you are given an instance of FieldFile as a proxy for accessing the underlying file. This class has several methods that can be used to interact with file data:

FieldFile.open(mode='rb')

Behaves like the standard Python open() method and opens the file associated with this instance in the mode specified by mode.

FieldFile.close()

Behaves like the standard Python file.close() method and closes the file associated with this instance.

FieldFile.save(name, content, save=True)

This method takes a filename and file contents and passes them to the storage class for the field, then associates the stored file with the model field. If you want to manually associate file data with FileField instances on your model, the save() method is used to persist that file data.

Takes two required arguments: name which is the name of the file, and content which is an object containing the file’s contents. The optional save argument controls whether or not the instance is saved after the file has been altered. Defaults to True.

Note that the content argument should be an instance of django.core.files.File, not Python’s built-in file object. You can construct a File from an existing Python file object like this:

from django.core.files import File
# Open an existing file using Python's built-in open()
f = open('/tmp/hello.world')
myfile = File(f)

Or you can construct one from a Python string like this:

from django.core.files.base import ContentFile
myfile = ContentFile("hello world")

For more information, see ファイルの管理.

FieldFile.delete(save=True)

Deletes the file associated with this instance and clears all attributes on the field. Note: This method will close the file if it happens to be open when delete() is called.

The optional save argument controls whether or not the instance is saved after the file has been deleted. Defaults to True.

FilePathField
class FilePathField(path=None[, match=None, recursive=False, max_length=100, **options])

ファイルシステム上のあるディレクトリ下のファイル名だけを選べるようになって いる CharField です。 3 つの特別な引数があり、そのうち最初の一つは 必須 です:

FilePathField.path

必須です。 FilePathField が選択肢を作成するためのディレクトリ への絶対パスです。例: "/home/images"

FilePathField.match

オプションです。正規表現を表す文字列で、 FilePathField がファ イル名のフィルタに使います。正規表現はフルパスではなくファイル名に適用 されるので注意してください。 例: "foo.*\.txt$"foo23.txt に はマッチしますが、 bar.txtfoo23.gif にはマッチしません。

FilePathField.recursive

オプションです。 True または False です。デフォルトは False で、 path のサブディレクトリを含めるかどうかを指 定します。

もちろん、これらの引数を組み合わせて使ってもかまいません。

よくある勘違いは、 match がファイル名ではなくフルパ スに適用されると思ってしまうことです。以下の例:

FilePathField(path="/home/images", match="foo.*", recursive=True)

/home/images/foo.gif にはマッチしますが、ファイル名本体 (foo.gifbar.gif) にマッチするため、 /home/images/foo/bar.gif にはマッチ しません。

FilePathField インスタンスは varchar(100) カラムをデータベース に作成します。他のフィールドと同様、 max_length 引数を使っ て最大長を変更できます。

FloatField
class FloatField([**options])

浮動小数点数です。Python の float 型インスタンスで表現されます。

admin では、 <input type="text"> (一行の入力フィールド) で表現されます。

FloatField vs. DecimalField

The FloatField class is sometimes mixed up with the DecimalField class. Although they both represent real numbers, they represent those numbers differently. FloatField uses Python’s float type internally, while DecimalField uses Python’s Decimal type. For information on the difference between the two, see Python’s documentation for the decimal module.

ImageField
class ImageField(upload_to=None[, height_field=None, width_field=None, max_length=100, **options])

FileField の属性とメソッドをすべて継承し、さらにアップロードされた オブジェクトが有効なイメージかどうか検証します。

In addition to the special attributes that are available for FileField, an ImageField also has height and width attributes.

To facilitate querying on those attributes, ImageField has two extra optional arguments:

ImageField.height_field

モデルインスタンスを保存する際に画像の高さを自動的に入れたいモデルフィー ルドの名前です。

ImageField.width_field

モデルインスタンスを保存する際に画像の幅を自動的に入れたいモデルフィー ルドの名前です。

Python Imaging Library が必要です。

ImageField インスタンスは varchar(100) カラムをデータベースに 作成します。他のフィールドと同様、 max_length 引数を使っ て最大長を変更できます。

IntegerField
class IntegerField([**options])

整数です。 admin では、 <input type="text"> (一行の入力フィールド) で表 現されます。

IPAddressField
class IPAddressField([**options])

IP アドレスを文字列形式で表したもの (例: “192.0.2.30”) です。admin では、 <input type="text"> (一行の入力フィールド) で表現されます。

GenericIPAddressField
class GenericIPAddressField([protocol=both, unpack_ipv4=False, **options])
リリースノートを参照してください

An IPv4 or IPv6 address, in string format (e.g. 192.0.2.30 or 2a02:42fe::4). The admin represents this as an <input type="text"> (a single-line input).

The IPv6 address normalization follows RFC 4291#section-2.2 section 2.2, including using the IPv4 format suggested in paragraph 3 of that section, like ::ffff:192.0.2.0. For example, 2001:0::0:01 would be normalized to 2001::1, and ::ffff:0a0a:0a0a to ::ffff:10.10.10.10. All characters are converted to lowercase.

GenericIPAddressField.protocol

Limits valid inputs to the specified protocol. Accepted values are 'both' (default), 'IPv4' or 'IPv6'. Matching is case insensitive.

GenericIPAddressField.unpack_ipv4

Unpacks IPv4 mapped addresses like ::ffff::192.0.2.1. If this option is enabled that address would be unpacked to 192.0.2.1. Default is disabled. Can only be used when protocol is set to 'both'.

NullBooleanField
class NullBooleanField([**options])

BooleanField と同じですが、 NULL を選択肢に使えます。 null=TrueBooleanField の代わりに使って下さい。 admin では、 「不明」 (“Unknown”) 「はい」 (“Yes”)、「いいえ」 (“No”) の選択肢をもつ <select> ボックスで表現されます。

PositiveIntegerField
class PositiveIntegerField([**options])

IntegerField と似ていますが、正の数か 0 でなければなりません。 0 が受け入れられる理由は、後方互換性を維持するためです。

PositiveSmallIntegerField
class PositiveSmallIntegerField([**options])

PositiveIntegerField と同じですが、ある範囲以下 (データベース依存 です)の値しか使えません。

SlugField
class SlugField([max_length=50, **options])

スラグ (slug)」は新聞業界の用語で、内容を示す短いラベル です。スラグは文字、数字、アンダースコア、ハイフンだけからなります。スラグ はよく URL に使われます。

CharField と同様、 max_length を指定できます。 (CharField のデータベース可搬性に関する注意と max_length の解説を参照してください) 指定しなかった場合、 Django はデフォルト値の 50 を使います。

Field.db_indexTrue に設定します。

It is often useful to automatically prepopulate a SlugField based on the value of some other value. You can do this automatically in the admin using prepopulated_fields.

SmallIntegerField
class SmallIntegerField([**options])

IntegerField と同様ですが、ある (データベース依存の) 範囲の値しか 使えません。

TextField
class TextField([**options])

長いテキストのためのフィールドです。admin では、 <textarea> (複数行の入 力フィールド) で表現されます。

MySQL ユーザへの注意

MySQLdb 1.2.2 でこのフィールドを使っていて、コレーションを (デフォルト 設定 でない) utf8_bin に設定していると、いろいろと問題を引き起こ します。詳しくは MySQL データベースに関する注意 を参照してください。

TimeField
class TimeField([auto_now=False, auto_now_add=False, **options])

時刻です。 DateFieldDateTimeField と同じく、自動的に 値を埋めるためのオプションを使えます。

admin では、JavaScript のショートカットがついた <input type="text"> で 表現されます。

URLField
class URLField([verify_exists=False, max_length=200, **options])

URL を表すための CharField です。引数を一つとります:

Deprecated since version 1.4: verify_exists is deprecated for security reasons as of 1.4 and will be removed in Django 1.5. Prior to 1.3.1, the default value was True.

URLField.verify_exists

True にすると、指定された URL が実在する (URL は実際にロードでき、 かつ 404 応答を返さない) かどうかを HEAD リクエストを使って検証します。 リダイレクト先はたどりません。

シングルスレッドで動作する開発サーバを使っていると、同じサーバ上の URL に対する検証をかけた瞬間にサーバがハングアップしてしまうので注意してく ださい。マルチスレッドで動作するサーバでは問題にならないはずです。

admin では、 <input type="text"> (一行の入力フィールド) で表現されます。

CharField の他のサブクラスと同じく、 URLField にはオプショ ンの引数として、フィールドの最大長 (文字数) を表す max_length を指定できます。 max_length を指定しないときのデフォルトの値は 200 です。

XMLField
class XMLField(schema_path=None[, **options])

TextField と同様ですが、指定されたスキーマに従って、値が有効な XML であ るか検証します。必須の引数を一つとります:

schema_path

検証に使う RelaxNG スキーマを指すファイルシステム上のパス名です。

リレーションフィールド

Django は、リレーションを表現するためのフィールドも定義しています。

ForeignKey
class ForeignKey(othermodel[, **options])

多対一のリレーションです。必須の固定引数として、リレーションを張るモデルの クラスをとります。

再帰的なリレーションを張る、つまり自分自身への多対一のリレーションを張る場 合には、 models.ForeignKey('self') を使います。

未定義のモデルへのリレーションを作成したい場合、モデルオブジェクトではなく モデルの名前も使えます:

class Car(models.Model):
    manufacturer = models.ForeignKey('Manufacturer')
    # ...

class Manufacturer(models.Model):
    # ...

他のアプリケーションで定義されているモデルを参照したければ、アプリケーショ ンラベルを明示的に指定せねばなりません。例えば、上の例の Manufacturer モデルが、 production という別のアプリケーションで定義されているのなら、 以下のように書かねばなりません:

class Car(models.Model):
    manufacturer = models.ForeignKey('production.Manufacturer')

この参照方法は、二つのアプリケーション間における循環インポート問題の解決に 使えます。

データベース上での表現

舞台裏では、 Django はフィールド名に "_id" をつけた名前でデータベースの カラム名を生成します。上の例では、 Car モデルのデータベーステーブルには manufacturer_id カラムが入ります (このカラム名は db_column を明示的 に指定して変更できます。詳しくは db_column を参照してくださ い) 。とはいえ、カスタムのSQL 文を発行するのでないかぎり、データベースのカ ラム名をコードで直接扱う必要はありません。

引数

ForeignKey は、他にもいくつかオプションの引数をとります。これらの 引数を使うと、リレーションの細かい動作を定義できます。

ForeignKey.limit_choices_to

データベースの照合オプション (クエリを生成する を参照) と値を対応 づけた辞書で、 admin で選択肢を表示するときに、表示するオブジェクトを絞 り込むために使えます。 Python の datetime モジュールと組み合わせれ ば、表示するオブジェクトを日付に基づいて制限できます。例えば:

limit_choices_to = {'pub_date__lte': datetime.now}

のようにすると、 pub_date が現在の日時より前のオブジェクトだけを選 べます。

辞書の代りに Q オブジェクトを使用すれば、 より 複雑なクエリ を指定できます。しかし limit_choices_toQ オブジェクトを指定した 場合、そのモデル用の ModelAdminraw_id_fields に、そのフィールド がリストアップされていない場合にだけ admin 上の選択肢に影響します。

ForeignKey.related_name

リレーション先のオブジェクトから逆参照するときに使われる名前です。 詳しくは related objects documentation を参照してください。 抽象ベースクラス で リレーションを定義する場合、この値を設定せねばなりません。また、抽象ベー スクラスで定義する場合には、 特殊な表記法 を使えます。

If you’d prefer Django didn’t create a backwards relation, set related_name to '+'. For example, this will ensure that the User model won’t get a backwards relation to this model:

user = models.ForeignKey(User, related_name='+')
ForeignKey.to_field

リレーション先のオブジェクトの、リレーションを張る対象のフィールド名で す。デフォルトでは、リレーション先のオブジェクトの主キーを使います。

リリースノートを参照してください
ForeignKey.on_delete

When an object referenced by a ForeignKey is deleted, Django by default emulates the behavior of the SQL constraint ON DELETE CASCADE and also deletes the object containing the ForeignKey. This behavior can be overridden by specifying the on_delete argument. For example, if you have a nullable ForeignKey and you want it to be set null when the referenced object is deleted:

user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)

The possible values for on_delete are found in django.db.models:

  • CASCADE: Cascade deletes; the default.

  • PROTECT: Prevent deletion of the referenced object by raising django.db.models.ProtectedError, a subclass of django.db.IntegrityError.

  • SET_NULL: Set the ForeignKey null; this is only possible if null is True.

  • SET_DEFAULT: Set the ForeignKey to its default value; a default for the ForeignKey must be set.

  • SET(): Set the ForeignKey to the value passed to SET(), or if a callable is passed in, the result of calling it. In most cases, passing a callable will be necessary to avoid executing queries at the time your models.py is imported:

    def get_sentinel_user():
        return User.objects.get_or_create(username='deleted')[0]
    
    class MyModel(models.Model):
        user = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user))
    
  • DO_NOTHING: Take no action. If your database backend enforces referential integrity, this will cause an IntegrityError unless you manually add a SQL ON DELETE constraint to the database field (perhaps using initial sql).

ManyToManyField
class ManyToManyField(othermodel[, **options])

多対多のリレーションです。必須の固定引数として、リレーション先のモデルを表 すクラスをとります。 ManyToManyField の引数は、 再帰的リレーショ ン遅延型のリレーション定義 に関するオプションを含め、 ForeignKey と 全く同じです。

データベース上での表現

舞台裏では、 Django は中間の結合テーブル (join table) を生成して、多対多の リレーションを表現します。デフォルトの設定では、テーブル名は many-to-many フィールドと、それを含むモデルの名前を使って生成されます。ただデータベース によっては一定の長さを超えるテーブル名をサポートしないため、テーブル名が長すぎる 場合は自動的に 64 文字に切り詰めて、さらにハッシュ値を使って一意な名前を 付けます。そのため author_books_9cdf4 といった名前のテーブルを見かけることが あると思いますが、これはまったく正常です。結合テーブルの名前は、 db_table オプションで手動指定できます。

引数

ManyToManyField は、他にもいくつかオプションの引数をとります。これ らの引数を使うと、リレーションの細かい動作を定義できます。

ManyToManyField.related_name

ForeignKey.related_name と同じです。

ManyToManyField.limit_choices_to

ForeignKey.limit_choices_to と同じです。

ManyToManyField を中間テーブル (intermediate table) と一緒に使うと、 limit_choices_to の効果はなくなります。

ManyToManyField.symmetrical

自分自身への ManyToManyField を定義すると きにのみ使います。以下のようなモデルを考えます:

class Person(models.Model):
    friends = models.ManyToManyField("self")

Django がこのモデルを処理する際、自分自身に対する ManyToManyField が定義されていることを認識して、 Person ク ラスに person_set 属性を追加しないようにします。その代り、 ManyToManyField を対称的 (symmetrical) であるとみなします。す なわち、私があなたの友達なら、あなたは私の友達である、というようにです。

self に対する多対多の関係に対称性を望まない場合は、 symmetricalFalse にしてください。これ により、 Django に逆参照用のデスクリプタを追加させて、 ManyToManyField を非対称にできます。

ManyToManyField.through

Django は多対多を管理するテーブルを自動的に作成しますが、中間テーブルを 独自に定義したいなら、 through オプションを使っ て、中間テーブルの表現に使いたいモデルを指定してください。

通常、このオプションを使うのは、 多対多の関係に追加のデータを持た せたいとき です。

ManyToManyField.db_table

多対多のリレーション情報を保存するために作成されるテーブルの名前です。 名前を指定しなければ、Django はデフォルトの名前を使います。デフォルトの 名前は、結合する二つのテーブルの名前に基づいて決められます。

OneToOneField
class OneToOneField(othermodel[, parent_link=False, **options])

一対一のリレーションです。一対一のリレーションは、概念的には unique=True であるような ForeignKey に似て いますが、リレーションの「逆」を辿ったときに、単一のオブジェクトを直接返す 点が違います。

最も OneToOneField が便利な局面は、他のモデルを何らかの形で拡張するとき のモデルの主キーとして使う場合です。例えば、 マルチテーブル継承 は、一対一のリレーションを子のモデルから親のモデルに自動的に張ることで実現 しています。

必須の固定引数として、リレーション先のモデルを表すクラスをとります。 引数は、 再帰的リレーション遅延 型のリレーション定義 に関するオプションを含め、 ForeignKey と全く同じです。

OneToOneField は、 ForeignKey で指定できる引数に加えて、以下の 引数を指定できます:

他のモデルを継承しているモデル中で True にすると、子のクラスのイン スタンスから親のクラスのインスタンスに向けたリンクのフィールドとして 使います。通常は、サブクラス化によって暗黙のうちに OneToOneField が作成されます。

リレーションオブジェクトリファレンス

revision-up-to:17812 (1.4)
class RelatedManager

“Related manager” は一対多リレーションや多対多リレーションに関連して 使われます。以下 2 つの場合に登場します:

  • ForeignKey リレーションの「向こう側」。 つまり:

    class Reporter(models.Model):
        ...
    
    class Article(models.Model):
        reporter = models.ForeignKey(Reporter)
    

    上の例では、マネージャ reporter.article_set で後述のメソッドが使用可能 になります (訳注: ここでの reporterReporter のインスタンス です)。

  • ManyToManyField リレーションの「両側」:

    class Topping(models.Model):
        ...
    
    class Pizza(models.Model):
        toppings = models.ManyToManyField(Topping)
    

    この例では、 topping.pizza_setpizza.toppings で後述のメソッド が使用可能になります (訳注: ここでの toppingTopping クラスの、 pizzaPizza クラスのインスタンスです) 。

これらの “related manager” はいくつか追加のメソッドを持っています:

add(obj1[, obj2, ...])

指定したモデルオブジェクトを、被リレーションのセットに追加し (リレーショ ン先のオブジェクトからリレーションを張り) ます。

使い方:

>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
>>> b.entry_set.add(e) # Entry e を Blog b に関連づけます。
create(**kwargs)

新たなオブジェクトを生成し、保存して、被リレーションのセットに追加しま す。新たに生成されたオブジェクトを返します:

>>> b = Blog.objects.get(id=1)
>>> e = b.entry_set.create(
...     headline='Hello',
...     body_text='Hi',
...     pub_date=datetime.date(2005, 1, 1)
... )

# e は自動的に保存されるので、 e.save() は呼ばなくてかまいません

上の例は、下記と同じ処理を実現します:

>>> b = Blog.objects.get(id=1)
>>> e = Entry(
...      blog=b,
...      headline='Hello',
...      body_text='Hi',
...      pub_date=datetime.date(2005, 1, 1)
...  )
>>> e.save()

リレーションを定義するためのキーワード引数を指定する必要はないので注意 してください。上の例では、 create()blog パラメタを渡してい ません。 Django は Entry オブジェクトの blog フィールドに b をセットすべきだと自動的に理解します。

remove(obj1[, obj2, ...])

指定したオブジェクトを被リレーションセットから除去します:

>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
>>> b.entry_set.remove(e) # Disassociates Entry e from Blog b.

データベースの一貫性を保持するために、このメソッドは null=TrueForeignKey オブジェクトでしか使えません。 リレーションフィールドの値を None (NULL) にできなければ、あるオブジェクトを 被リレーションセットから除去したときに、何らかの他のオブジェクトに対して リレーションを張り直さなければならないからです。上の例で、 b.entry_set() からの e の除去は e.blog = None に 相当しますが、 blogForeignKey には null=True が設定されていないので、これは無効な操作です。

clear()

被リレーションセットから、全てのオブジェクトを除去します:

>>> b = Blog.objects.get(id=1)
>>> b.entry_set.clear()

このメソッドは、リレーション元のオブジェクトを削除せず、ただ単に リレーションを解除するだけなので注意してください。

remove() と同様、 clear()null=TrueForeignKey でしか使えません。

モデルの Meta オプション

revision-up-to:17812 (1.4)

このドキュメントでは、モデルの内部クラス Meta に指定できる メタデータオプション について解説しています。

Meta オプション
abstract
Options.abstract

abstract = True に設定すると、このモデルは 抽象ベースクラス になります。

app_label
Options.app_label

もしモデルが標準的な models.py 以外の場所にある場合 (たとえば、 そのアプリのモデルがサブモジュール myapp.models にある場合)、 そのモデルがどのアプリに属しているのか定義する必要があります:

app_label = 'myapp'
db_table
Options.db_table

モデルの使うデータベーステーブルの名前です:

db_table = 'music_album'
テーブル名

ユーザの手間を省くため、 Django はモデルクラスやアプリケーションの名前を 元にデータベーステーブルの名前を導出します。モデルのデータベーステーブル名は、 モデルの「アプリケーションラベル (app label)」、つまり manage.py startapp で指定した名前と、モデルのクラス名をアンダースコアで 結んで生成します。

例えば、 (manage.py startapp bookstore で作成した) bookstore という アプリケーションの中に class Book で定義したモデルがあった場合その データベーステーブルの名前は bookstore_book です。

データベーステーブル名をオーバライドしたければ、 class Metadb_table パラメタを設定します。

データベーステーブル名が SQL の予約語と一致している場合や、ハイフンのように Python の変数名として扱えない文字を含んでいても問題ありません。 Django は カラムとテーブル名を舞台裏でクオート処理するからです。

MySQL のために小文字のテーブル名を使うこと

MySQL バックエンドを使っている場合は特に、 db_table でテーブル名を オーバーライドする際に小文字のテーブル名を使うよう強くお勧めします。 詳細は MySQL に関する注意 を参照してください。

db_tablespace
Options.db_tablespace

このモデルで使用する データベースのテーブルスペース の名前です。デフォルトでは DEFAULT_TABLESPACE が設定されていれば、それを使用します。 バックエンドがテーブルスペースをサポートしていない場合、このオプションは 無視されます。

get_latest_by
Options.get_latest_by

モデル中の DateField または DateTimeField の名前です。 このオプションは、モデルの Managerlatest メソッドが使うデフォルトのフィールドを指定します。

例えば:

get_latest_by = "order_date"

詳しくは latest() を参照してください。

managed
Options.managed

デフォルトでは True です。その場合 Django は適切なデータベーステーブルを syncdb で作成し、 reset 管理コマンドの処理の中で 削除します。すなわち、 Django がデータベーステーブルのライフサイクルを “管理する (manage)” ことになります。

False の場合、データベーステーブルの作成や削除がこのモデルのために 行われることはありません。モデルが、他の手段で作成済みのテーブルや データベースビューを表す場合に、役立つでしょう。これが managed=False とした場合に起こる 唯一の 違いです。モデルの処理に関して、他はすべて 完全に普通通りです。以下についても同じです:

  1. (訳注: どのフィールドが主キーであるかを) 宣言しない限り、自動的に 主キーフィールドをモデルに追加します。”管理しない” モデルを使っている 場合、後でコードを読む人が混乱しないように、モデリングしている データベーステーブルの全カラムを指定することをお勧めします。
  1. もし managed=False なモデルが他の “管理しない” モデルを指す ManyToManyField を含んでいる場合、 many-to-many 結合用の中間テーブルも作成されません。しかし、 “管理する” モデルと “管理しない” モデルの間の中間テーブルは 作成されます

    このデフォルトの振る舞いを変更する必要がある場合、中間テーブル用の 明示的なモデルを (必要に応じて managed を指定して) 作成し、 ManyToManyField.through 属性を使ってそのカスタムモデルを そのリレーションで使うように指定してください。

managed=False としたモデルが関わるテストにおいて、テストのセットアップ 処理で正しいテーブルを作成するかどうかはユーザ次第です。

もしモデルクラスの Python レベルでの振る舞いを変更してみたいのであれば、 managed=False としつつ既存のモデルのコピーを作成することも 可能と言えば可能 です。しかし、その状況であればもっと良いアプローチが あります: プロキシモデル です。

order_with_respect_to
Options.order_with_respect_to

指定したフィールドでオブジェクトを「並べ替え可能 (orderable)」であると宣言します。 このオプションを使うのは、リレーションの張られたオブジェクトを、親オブジェクト に従って並べ替えたい場合がほとんどです。例えば、 AnswerQuestion にリレーションを張っており、一つの Question に複数の Answer があっ て、 Answer の順番が重要である場合は以下のようにします:

class Answer(models.Model):
    question = models.ForeignKey(Question)
    # ...

    class Meta:
        order_with_respect_to = 'question'

order_with_respect_to が設定されているとき、関係づけられたオブジェクトの 並び順を取得・設定する 2 つのメソッドが追加されます: get_RELATED_order()set_RELATED_order() という名前で、ただし RELATED の部分は小文字化したモデル名になります。たとえば Question オブジェクトが複数の Answer オブジェクトと関係づけられているとしたら、 返されるリストには関係づけられた Answer オブジェクトの主キーが 格納されています:

>>> question = Question.objects.get(id=1)
>>> question.get_answer_order()
[1, 2, 3]

Question オブジェクトに関係づけられた Answer オブジェクトの並び順は Answer の主キーのリストを渡せば設定できます:

>>> question.set_answer_order([3, 1, 2])

関係づけられたオブジェクトには、さらに 2 つメソッドが追加されます。 get_next_in_order()get_previous_in_order() というメソッドで、 正しい順番でオブジェクトにアクセスするのに使えます。 Answer オブジェクトが id で並べられるとすると:

>>> answer = Answer.objects.get(id=2)
>>> answer.get_next_in_order()
<Answer: 3>
>>> answer.get_previous_in_order()
<Answer: 1>

order_with_respect_to を変更する

order_with_respect_to_order という名前で追加のフィールド / データベースカラムを追加します。そのため最初の syncdb の後に order_with_respect_to を追加または変更するのであれば、モデルも 変更するなど、関連する変更を確実に行ってください。

ordering
Options.ordering

オブジェクトのリストを取得するときに使われる、オブジェクトのデフォルトの 並び順規則です:

ordering = ['-order_date']

値は文字列のタプルやリストです。各文字列はフィールドの名前で、降順に並べる 場合にはオプションの “-” を先頭に付けます。先頭に “-” のないフィールドは 昇順に並べられます。順番をランダムにするには ”?” を使って下さい。

例えば、 pub_date フィールドで昇順に並べる場合には以下のようにします:

ordering = ['pub_date']

pub_date フィールドで降順に並べる場合には以下のようにします:

ordering = ['-pub_date']

pub_date フィールドで降順に並べ、さらに author で昇順に場合には以下 のようにします:

ordering = ['-pub_date', 'author']
Django の admin はリスト・タプル中の全要素をちゃんと扱います。 1.4 以前は、最初の要素以外は無視されました。
permissions
Options.permissions

オブジェクトの生成時にパーミッションテーブルに追加するパーミッションの リストです。 admin セットをもつオブジェクトには、追加、削除、変更の パーミッションが自動的に生成されます。以下の例では、 can_deliver_pizzas という追加のパーミッションを定義しています:

permissions = (("can_deliver_pizzas", "Can deliver pizzas"),)

(permission_code, human_readable_permission_name) の形式をとる 2 要素の タプルからなるリストです。

proxy
Options.proxy

proxy = True である場合、他のモデルをサブクラス化したモデルは プロキシモデル として扱われます。

unique_together
Options.unique_together

組み合わせとして一意にしなければならないフィールドセットのリストです:

unique_together = (("driver", "restaurant"),)

このリストは、フィールド名のリストからなるリストです。各要素のリストに 入っているフィールドの値の組み合わせは、データベース上で一意でなければ なりません。この制約は Django の admin 上で使われるとともに、データベース レベルでも強制されます (すなわち、適切な UNIQUE 文が CREATE TABLE 文に入ります)。

便宜上、 unique_together は一つのリストのときは単一セットのフィールド として扱います:

unique_together = ("driver", "restaurant")

unique_together に ManyToManyField を含めることはできません。(何を意味しているのかハッキリしません!) ManyToManyField に関係した一意性を検証する 必要があるのであれば、シグナルか、明示的な through モデルを使ってみてください。

verbose_name
Options.verbose_name

人間可読なオブジェクト名の単数形です:

verbose_name = "pizza"

この引数を指定しない場合、Django はクラス名を解体した文字列を使います。 例えば CamelCasecamel case になります。

verbose_name_plural
Options.verbose_name_plural

オブジェクトの複数形名です:

verbose_name_plural = "stories"

この引数を指定しない場合、Django は verbose_name + "s" を使います。

モデルインスタンスリファレンス

revision-up-to:17812 (1.4) unfinished

このドキュメントでは、モデル API の詳細を解説します。このドキュメントは、 モデルデータベースクエリ といったガイドを前提にしているので、このドキュメントを 読む前に、予め読んで理解しておくとよいでしょう。

このリファレンスでは、 データベースクエリガイドWeblog のモデル例 を使います。

オブジェクトの生成

モデルの新たなインスタンスは、通常の Python のクラスと同じ方法で生成します:

class Model(**kwargs)

キーワード引数に指定できる名前は、モデルで定義したフィールドの名前です。 モデルのインスタンスを生成しても、 save() を呼び出すまで データベースは操作されません。

Validating objects
リリースノートを参照してください

There are three steps involved in validating a model:

  1. Validate the model fields
  2. Validate the model as a whole
  3. Validate the field uniqueness

All three steps are performed when you call a model’s full_clean() method.

When you use a ModelForm, the call to is_valid() will perform these validation steps for all the fields that are included on the form. See the ModelForm documentation for more information. You should only need to call a model’s full_clean() method if you plan to handle validation errors yourself, or if you have excluded fields from the ModelForm that require validation.

Model.full_clean(exclude=None)

This method calls Model.clean_fields(), Model.clean(), and Model.validate_unique(), in that order and raises a ValidationError that has a message_dict attribute containing errors from all three stages.

The optional exclude argument can be used to provide a list of field names that can be excluded from validation and cleaning. ModelForm uses this argument to exclude fields that aren’t present on your form from being validated since any errors raised could not be corrected by the user.

Note that full_clean() will not be called automatically when you call your model’s save() method, nor as a result of ModelForm validation. You’ll need to call it manually when you want to run one-step model validation for your own manually created models.

Example:

try:
    article.full_clean()
except ValidationError, e:
    # Do something based on the errors contained in e.message_dict.
    # Display them to a user, or handle them programatically.

The first step full_clean() performs is to clean each individual field.

Model.clean_fields(exclude=None)

This method will validate all fields on your model. The optional exclude argument lets you provide a list of field names to exclude from validation. It will raise a ValidationError if any fields fail validation.

The second step full_clean() performs is to call Model.clean(). This method should be overridden to perform custom validation on your model.

Model.clean()

This method should be used to provide custom model validation, and to modify attributes on your model if desired. For instance, you could use it to automatically provide a value for a field, or to do validation that requires access to more than a single field:

def clean(self):
    from django.core.exceptions import ValidationError
    # Don't allow draft entries to have a pub_date.
    if self.status == 'draft' and self.pub_date is not None:
        raise ValidationError('Draft entries may not have a publication date.')
    # Set the pub_date for published items if it hasn't been set already.
    if self.status == 'published' and self.pub_date is None:
        self.pub_date = datetime.datetime.now()

Any ValidationError exceptions raised by Model.clean() will be stored in a special key error dictionary key, NON_FIELD_ERRORS, that is used for errors that are tied to the entire model instead of to a specific field:

from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
try:
    article.full_clean()
except ValidationError, e:
    non_field_errors = e.message_dict[NON_FIELD_ERRORS]

Finally, full_clean() will check any unique constraints on your model.

Model.validate_unique(exclude=None)

This method is similar to clean_fields(), but validates all uniqueness constraints on your model instead of individual field values. The optional exclude argument allows you to provide a list of field names to exclude from validation. It will raise a ValidationError if any fields fail validation.

Note that if you provide an exclude argument to validate_unique(), any unique_together constraint involving one of the fields you provided will not be checked.

オブジェクトの保存

オブジェクトをデータベースに書き戻すには、 save() を使います:

Model.save([force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS])
The using argument was added.

If you want customized saving behavior, you can override this save() method. See 既存のモデルメソッドをオーバライドする for more details.

モデルの保存処理にはいくつか細かい注意点があります。以下の章を参照してください。

主キーの自動インクリメント

モデルに AutoField 、すなわち自動インクリメントされる 主キーがある場合には、オブジェクトに対して最初に save() を呼び出したときに 自動インクリメント値が計算され、保存されます:

>>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b2.id     # b には ID がないので None を返します。
>>> b2.save()
>>> b2.id     # 新たに保存されたオブジェクトの ID を返します。

ID の値は Django ではなくデータベースによって計算されるので、 save() を 呼び出すまでは ID の値は分かりません。

利便性のため、明示的に primary_key=True を指定したフィールドを 作成しないかぎり、デフォルトでは各モデルに id という名前の AutoField が追加されます。詳しくは AutoField のドキュメントを参照してください。

pk プロパティ
Model.pk

主キーを自前で定義しているか、 Django によって供給されているかに関係なく、 それぞれのモデルは pk と呼ばれるプロパティを持ちます。 これはモデルの通 常の属性のように振る舞いますが、実はモデルの主キーフィールドのエイリアスで す。その他の属性と同じように、この値は読み書き可能で、モデルのフィールドを 修正し更新できます。

自動主キーの値を明示的に指定する

モデルが AutoField を持っていて、新たなオブジェクトの ID を保存時に明示的に指定したい場合、 ID を自動的に決定させずに保存前に明示的に 指定してください:

>>> b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b3.id     # Returns 3.
>>> b3.save()
>>> b3.id     # Returns 3.

自動主キーの値を手動で割り当てる場合、決して既に存在する主キーの値を割り当 てないようにしてください! 明示的な主キー値を持った新たなオブジェクトを作成 し、その主キーがすでにデータベース上に存在する場合、 Django は保存操作を新 たなオブジェクトの作成ではなく、既存のオブジェクトの変更とみなします。

上の 'Cheddar Talk' ブログを例にとると、以下の例はデータベース上の既存 のレコードをオーバライドしてしまいます:

b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.')
b4.save()  # Overrides the previous blog with ID=3!

この理由については後述の UPDATE と INSERT の区別 を参照してください。

主キーの衝突がないとはっきり判っている場合なら、自動主キーの値の明示的な指 定は大量のオブジェクトを保存する際にきわめて便利です。

オブジェクトの保存時に何が起きるのか

Django は以下の段階を踏んでオブジェクトを保存します:

  1. pre_save シグナルの発行 django.db.models.signals.pre_save シグナル の発行によって、何らかのオブジェクトを保存しようとしていることを通知 します。このシグナルを待ち受けている関数でカスタムの処理を実行できます。

  2. データの前処理 オブジェクトの各フィールドについて、保存時に自動的に 実行する必要があるデータ修飾処理がないか調べ、あれば実行します。

    ほとんどのフィールドは前処理を 伴いません 。フィールドのデータはそのまま 保存されます。前処理が行われるのは、特殊な挙動を示すフィールドだけです。 例えば、 auto_now=True に設定された DateField の場合、前処理の段階で、フィールドの内容が現在の日付になるようデータを 置き換えます (現時点では、「特殊な」挙動を示すフィールドのリストを 全て列挙したドキュメントはありません)。

  3. データベース保存用のデータ準備処理 各フィールドについて、フィールドの 現在の値を元にデータベースに保存できる型のデータを生成します。

    ほとんどのフィールドはデータ準備処理を 伴いません 。整数や文字列は Python オブジェクトとして「いつでもデータベースへの書き込みに使える」 形式になっています。ただ、より複雑なデータ型の場合、なにがしかの修飾 が必要なことがあります。

    例えば、 DateField は、データの保存に Python の datetime 型を使います。データベースは datetime オブジェクトを 保存しないので、データベースに保存するには、フィールドの値を ISO 準拠の日付文字列に変換せねばなりません。

  4. データベースへの保存 前処理と準備処理を経たデータが SQL 文に組み込まれ、 データベースに挿入されます。

  5. post_save シグナルの発行 django.db.models.signals.pre_save シグナルと同じく、オブジェクトが 成功理に保存されたことを通知するために django.db.models.signals.post_save シグナルが発行されます。

UPDATE と INSERT の区別

Django データベースオブジェクトがオブジェクトの作成と変更に同じ save() メソッドを使っていることにお気づきかもしれませんね。 Django は INSERTUPDATE SQL 文のどちらを使うべきかの判断を抽象化しています。具体的 に言うと、 save() を呼び出したときに、Django は以下のアルゴリズムに従い ます:

  • オブジェクトの主キー属性の評価値が False でない場合 (None や 空文字列の場合などでない場合) 、 Django は SELECT クエリを使って、 該当する主キーを持つレコードが存在するかどうか調べます。
  • 該当する主キーを持つレコードがデータベース上に存在する場合には UPDATE クエリを使います。
  • オブジェクトの主キー属性が設定 されていない 場合や、主キーが設定さ れているが該当するレコードは存在しない場合、 INSERT を使います。

新たなオブジェクトを保存する際、まだ使われていない値を主キーに指定できる保 証がないかぎり、主キーの値を明示的に指定しないよう注意してください。詳しく は上記の 自動主キーの値を明示的に指定する の節や、後述の INSERT や UPDATE を強制する を参照してください。

INSERT や UPDATE を強制する

ごく稀に、 save() メソッドに INSERT だけを実行させ、 UPDATE にフォールバックさせたくない、あるいはその逆、すなわち UPDATE が可能なら実行するが、新たなレコードの INSERT はさせたくないような場合が あります。そんなときには、 force_insert=Trueforce_update=True パラメタを save() メソッドに渡してください。 明らかなことではありますが、INSERTUPDATE は同時に行えないので、 両方のパラメタを同時に渡すとエラーを引き起こします。

このパラメタが必要なケースは本当にごく稀な場合だけです。たいていは、 Django は正しい SQL で保存を行いますし、パラメタをオーバライドすると、追跡の困難な エラーにつながる恐れがあります。特殊な用途でだけ、このパラメタを使ってくだ さい。

Updating attributes based on existing fields

Sometimes you’ll need to perform a simple arithmetic task on a field, such as incrementing or decrementing the current value. The obvious way to achieve this is to do something like:

>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold += 1
>>> product.save()

If the old number_sold value retrieved from the database was 10, then the value of 11 will be written back to the database.

This sequence has a standard update problem in that it contains a race condition. If another thread of execution has already saved an updated value after the current thread retrieved the old value, the current thread will only save the old value plus one, rather than the new (current) value plus one.

The process can be made robust and slightly faster by expressing the update relative to the original field value, rather than as an explicit assignment of a new value. Django provides F() expressions for performing this kind of relative update. Using F() expressions, the previous example is expressed as:

>>> from django.db.models import F
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold = F('number_sold') + 1
>>> product.save()

This approach doesn’t use the initial value from the database. Instead, it makes the database do the update based on whatever value is current at the time that the save() is executed.

Once the object has been saved, you must reload the object in order to access the actual value that was applied to the updated field:

>>> product = Products.objects.get(pk=product.pk)
>>> print product.number_sold
42

For more details, see the documentation on F() expressions and their use in update queries.

Deleting objects
Model.delete([using=DEFAULT_DB_ALIAS])
The using argument was added.

Issues a SQL DELETE for the object. This only deletes the object in the database; the Python instance will still exist and will still have data in its fields.

For more details, including how to delete objects in bulk, see オブジェクトの削除.

If you want customized deletion behavior, you can override the delete() method. See 既存のモデルメソッドをオーバライドする for more details.

その他のモデルインスタンスメソッド

モデルには、特殊な使われ方をするメソッドがあります:

__unicode__
Model.__unicode__()

__unicode__() メソッドは、オブジェクトに対して unicode() を呼び出し た際に呼び出されます。Django uses unicode(obj) (or the related function, str(obj)) in a number of places. Most notably, to display an object in the Django admin site and as the value inserted into a template when it displays an object. Thus, you should always return a nice, human-readable representation of the model from the __unicode__() method.

For example:

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)

モデルに __unicode__() メソッドだけを定義して、 __str__() は定義しないでおくと、 Django が自動的に __str__() メソッドを モデルに追加します。この __str__() メソッドは、 __unicode__() を呼び出して、その戻り値を UTF-8 でエンコードした文字列を返します。 開発上はこの仕様に従い、 __unicode__() だけを定義して、文字列オブジェクト への変換は Django 任せにするよう勧めます。

__str__
Model.__str__()

The __str__() method is called whenever you call str() on an object. The main use for this method directly inside Django is when the repr() output of a model is displayed anywhere (for example, in debugging output). Thus, you should return a nice, human-readable string for the object’s __str__(). It isn’t required to put __str__() methods everywhere if you have sensible __unicode__() methods.

The previous __unicode__() example could be similarly written using __str__() like this:

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __str__(self):
        # first_name や last_name は Unicode 文字列なので、
        # django.utils.encoding.smart_str() を使う
        return smart_str('%s %s' % (self.first_name, self.last_name))
get_absolute_url
Model.get_absolute_url()

オブジェクトの正統的 (canonical) な URL を演算する方法を Django に教えるには get_absolute_url メソッドを定義してください。To callers, this method should appear to return a string that can be used to refer to the object over HTTP.

例えば:

def get_absolute_url(self):
    return "/people/%i/" % self.id

(Whilst this code is correct and simple, it may not be the most portable way to write this kind of method. The permalink() decorator, documented below, is usually the best approach and you should read that section before diving into code implementation.)

Django が get_absolute_url() を使う場面の一例が admin インタフェースの 中にあります。あるオブジェクトがこのメソッドを定義している場合、そのオブジェクト の編集ページには「サイト上で表示 (View on site)」というリンクが表示されます。 このリンク先はオブジェクトの get_absolute_url() から得られる URL になっており、オブジェクトの公開ビューに直接飛べるようになります。

同様に、その他の例えば 配信フィードフレームワーク などが get_absolute_url() を、定義されていれば 使います。もしモデルのインスタンスごとに一意な URL を持つのが自然であるならば、 get_absolute_url() を定義するべきでしょう。

テンプレートでは、オブジェクトの URL をハードコードする代わりに get_absolute_url() を使うよう習慣づけすべきです。例えば、 以下のテンプレートコードは悪い例です:

<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a>

こちらのテンプレートコードの方がもっと良いです:

<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>

The logic here is that if you change the URL structure of your objects, even for something simple such as correcting a spelling error, you don’t want to have to track down every place that the URL might be created. Specify it once, in get_absolute_url() and have all your other code call that one place.

Note

get_absolute_url() の返す文字列は ASCII 文字だけで構成されている 必要 があります (RFC 2396 の URI 仕様でそのように要求されています)。 また、必要に応じて URL エンコードせねばなりません。

戻り値については、まったく追加処理することなく get_absolute_url() を呼び出すコードやテンプレートからすぐ利用可能であるべきです。 完全に ASCII の範囲に入らない文字を含む Unicode 文字列を使っているのであれば、 django.utils.encoding.iri_to_uri() が役に立つかもしれません。

追加のインスタンスメソッド

save(), delete() に加えて、モデルオブジェクトは 以下メソッドのうちいくつかを持つことがあります:

Model.get_FOO_display()

choices セットを持つ全てのフィールドについて、 オブジェクトは get_FOO_display() メソッドを持ちます。 FOO はフィールド名です。このメソッドは、「人間可読な」フィールド名を返します。 例えば、以下のモデル:

GENDER_CHOICES = (
    ('M', 'Male'),
    ('F', 'Female'),
)
class Person(models.Model):
    name = models.CharField(max_length=20)
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)

では、各 Person インスタンスは get_gender_display() メソッド を持ちます:

>>> p = Person(name='John', gender='M')
>>> p.save()
>>> p.gender
'M'
>>> p.get_gender_display()
'Male'
Model.get_next_by_FOO(**kwargs)
Model.get_previous_by_FOO(**kwargs)

null=True であるような DateField および DateTimeField フィールドについて、オブジェクトは get_next_by_FOO() および get_previous_by_FOO() メソッドを持ちます。 FOO はフィールド名です。このメソッドは該当の日付フィールドに応じて 前のオブジェクトや次のオブジェクトを返します。適切なオブジェクトがなければ DoesNotExist を送出します。

これらのメソッドはいずれもオプションのキーワード引数をとります。引数は 前述の「 Field lookups 」で解説した形式にします。

同じ日付値を持つオブジェクトがある場合、このメソッドは主キーを判断基準として 使います。これにより、レコードがスキップしたり重複したりしないことが 保証されています。また、これらのメソッドを未保存のオブジェクトでは使えないことも 意味しています。

QuerySet API リファレンス

revision-up-to:17812 (1.4) unfinished

このドキュメントでは、 クエリセット(QuerySet) API について詳しく解説し ます。このドキュメントは、 モデルデータベースクエリ に基づいて書かれているので、 あらかじめ読んでおくよう勧めます。

このリファレンスを通じて、例題には データベースクエリガイド で取り上げた ブログのモデル例 を使います。

クエリセットはいつ評価されるのか

内部的には、クエリセットの生成、フィルタ操作、スライス、コード間の受渡しは、 データベースを操作することなく行えます。クエリセットを何らかの形で評価しな い限り、データベースの操作は実際には起こらないのです。

以下の方法を使うと、クエリセットを評価できます:

  • イテレーション。 クエリセットはイテレーション可能オブジェクトであ り、オブジェクトに対して最初にイテレーション操作を行ったときにデータ ベースクエリを実行します。例えば、以下の例はデータベース中の全てのエ ントリのヘッドラインを出力します:

    for e in Entry.objects.all():
        print e.headline
    
  • スライス。 クエリセットに制約を課す で説明しているように、 Python の配列スライス表記を使うとクエリセットをスライスできます。 未評価の QuerySet をスライスすると通常は新しい未評価の QuerySet を返しますが、スライス表記に「ステップ (step)」パラメタを使った場合は、 データベースクエリを実行してリストを返します。(部分的または完全に) 評価した QuerySet をスライスした場合も、リストを返します。
  • Pickle 化 / キャッシュ。 QuerySets を pickle する 時にどう関わってくるのか、詳しくは後述します。 この章の趣旨的に重要なのは、結果はデータベースから読み出されるということです。

  • repr(). クエリセットに対して repr() を呼び出すと、クエリセッ トは値評価されます。これは Python 対話インタプリタでの利便性のための 仕様で、 API を対話的に使うときに結果を即座に見られるようにしています。

  • len(). クエリセットに対して len() を呼び出すと、クエリセッ トは値評価されます。予想に違わず、 len() はクエリ結果リストの長さ を返します。

    注意: クエリセット中のレコードの数を知りたいだけなら、 len()使わないでください 。レコード数の計算はデータベース上で SQL 文の SELECT COUNT(*) 使って行う方が遥かに効率的であり、まさにその理由 から Django では count() メソッドを提供しています。後述の count() を参照してください。

  • list(). クエリセットに対して list() を呼び出すと、値評価を強 制できます。例えば:

    entry_list = list(Entry.objects.all())
    

    とはいえ、この方法を使うと、Django が全ての要素のリストをメモリ上にロー ドするため、巨大なメモリオーバヘッドを引き起こす可能性があるので十分 注意してください。これに対し、クエリセットに対するイテレーション操作 では、必要な分だけデータをロードしてオブジェクトをインスタンス化する という利点があります。

  • bool()。 bool() の使用時や if 文での使用時など、真理値として QuerySet を評価すると、クエリーが実行されます。もし一つ以上の結果が得られた場合、 QuerySet は真 (True) と評価され、さもなければ偽 (False) と評価されます。 たとえば:

    if Entry.objects.filter(headline="Test"):
       print "There is at least one Entry with the headline Test"
    

    Note: もし一つ以上の結果が存在するかどうかを知りたいだけで、 実際のオブジェクトが必要無いのであれば、この方法は 使わないでくださいexists() を使った方がもっと効率的です (後述します)。

Pickling QuerySets

If you pickle a QuerySet, this will force all the results to be loaded into memory prior to pickling. Pickling is usually used as a precursor to caching and when the cached queryset is reloaded, you want the results to already be present and ready for use (reading from the database can take some time, defeating the purpose of caching). This means that when you unpickle a QuerySet, it contains the results at the moment it was pickled, rather than the results that are currently in the database.

If you only want to pickle the necessary information to recreate the QuerySet from the database at a later time, pickle the query attribute of the QuerySet. You can then recreate the original QuerySet (without any results loaded) using some code like this:

>>> import pickle
>>> query = pickle.loads(s)     # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query            # Restore the original 'query'.

The query attribute is an opaque object. It represents the internals of the query construction and is not part of the public API. However, it is safe (and fully supported) to pickle and unpickle the attribute’s contents as described here.

You can’t share pickles between versions

Pickles of QuerySets are only valid for the version of Django that was used to generate them. If you generate a pickle using Django version N, there is no guarantee that pickle will be readable with Django version N+1. Pickles should not be used as part of a long-term archival strategy.

クエリセット API

通常は手動で作成しないものではありますが (Manager を通して作成するでしょうから)、 QuerySet の正式な宣言は以下の通りです:

class QuerySet([model=None, query=None, using=None])

通常、クエリセットを操作するときには、 フィルタを連鎖 させます。クエリセットに対するフィルタ操作は、 ほとんどが新たなクエリセットを返します。これらのメソッドの詳細は後述します。

QuerySet クラスには状態の分析 (introspection) に使える公開された属性が 2 つあります:

ordered

QuerySet が整列済みであれば True になります — つまり、 order_by() 節またはデフォルト整列順序の指定がモデルにあれば True になります。さもなければ False になります。

db

そのクエリーを、その時点で実行した場合に使われるデータベースです。

Note

QuerySetquery パラメータが存在しているのは GeoQuerySet などの特殊な クエリーを行うサブクラスが内部的なクエリーの状態を再構築できるように するためです。パラメータの値はクエリーの素 (opaque) の表現であり、 公開 API の一部ではありません。簡単に言うと: これについて質問するくらいであれば使う必要はありません。

新たなクエリセットを返すメソッド

Django は、クエリセットの返す結果の形式や、 SQL クエリの実行方法を変更する ためのリファインメソッドを幅広く提供しています。

filter
filter(**kwargs)

指定の照合パラメタに一致するオブジェクトの入った新たなクエリセットを返しま す。

照合パラメタ (**kwargs) は後述の フィールドの照合 で説明するフォーマッ トにします。複数のパラメタを指定すると、背後の SQL 文では AND で結合さ れます。

exclude
exclude(**kwargs)

指定の照合パラメタに一致 しない オブジェクトの入った新たなクエリセットを 返します。

照合パラメタ (**kwargs) は後述の フィールドの照合 で説明するフォーマッ トにします。複数のパラメタを指定すると、背後の SQL 文では AND で結合さ れ、制約条件節全体を NOT() で囲みます。

以下の例では、 pub_date が 2005 年 1 月 3 日より未来の日時になっていて、 かつ headline が “Hello” で始まる全てのエントリを除外します:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')

SQL では以下のようなクエリの評価と同じです:

SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

また、以下の例では、 pub_date が 2005 年 1 月 3 日より未来の日時で あるか、 または headline が “Hello” で始まる全てのエントリを除外しま す:

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')

SQL では以下のようなクエリの評価と同じです:

SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'

二つ目の例の方が制約が厳しいことに注意して下さい。

annotate
annotate(*args, **kwargs)

QuerySet 中の各オブジェクトを、クエリーに関係するオブジェクトを集計 (aggregate) した値 (平均値や合計値など) のリストでアノテート (annotate) します。 annotate() の各引数は、返される QuerySet 中のオブジェクトに 追加されるアノテーションです。

django が提供する集計関数については Aggregation Functions で後述します。

キーワード引数を使って指定したアノテーションは、そのキーワードをアノテーション の別名として使用します。無名の引数で指定した場合は、集計関数の名前と 集計対象モデルフィールドの名前を元に別名が生成されます。

たとえばブログのリストを操作しているとすると、各ブログに何個のエントリーが 作られているのか知りたいと思うかもしれません:

>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42

Blog モデル自体は entry__count 属性を定義していません。しかし集計関数 の指定にキーワード引数を使うことでアノテーションの名前を変えられます:

>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42

集計に関する深い議論については 集計のトピックガイド を参照してください。

order_by
order_by(*fields)

デフォルトでは、 QuerySet の返す結果はモデルの Metaordering オプションに指定した整列条件のタプルに従って整列されます。 order_by を 使うと、この挙動を QuerySet 単位でオーバライドできます。

例えば:

Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

このクエリを実行すると、検索結果はまず pub_date で降順に並べられ、次い で headline で昇順に並べられます。 "-pub_date" の先頭にあるマイナス 記号が 降順 を表しています。何も指定しないと昇順です。整列をランダムにし たければ、以下のように ”?” を使います:

Entry.objects.order_by('?')

注意: order_by('?') を使うと、使っているバックエンドによってはコストの かかる低速なクエリを実行してしまいます。

別のモデル内のフィールドを使ってモデルを整列させるには、モデルのリレーショ ン追跡と同じ構文を使ってフィールドを指定します。すなわち、フィールド名の後 ろにアンダースコア 2 つ (__) 、さらに新たなモデルのフィールド名を続けま す。この調子で、任意の深さまでモデルを追跡できます。例えば:

Entry.objects.order_by('blog__name', 'headline')

他のモデルへのリレーションを使ってモデルインスタンスを整列しようとすると、 Django はリレーション先のモデルのデフォルトの整列順 (Meta.ordering が指定されていなければプライマリキー) を使います。例えば:

Entry.objects.order_by('blog')

は、 Blog モデルにデフォルトの整列順が指定されていないので、以下のコー ドと同じです:

Entry.objects.order_by('blog__id')

リレーション先のモデルのフィールドを使った整列と distinct() を組み合わせる場合は注意が必要です。リレーション先のモデルの整列が、 どのような影響を受けるかは、 distinct() の説明を参照してください。

クエリ結果の整列には、 (ManyToManyField のような) 複数の値で構成されるフィールドも指定できます。通常、こうした指定には あまり意味がなく、本当に高度な使い方です。しかし、クエリセットを フィルタした結果や、もともとのデータにおいて、リレーション元のオブジェクトから 参照しているオブジェクトが一つしかないことが暗黙的に決まっていると はっきりしていれば、整列結果は期待通りになるでしょう。複数の値で構成される フィールドで整列を行う場合には、十分注意して、期待通りの結果が得られるか 確認してください。

大小文字の区別を考慮して整列するかどうかを指定する方法はありません。大小文 字の区別については、 Django は現在使っているデータベースバックエンドの整列 方法に従います。

もしデフォルトの並び順すらも含めて整列させたくない場合、パラメータを付けずに order_by() を呼んでください。

QuerySet.ordered 属性を確認すればクエリーが整列されているかどうか 判定できます。この属性は、どのような整列方法であっても、整列されていれば True になります。

reverse
reverse()

クエリセットに要素を逆順に返させたいときは reverse() メソッドを使ってく ださい。 reverse() を 2 回呼ぶと、並び順を通常に戻します。

ところでクエリセットの「末尾の」 5 つの要素を取り出す場合、以下のように書け ます:

my_queryset.reverse()[:5]

これは、 Python で起きる末尾部分のスライスと完全には同じでないので注意しま しょう。上の例の場合、要素を、末尾から順に返します。 Python で seq[-5:] のようにした場合、末尾から 5 番目を最初に返します。 SQL で効率 的に表現する方法がないので、 Django は このやり方 (末尾からのスライス) をサ ポートしていません。

また、 reverse() は一般に、すでに整列方法の定義されているクエリセット (デフォルトの整列順の定義されたモデルから取り出したクエリセットや、 order_by() で整列されたもの) に対して呼びだすべきものです。整列方法の定 義されていないクエリセットに対して reverse() を呼び出しても、何ら効果 をもたらしません (reverse() を呼び出す前に整列方法が定義されていなけれ ば、呼び出した後の整列方法も未定義のままです)。

distinct
distinct([*fields])

SQL クエリに SELECT DISTINCT を使う新たな QuerySet を返します。 distinct() を使うと、クエリ結果から重複する行をなくします。

デフォルトでは、 QuerySet は重複する行を除去しません。通常は、 Blog.objects.all() のような単純なクエリは重複する行を含むような結果にな らないため、これはあまり問題ではありません。しかし、クエリが複数のテーブル にわたる場合、 QuerySet の評価結果に重複する結果が入る場合があります。 その場合には distinct() を使って下さい。

Note

order_by() に指定したフィールドは、 SQL レベルで SELECT されます。そのため、 order_by()distinct() と組み合わせると 予期しない結果を生むことがあります。例えば、リレーション先のモデルフィー ルドを使って整列を行うと、それらのフィールドも SELECT されるため、 リレーション元のオブジェクトは同じ値で、リレーション先のフィールド値だ けが違うレコードは異なる (distinct) レコードとみなされます。リレーショ ン先のレコードカラムは (順序を制御するために使われるだけなので) 返され ず、その結果、distinct 制約を満たしていないクエリ結果が返されるように見 えてしまいます。

同様に、 values() クエリを使って SELECT 対象のカラムを制約する 場合も、 order_by() に指定したカラム (またはモデルのデフォルトの順 序制御カラム) が自動的にクエリ結果に含められ、結果の一意性に影響を及ぼ します。

distinct() を使う場合、リレーション先のフィールドを使った並べ替えに はよく注意しましょう。同様に、 distinct()values() を同時に 使うときにも、 values() の対象とするフィールドに順序カラムが入って いない場合はよく注意してください。

リリースノートを参照してください

Django 1.4 以降では、 DISTINCT が適用されるべきフィールド名を位置指定引数 (*fields) で指定できます。これは SQL クエリーの SELECT DISTINCT ON に変換されます。

違いを説明します。通常の distinct() の呼び出しでは、データベースは どの行が異なる (distinct) のかを判断するために各行の 全フィールドを 比較します。 フィールド名を指定した distinct() の呼び出しでは、データベースは指定された フィールド名だけを比較します。

Note

このフィールド名を指定する機能は PostgreSQL でのみ利用可能です。

Note

フィールド名を指定する場合、 order_by() を QuerySet に指定する 必要 (must) があり、また order_by() に指定するフィールド群は distinct() に指定するフィールド群で始まっている (順番も同じ) 必要があります。

たとえば、 SELECT DISTINCT ON (a) は列 a の値それぞれについて、 その値が最初に現れる行を取得します。 If you don’t specify an order, you’ll get some arbitrary row.

Examples:

>>> Author.objects.distinct()
[...]

>>> Entry.objects.order_by('pub_date').distinct('pub_date')
[...]

>>> Entry.objects.order_by('blog').distinct('blog')
[...]

>>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
[...]

>>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
[...]

>>> Entry.objects.order_by('author', 'pub_date').distinct('author')
[...]
values
values(*fields)

ValueQuerySet を返します。 ValueQuerySetQuerySet のサブクラ スで、評価結果としてモデルインスタンスオブジェクトの代りに辞書のリストを返 す QuerySet です。

リスト中の各辞書は個々のオブジェクトを表現しており、キーがモデルオブジェク トの各属性名に、対応しています。

以下の例では、 values() の辞書と通常のモデルオブジェクトを比較していま す:

# Blog オブジェクトのリストを返します。
>>> Blog.objects.filter(name__startswith='Beatles')
[<Blog: Beatles Blog>]

# 辞書のリストを返します。
>>> Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]

values() メソッドはオプションの可変長の引数 *fields を取れます。 このオプションは SELECT の制限に使うフィールド名を列挙したものです。 fields を指定した場合、辞書には指定した名前のフィールドのキーと 値だけが入ります。 *fields を指定しなければ、辞書にはテーブルの全ての フィールドのキーと値が入ります。

例を示します:

>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]

注意すべき点がいくつかあります:

  • ForeignKey foo がモデルに入っている場 合、 values() がデフォルトで返す辞書には、 foo_id というキー が入ります。これは、リレーションの実際の値が入っているモデル内部の隠 しフィールドの名前です (foo はリレーション先のモデルインスタンス への参照です)。一方、 values() にフィールド名を指定して呼び出す 場合は、 foofoo_id のどちらでも渡せますが、得られる結果は 同じ (辞書のキーは渡したフィールド名と同じ) で、リレーションの実際の 値です。

    例を以下に示します:

    >>> Entry.objects.values()
    [{'blog_id': 1, 'headline': u'First Entry', ...}, ...]
    
    >>> Entry.objects.values('blog')
    [{'blog': 1}, ...]
    
    >>> Entry.objects.values('blog_id')
    [{'blog_id': 1}, ...]
    
  • values()distinct() を組み合わせて使う場合、カラム値による 並べ替えが結果に思わぬ影響をもたらすことがあります。詳しくは distinct() の節を参照してください。

  • もし extra() の呼び出し後に values() を使う場合、 extra()select 引数で定義されるフィールドすべてを明示的に values() の呼び出し時に指定する必要があります。 values() の呼び出し後に extra() を呼び出した場合、 select で追加されるフィールドは 無視されます。

ValuesQuerySet が便利なのは、わずかな数のフィールドの値しか必要でなく、 モデルインスタンスオブジェクトの機能が必要でないと分かっている場合です。 必要なフィールドだけを選択すると、さらに効率的です。

最後に、 ValuesQuerySetQuerySet のサブクラスなので、 QuerySet の全てのメソッドを持っている点に注意してください。 ValuesQuerySet に対して filter()order_by() といった操作を行 えます。つまり、以下の二つの呼び出しは等価です:

Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()

Django の作者たちは、全ての SQL 関係のメソッドを先に配置し、その後に (必要 なら) 出力関係のメソッド (values() など) を配置するやり方を好んでいます。 とはいえ、これは実際上問題ではないので、個人的な信条を反映させてかまいませ ん。

リリースノートを参照してください

以前は values() メソッドに ManyToManyField 属性を渡すと、何も返されず、エラーが送出されました。

この制限は無くなり、 OneToOneFieldForeignKey そして ManyToManyField 属性を通して関係したモデルのフィールドを参照することも 可能になりました:

Blog.objects.values('name', 'entry__headline')
[{'name': 'My blog', 'entry__headline': 'An entry'},
     {'name': 'My blog', 'entry__headline': 'Another entry'}, ...]

Warning

ManyToManyField 属性と逆引きのリレーションは複数 の行を持つ可能性があるので、これらを含めると結果セットのサイズが増えること があります。これはそのようなフィールドを values() クエリーに複数含めると、 すべての組み合わせが返されるため、特に顕著になります。

values_list
values_list(*fields)

values() に似ていますが、辞書を返す代わりに、イテレーション時にタプルを 返します。各タプルには values_list() の引数に渡したフィールドの値が、 引数の順番に一致して入っています。例えば:

>>> Entry.objects.values_list('id', 'headline')
[(1, u'First entry'), ...]

フィールドを一つだけ指定する場合、 flat というパラメタも指定できます。 このパラメタを True にすると、結果は 1 要素のタプルではなく一つの値とし て返されます。以下の例を見れば、違いがはっきりするでしょう:

>>> Entry.objects.values_list('id').order_by('id')
[(1,), (2,), (3,), ...]

>>> Entry.objects.values_list('id', flat=True).order_by('id')
[1, 2, 3, ...]

複数のフィールドを指定しているときに flat を渡すとエラーを送出します。

values_list() に引数を渡さなければ、モデルの全てのフィールドを定義順に 並べたタプルのリストを返します。

dates
dates(field, kind, order='ASC')

DateQuerySet を返します。 DateQuerySetQuerySet のサブクラス で、評価結果としてクエリセット内のコンテンツの全日付を datetime.datetime オブジェクトとして返します。

field はモデルの DateField または DateTimeField の名前です。

kind"year", "month" または "day" です。 結果リスト中の各 datetime.datetime オブジェクトは type の指定に従っ て切り詰められます。

  • "year" を指定すると、フィールドの年部分の値の重複しないリストを返します。
  • "month" を指定すると、フィールドの年/月部分の値の重複しないリストを 返します。
  • "day" を指定すると、フィールドの年/月/日部分の値の重複しないリストを 返します。

order には結果の並び順を指定します。デフォルト値は 'ASC' で、 "ASC" または "DESC" にできます。

例を示します:

>>> Entry.objects.dates('pub_date', 'year')
[datetime.datetime(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.datetime(2005, 2, 1), datetime.datetime(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.datetime(2005, 2, 20), datetime.datetime(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.datetime(2005, 3, 20), datetime.datetime(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.datetime(2005, 3, 20)]

Warning

タイムゾーンサポートが有効化されていると Django はデータベース接続で UTC を使うので、集計は UTC にて行われます。 これは、現在の実装における既知の制限事項です。

none
none()

EmptyQuerySet を返します。 EmptyQuerySet とは、評価結果が常に空の リストである QuerySet のサブクラスです。関数の戻り値などで空の照合結果を 返したいけれども、呼び出し側が (空のリストなどではなく) クエリセットオブジェクト の戻り値を期待しているような場合に便利です。

例:

>>> Entry.objects.none()
[]
all
all()

クエリセット(またはそのサブクラス)の コピー を返します。モデルマネジャや クエリセットを引数に渡してフィルタ処理を行わせたいような場合に便利です。 モデルマネジャもクエリセットも all() を呼び出して、適切なクエリセットを 取り出せるからです。

extra
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

時として、 Django のクエリ表記法だけでは複雑な WHERE 節を容易に表現でき ない場合があります。こうした特異な場合のために、 Django では extra() というクエリセット修飾子を提供しています。このメソッドは、クエリセットが 生成する SQL 文中に特定の SQL 節を挿入するためのフックです。

定義上、これらの拡張照合機能は (直接 SQL コードを書いているため) データベー スエンジン間の可搬性がありません。また、 DRY 則の侵犯でもあります。可能な限 り使わないようにして下さい。

params, select, where, tables のいずれかを指定します。 いずれの引数も必須ではありませんが、少なくとも一つは指定せねばなりません。

  • select

    select キーワードを使うと、 SELECT 節に追加のフィールドを選択で きます。この引数は、属性名とその属性値を計算するための SQL 節を対応づけ た辞書にします。

    例えば:

    Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
    

    のようにすると、 Entry オブジェクトは、エントリの pub_date が Jan. 1, 2006 より大きいかどうかを示すブール値の属性 is_recent を 持つようになります。

    Django は指定された SQL を直接 SELECT 文に挿入するので、上の例の SQL 文は以下のようになります:

    SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent
    FROM blog_entry;
    

    次の例はもっと高度です。この例では、 Blog オブジェクトに関連づけら れている Entry オブジェクトの個数を表す整数を、 Blog オブジェク トの entry_count 属性に持たせるためにサブクエリを実行しています:

    Blog.objects.extra(
        select={
            'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
        },
    )
    

    上の場合では、クエリの FROM 節に blog_blog が入るという事実を 利用しています。

    上の例の場合、 SQL は以下のようになります:

    SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id)
    FROM blog_blog;
    

    ほとんどのデータベースエンジンでは、サブセレクションの周りに丸括弧が必 要ですが、Django の select 節では必要ないということに注意してくださ い。また、 MySQL の一部のバージョンのように、データベースバックエンドに よってはサブクエリをサポートしないので注意してください。

    ごく稀に、 extra(select=...) に指定する SQL にパラメタを渡したい場 場合があります。そんなときは select_params パラメタを使ってください。 ただし、 select_params はシーケンス型で、 select は辞書なので、 select= の中でパラメタが正しく一致するように注意する必要があります。 select に通常の辞書型を渡す代わりに django.utils.datastructures.SortedDict を指定すれば、こうした状況を うまく扱えます。

    例えば、以下のコードは期待通りに動作します:

    Blog.objects.extra(
        select=SortedDict([('a', '%s'), ('b', '%s')]),
        select_params=('one', 'two'))
    

    extra() に SELECT パラメタを渡す時には、 "%%s" (s の前のパー セント記号が 二重 のもの) だけは使わないでください。 Django は %s を探してパラメタの挿入位置を追跡しますが、 "%%s" のように % がエスケープされていると検出しないからです。そのため、クエリ結果 が正しくなくなります。

  • where / tables

    明示的に追加の WHERE 節を渡す必要がある場合 – おそらく非明示的な結 合を行っている場合 – には、 where キーワードを使って下さい。 tables を使えば、 SQL の FROM 節に手動でテーブル名を追加できま す。

    wheretables は、ともに文字列のリストを引数にとります。 where パラメタの内容は全て、多の検索条件と “AND” で結合されます。

    例えば:

    Entry.objects.extra(where=['id IN (3, 4, 5, 20)'])
    

    は、(大雑把にいって) 以下のような SQL 文に変換されます:

    SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20);
    

    tables パラメタを使う場合、クエリ中にすでに登場しているテーブルを指 定していないか注意が必要です。 tables パラメタに追加のテーブル名を 指定して、それがすでにクエリ中に含まれているテーブルであった場合、 Django はユーザがそのテーブルをさらに加えようとしているものとみなします。 その場合、追加されたテーブルの名前にはエイリアスがつけられるので、問題 を引き起こします。 SQL 文の中に同じテーブルを複数回登場させる場合、デー タベースがそれぞれのテーブルを区別できるように、2度目以降のテーブル名に はエイリアスをつけねばなりません。そのため、 where パラメタにすでに クエリ中に存在するテーブル名を渡すと、エラーを引き起こすのです。

    通常は、すでにクエリ中に存在するテーブル名を追加するような作業はしない はずです。しかし、上で述べたようなことが起きてしまう場合には、いくつか 解決方法があります。まず、追加でテーブル名を指定しなくても正しくクエリ を実行できるか試してください。それがだめなら、クエリセットを構築する際 に、 extra() を先に呼び出して、テーブル名を最初に登場させてみてく ださい。最後に、どうしてもうまくいかないのなら、生成されるクエリを見て、 where を書き直し、テーブル名にエイリアスを与えてみてください。 エイリアスは同じ方法でクエリセットを生成している限り同じ名前を持つので、 エイリアス名は変化しないものとして扱えます。

  • order_by

    クエリセットの評価結果を、 extra() に入れたフィールドやテーブルに基 づいて並べ替えたい場合は、 extra()order_by パラメタを指定し てください。 order_by は文字列のシーケンスで指定します。各文字列は (order_by() メソッドで指定するような) モデルフィールド名か、 table_name.column_name 形式か、 extra()select パラメ タに指定したカラムのエイリアスのいずれかで指定します。

    例を示しましょう:

    q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
    q = q.extra(order_by = ['-is_recent'])
    

    上の例は、 is_recent が真であるような結果を先に表示します (True よりも False が先にくるのは降順のときだからです)。

    ちなみに、上の例でわかるように、 extra() は何度も呼び出しできます。 (その度に、制約条件が追加されてゆきます)。

  • params

    上で説明した where パラメタでは、標準の Python の文字列プレースホル ダ '%s' を使って、データベースエンジンが自動的にパラメタをクオート するよう指示できます。 params 引数には、プレースホルダで置き換えら れるパラメタのリストを指定します。

    例えば:

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    

    where の中に直接値を埋め込まず、常に params を使うようにしてく ださい。というのも、 params を使えば、バックエンド固有の方法でパラ メタの値を正しくクオートするからです。 例えば引用符文字などを正しくエ スケープします。

    悪い例:

    Entry.objects.extra(where=["headline='Lennon'"])
    

    良い例:

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    
defer
defer(*fields)

In some complex data-modeling situations, your models might contain a lot of fields, some of which could contain a lot of data (for example, text fields), or require expensive processing to convert them to Python objects. If you are using the results of a queryset in some situation where you know you don’t know if you need those particular fields when you initially fetch the data, you can tell Django not to retrieve them from the database.

This is done by passing the names of the fields to not load to defer():

Entry.objects.defer("headline", "body")

A queryset that has deferred fields will still return model instances. Each deferred field will be retrieved from the database if you access that field (one at a time, not all the deferred fields at once).

You can make multiple calls to defer(). Each call adds new fields to the deferred set:

# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")

The order in which fields are added to the deferred set does not matter. Calling defer() with a field name that has already been deferred is harmless (the field will still be deferred).

You can defer loading of fields in related models (if the related models are loading via select_related()) by using the standard double-underscore notation to separate related fields:

Blog.objects.select_related().defer("entry__headline", "entry__body")

If you want to clear the set of deferred fields, pass None as a parameter to defer():

# Load all fields immediately.
my_queryset.defer(None)

Some fields in a model won’t be deferred, even if you ask for them. You can never defer the loading of the primary key. If you are using select_related() to retrieve related models, you shouldn’t defer the loading of the field that connects from the primary model to the related one (at the moment, that doesn’t raise an error, but it will eventually).

Note

The defer() method (and its cousin, only(), below) are only for advanced use-cases. They provide an optimization for when you have analyzed your queries closely and understand exactly what information you need and have measured that the difference between returning the fields you need and the full set of fields for the model will be significant.

Even if you think you are in the advanced use-case situation, only use defer() when you cannot, at queryset load time, determine if you will need the extra fields or not. If you are frequently loading and using a particular subset of your data, the best choice you can make is to normalize your models and put the non-loaded data into a separate model (and database table). If the columns must stay in the one table for some reason, create a model with Meta.managed = False (see the managed attribute documentation) containing just the fields you normally need to load and use that where you might otherwise call defer(). This makes your code more explicit to the reader, is slightly faster and consumes a little less memory in the Python process.

only
only(*fields)

The only() method is more or less the opposite of defer(). You call it with the fields that should not be deferred when retrieving a model. If you have a model where almost all the fields need to be deferred, using only() to specify the complementary set of fields can result in simpler code.

Suppose you have a model with fields name, age and biography. The following two querysets are the same, in terms of deferred fields:

Person.objects.defer("age", "biography")
Person.objects.only("name")

Whenever you call only() it replaces the set of fields to load immediately. The method’s name is mnemonic: only those fields are loaded immediately; the remainder are deferred. Thus, successive calls to only() result in only the final fields being considered:

# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")

Since defer() acts incrementally (adding fields to the deferred list), you can combine calls to only() and defer() and things will behave logically:

# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")

# Final result loads headline and body immediately (only() replaces any
# existing set of fields).
Entry.objects.defer("body").only("headline", "body")

All of the cautions in the note for the defer() documentation apply to only() as well. Use it cautiously and only after exhausting your other options.

using
using(alias)
リリースノートを参照してください

This method is for controlling which database the QuerySet will be evaluated against if you are using more than one database. The only argument this method takes is the alias of a database, as defined in DATABASES.

For example:

# queries the database with the 'default' alias.
>>> Entry.objects.all()

# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')
select_for_update
select_for_update(nowait=False)
リリースノートを参照してください

Returns a queryset that will lock rows until the end of the transaction, generating a SELECT ... FOR UPDATE SQL statement on supported databases.

For example:

entries = Entry.objects.select_for_update().filter(author=request.user)

All matched entries will be locked until the end of the transaction block, meaning that other transactions will be prevented from changing or acquiring locks on them.

Usually, if another transaction has already acquired a lock on one of the selected rows, the query will block until the lock is released. If this is not the behavior you want, call select_for_update(nowait=True). This will make the call non-blocking. If a conflicting lock is already acquired by another transaction, DatabaseError will be raised when the queryset is evaluated.

Note that using select_for_update() will cause the current transaction to be considered dirty, if under transaction management. This is to ensure that Django issues a COMMIT or ROLLBACK, releasing any locks held by the SELECT FOR UPDATE.

Currently, the postgresql_psycopg2, oracle, and mysql database backends support select_for_update(). However, MySQL has no support for the nowait argument. Obviously, users of external third-party backends should check with their backend’s documentation for specifics in those cases.

Passing nowait=True to select_for_update using database backends that do not support nowait, such as MySQL, will cause a DatabaseError to be raised. This is in order to prevent code unexpectedly blocking.

Using select_for_update on backends which do not support SELECT ... FOR UPDATE (such as SQLite) will have no effect.

QuerySet を返さないメソッド

以下のクエリセットメソッドは、クエリセットを評価して、クエリセット でない 値を返します。

これらのメソッドはキャッシュを使わず (後述の キャッシュとクエリセット を参照してください)、メソッド呼び出しごとにデータベースにクエリをかけます。

get
get(**kwargs)

照合パラメタに一致するオブジェクトを返します。照合パラメタは後述の フィールドの照合 で説明するフォーマットにします。

複数のオブジェクトがみつかると、 get()MultipleObjectsReturned を送出します。The MultipleObjectsReturned exception is an attribute of the model class.

指定パラメタに対するオブジェクトが見つからなかった場合には get()DoesNotExist 例外を送出します。この例外は モデルクラスの属性の一つです。例えば:

Entry.objects.get(id='foo') # raises Entry.DoesNotExist

DoesNotExist 例外は django.core.exceptions.ObjectDoesNotExist を継承しているので、 複数の DoesNotExist 例外を except: のターゲットにできます。例えば:

from django.core.exceptions import ObjectDoesNotExist
try:
    e = Entry.objects.get(id=3)
    b = Blog.objects.get(id=1)
except ObjectDoesNotExist:
    print "Either the entry or blog doesn't exist."
create
create(**kwargs)

ワンステップでオブジェクトを生成して保存するための便宜メソッドです。 すなわち、以下の文:

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

と、以下の文:

p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)

は等価です。

force_insert パラメタはここでは説明してい ませんが、このパラメタを指定すると、常に新たなオブジェクトを生成します。 通常は、このパラメタのことを気にする必要はありません。しかし、モデルに手動 で設定した主キーが存在していて、すでにデータベース上にある主キーと同じ値を もったオブジェクトを create() して保存しようとすると、主キーの一意性が 破れてしまうため、 IntegrityError を引き起こしてしまいます。 ですから、手動で主キーを設定したときには、例外処理を準備しておいてください。

get_or_create
get_or_create(**kwargs)

kwargs に指定したオブジェクトを照合し、なければ生成するための便宜メソッドで す。

(object, created) の形式のタプルを返します。 object は取得または作 成されたオブジェクトであり、 created はブール値で、オブジェクトが新たに 生成されたかどうかを示します。

このメソッドは、お決まりのコードを書く上でのショートカットとして定義されて おり、データを取り込むスクリプトを書くときに便利です。例えば:

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()

このようなコードパターンでは、モデル中のフィールドが増えると手に負えなくな ります。 get_or_create() を使うと、上のコード例は以下のように書き直せま す:

obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon',
                  defaults={'birthday': date(1940, 10, 9)})

get_or_create() に渡されたキーワード引数は、 (オプションの引数である defaults を除いて) 全て get() の呼び出し時の引数として渡されます。 オブジェクトが見つかった場合、 get_or_create() は見つかったオブジェクト と False を返します。オブジェクトが 見つからなかった 場合、新たに生成 されたオブジェクトと True を返します。新たなオブジェクトは以下のアルゴ リズムで作成されます:

defaults = kwargs.pop('defaults', {})
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
params.update(defaults)
obj = self.model(**params)
obj.save()

上のコードを日本語で表すなら、まず 'defaults' でないキーワード引数のう ち、二重アンダースコアを含まないもの (二重アンダースコアはあいまい照合のキー ワードなので除外します) を使ってパラメタ params を作成し、必要に応じて デフォルト値 defaults で内容を更新して、その結果をモデルクラスを呼び出 すときのキーワード引数に使う、という処理に相当します。上で示唆したように、 ここではアルゴリズムを簡単化して、必要な部分だけを記述しています。内部実装 では、もっと細かくエラーチェックを行い、境界条件を処理しています。興味があ るなら、ぜひコードを読んでみてください。

defaults という名前のフィールド名を持っていて、 get_or_create() の 中で厳密照合に使いたければ、以下のように 'defaults__exact' を使います:

Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})

主キーを手動で指定している場合、 get_or_create() メソッドは create() と同じようなエラーを引き起こします。すなわち、すでにデータベー ス上に存在するキーを使ってオブジェクトを生成しようとすると、 IntegrityError を送出します。

最後に、 Django ビューの中で get_or_create() を使う場合についてひとこと 注意しておきましょう。上で説明したように、主として get_or_create() が有 用なのは、データを解析し、該当する既存のデータが存在しない場合に新たなレコー ドを生成するようなスクリプトを書く場合です。ビューで get_or_create() を 使いたいのなら、特に理由のない限り POST リクエスト中で使うようにしましょ う。一般論として、 GET リクエストの処理中ではデータに影響を及ぼすべきで はありません。データに副作用をもたらすようなページのリクエストには常に POST を使うようにしましょう。詳しくは、 HTTP 仕様における 安全なメソッド を参照してください。

bulk_create
bulk_create(objs)
リリースノートを参照してください

This method inserts the provided list of objects into the database in an efficient manner (generally only 1 query, no matter how many objects there are):

>>> Entry.objects.bulk_create([
...     Entry(headline="Django 1.0 Released"),
...     Entry(headline="Django 1.1 Announced"),
...     Entry(headline="Breaking: Django is awesome")
... ])

This has a number of caveats though:

  • The model’s save() method will not be called, and the pre_save and post_save signals will not be sent.
  • It does not work with child models in a multi-table inheritance scenario.
  • If the model’s primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does.

Limits of SQLite

SQLite sets a limit on the number of parameters per SQL statement. The maximum is defined by the SQLITE_MAX_VARIABLE_NUMBER compilation option, which defaults to 999. For instance, if your model has 8 fields (including the primary key), you cannot create more than 999 // 8 = 124 instances at a time. If you exceed this limit, you’ll get an exception:

django.db.utils.DatabaseError: too many SQL variables

If your application’s performance requirements exceed SQLite’s limits, you should switch to another database engine, such as PostgreSQL.

count()
count()

クエリセットに一致するデータベース上のオブジェクトの個数を表す整数を返しま す。 count() メソッドは例外を送出しません。

例えば:

# データベース中のエントリの総数を返します。
Entry.objects.count()

# ヘッドラインが 'Lennon' を含むエントリの総数を返します。
Entry.objects.filter(headline__contains='Lennon').count()

count() の呼び出しは背後で SELECT COUNT(*) を実行するので、 単にオブジェクトの個数を数えたい場合には、全てのレコードを Python オブジェクトとしてロードしてから len() を呼び出すのではなく、常に count() を使うようにしてください。

(PostgreSQL や MySQL といった) どのデータベースを使っているかによって、 count() の戻り値が Python の通常の整数型ではなく、長整数になることもあ ります。これは実装上の問題であり、現実的に問題になることはありません。

in_bulk
in_bulk(id_list)

主キーの値のリストを引数にとり、各主キー値とオブジェクトを対応づけた辞書を 返します。

例えば:

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}

in_bulk() に空のリストを渡すと空の辞書を返します。

iterator
iterator()

QuerySet を評価し (クエリを実行し) て、その結果の入ったイテレータ (PEP 234 を参照してください) を返します。A QuerySet typically caches its results internally so that repeated evaluations do not result in additional queries. In contrast, iterator() will read results directly, without doing any caching at the QuerySet level (internally, the default iterator calls iterator() and caches the return value). For a QuerySet which returns a large number of objects that you only need to access once, this can results in better performance and a significant reduction in memory.

すでに値にアクセス済みの QuerySet に対して iterator() を呼び出すと、 値の評価が再度行われ、クエリが繰り返し発行されるので注意してください。

Also, use of iterator() causes previous prefetch_related() calls to be ignored since these two optimizations do not make sense together.

latest
latest(field_name=None)

日付フィールドである field_name の値に応じて、テーブル中の最新のオブジェ クトを返します。

以下の例では、 pub_date フィールドに応じて、テーブル中の最新の Entry を返します:

Entry.objects.latest('pub_date')

モデルの Metaget_latest_by を指定している場合、 latest()field_name 引数は省略できます。 Django は get_latest_by に指定したフィールドを デフォルト値にします。

get() と同様、 latest() は指定パラメタに一致するオブジェクトがない 場合に DoesNotExist を送出します。

latest() は純粋に利便性と可読性のためだけに存在しています。

aggregate
aggregate(*args, **kwargs)

Returns a dictionary of aggregate values (averages, sums, etc) calculated over the QuerySet. Each argument to aggregate() specifies a value that will be included in the dictionary that is returned.

The aggregation functions that are provided by Django are described in Aggregation Functions below.

Aggregates specified using keyword arguments will use the keyword as the name for the annotation. Anonymous arguments will have an name generated for them based upon the name of the aggregate function and the model field that is being aggregated.

For example, when you are working with blog entries, you may want to know the number of authors that have contributed blog entries:

>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}

By using a keyword argument to specify the aggregate function, you can control the name of the aggregation value that is returned:

>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}

For an in-depth discussion of aggregation, see the topic guide on Aggregation.

exists
exists()
リリースノートを参照してください

Returns True if the QuerySet contains any results, and False if not. This tries to perform the query in the simplest and fastest way possible, but it does execute nearly the same query. This means that calling QuerySet.exists() is faster than bool(some_query_set), but not by a large degree. If some_query_set has not yet been evaluated, but you know that it will be at some point, then using some_query_set.exists() will do more overall work (one query for the existence check plus an extra one to later retrieve the results) than simply using bool(some_query_set), which retrieves the results and then checks if any were returned.

update
update(**kwargs)

Performs an SQL update query for the specified fields, and returns the number of rows affected.

For example, to turn comments off for all blog entries published in 2010, you could do this:

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)

(This assumes your Entry model has fields pub_date and comments_on.)

You can update multiple fields — there’s no limit on how many. For example, here we update the comments_on and headline fields:

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')

The update() method is applied instantly, and the only restriction on the QuerySet that is updated is that it can only update columns in the model’s main table, not on related models. You can’t do this, for example:

>>> Entry.objects.update(blog__name='foo') # Won't work!

Filtering based on related fields is still possible, though:

>>> Entry.objects.filter(blog__id=1).update(comments_on=True)

You cannot call update() on a QuerySet that has had a slice taken or can otherwise no longer be filtered.

The update() method returns the number of affected rows:

>>> Entry.objects.filter(id=64).update(comments_on=True)
1

>>> Entry.objects.filter(slug='nonexistent-slug').update(comments_on=True)
0

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132

If you’re just updating a record and don’t need to do anything with the model object, the most efficient approach is to call update(), rather than loading the model object into memory. For example, instead of doing this:

e = Entry.objects.get(id=10)
e.comments_on = False
e.save()

...do this:

Entry.objects.filter(id=10).update(comments_on=False)

Using update() also prevents a race condition wherein something might change in your database in the short period of time between loading the object and calling save().

Finally, realize that update() does an update at the SQL level and, thus, does not call any save() methods on your models, nor does it emit the pre_save or post_save signals (which are a consequence of calling Model.save()). If you want to update a bunch of records for a model that has a custom save()`() method, loop over them and call save(), like this:

for e in Entry.objects.filter(pub_date__year=2010):
    e.comments_on = False
    e.save()
delete
delete()

Performs an SQL delete query on all rows in the QuerySet. The delete() is applied instantly. You cannot call delete() on a QuerySet that has had a slice taken or can otherwise no longer be filtered.

For example, to delete all the entries in a particular blog:

>>> b = Blog.objects.get(pk=1)

# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()

By default, Django’s ForeignKey emulates the SQL constraint ON DELETE CASCADE — in other words, any objects with foreign keys pointing at the objects to be deleted will be deleted along with them. For example:

blogs = Blog.objects.all()
# This will delete all Blogs and all of their Entry objects.
blogs.delete()
This cascade behavior is customizable via the on_delete argument to the ForeignKey.

The delete() method does a bulk delete and does not call any delete() methods on your models. It does, however, emit the pre_delete and post_delete signals for all deleted objects (including cascaded deletions).

フィールドの照合

フィールドの照合操作によって、 SQL の WHERE 節の中身が決まります。 フィールドの照合を行うには、 filter(), exclude() および get() といったクエリセットのメソッドのキーワード引数を指定します。

For an introduction, see models and database queries documentation.

exact

厳密な一致です、比較対象の値を None にすると、SQL における NULL と の比較として扱われます (詳しくは isnull を参照してください)。

使い方の例を示します:

Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)

これは、以下の SQL と等価です:

SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;

MySQL での比較

MySQL には「コレーション (collation)」という設定があり、 exact 比較 で大小文字を区別するか決めています。これはデータベースの設定であって、 Djangoの設定では ありません 。 MySQL のテーブルは大小文字を区別して比 較するように構成できますが、トレードオフもあります。詳しくは、 データベース ドキュメントの コレーションの節 を参照してください。

iexact

大小文字の区別をしない一致です。

使い方の例を示します:

Blog.objects.get(name__iexact='beatles blog')

これは、以下の SQL と等価です:

SELECT ... WHERE name ILIKE 'beatles blog';

この例は、 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG' などにマッチします。

SQLite users

When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons. SQLite does not do case-insensitive matching for Unicode strings.

contains

大小文字を区別する包含テストです。

使い方の例を示します:

Entry.objects.get(headline__contains='Lennon')

これは、以下の SQL と等価です:

SELECT ... WHERE headline LIKE '%Lennon%';

この例では、 'Lennon honored today' というヘッドラインには一致しますが、 'lennon honored today' には一致しません。

SQLite users

SQLite は大小文字を区別する LIKE をサポートしないので、 containsicontains と同じになります。See the database note for more information.

icontains

大小文字を区別しない包含テストです。

使い方の例を示します:

Entry.objects.get(headline__icontains='Lennon')

これは、以下の SQL と等価です:

SELECT ... WHERE headline ILIKE '%Lennon%';

SQLite users

When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons.

in

指定のリストに入っているものに一致します。

使い方の例を示します:

Entry.objects.filter(id__in=[1, 3, 4])

これは、以下の SQL と等価です:

SELECT ... WHERE id IN (1, 3, 4);

リテラル値のリストを渡す代わりに、クエリセットを使って動的なリストとして評 価してもかまいません:

q = Blog.objects.filter(name__contains='Cheddar').values('pk').query
e = Entry.objects.filter(blog__in=q)

このクエリセットは、以下の SQL と等価です:

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

また、上のコードは以下のようにも書けます:

inner_q = Blog.objects.filter(name__contains='Cheddar').values('pk').query
entries = Entry.objects.filter(blog__in=inner_q)

Warning

query 属性は、まだ明確に仕様の定まっていない内部的な属性です。 現在は上記のように問題なく使えますが、将来のバージョンで API が変更され るかもしれません。

This second form is a bit less readable and unnatural to write, since it accesses the internal query attribute and requires a ValuesQuerySet. If your code doesn’t require compatibility with Django 1.0, use the first form, passing in a queryset directly.

If you pass in a ValuesQuerySet or ValuesListQuerySet (the result of calling values() or values_list() on a queryset) as the value to an __in lookup, you need to ensure you are only extracting one field in the result. For example, this will work (filtering on the blog names):

inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
entries = Entry.objects.filter(blog__name__in=inner_qs)

This example will raise an exception, since the inner query is trying to extract two field values, where only one is expected:

# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
entries = Entry.objects.filter(blog__name__in=inner_qs)

Performance considerations

Be cautious about using nested queries and understand your database server’s performance characteristics (if in doubt, benchmark!). Some database backends, most notably MySQL, don’t optimize nested queries very well. It is more efficient, in those cases, to extract a list of values and then pass that into the second query. That is, execute two queries instead of one:

values = Blog.objects.filter(
        name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))

Note the list() call around the Blog QuerySet to force execution of the first query. Without it, a nested query would be executed, because クエリセットは遅延評価される.

gt

より大きい値に一致します。

使い方の例を示します:

Entry.objects.filter(id__gt=4)

これは、以下の SQL と等価です:

SELECT ... WHERE id > 4;
gte

等しいか、より大きい値に一致します。

lt

より少ない値に一致します。

lte

等しいか、より少ない値に一致します。

startswith

大小文字を区別する starts-with です。

使い方の例を示します:

Entry.objects.filter(headline__startswith='Will')

これは、以下の SQL と等価です:

SELECT ... WHERE headline LIKE 'Will%';

SQLite は大小文字を区別する LIKE をサポートしないので、 startswithistartswith と同じになります。

istartswith

大小文字を区別しない starts-with です。

使い方の例を示します:

Entry.objects.filter(headline__istartswith='will')

これは、以下の SQL と等価です:

SELECT ... WHERE headline ILIKE 'Will%';

SQLite users

When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons.

endswith

大小文字を区別する ends-with です。

使い方の例を示します:

Entry.objects.filter(headline__endswith='cats')

これは、以下の SQL と等価です:

SELECT ... WHERE headline LIKE '%cats';

SQLite users

SQLite は大小文字を区別する LIKE をサポートしないので、 endswithiendswith と同じです。Refer to the database note documentation for more.

iendswith

大小文字を区別しない ends-with です。

使い方の例を示します:

Entry.objects.filter(headline__iendswith='will')

これは、以下の SQL と等価です:

SELECT ... WHERE headline ILIKE '%will'

SQLite users

When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons.

range

範囲テスト (閉包テスト) です。

使い方の例を示します:

start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

これは、以下の SQL と等価です:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

range は日付、数値、文字など、SQL で BETWEEN を使える場所ならどこで も使えます。

year

date/datetime フィールドに対する、 year の厳密一致です。

使い方の例を示します:

Entry.objects.filter(pub_date__year=2005)

これは、以下の SQL と等価です:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31 23:59:59.999999';

(厳密な SQL シンタクスはデータベースエンジンによって違います。)

month

日付 (date) と日時 (datetime) フィールドに対する、 month の厳密一致です。 1 (1月) から 12 (12 月) までの整数を引数にとります。

使い方の例を示します:

Entry.objects.filter(pub_date__month=12)

これは、以下の SQL と等価です:

SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';

(厳密な SQL シンタクスはデータベースエンジンによって違います。)

day

日付 (date) と日時 (datetime) フィールドに対する day の厳密一致です。

使い方の例を示します:

Entry.objects.filter(pub_date__day=3)

これは、以下の SQL と等価です:

SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';

(厳密な SQL シンタクスはデータベースエンジンによって違います。)

このクエリ文は、「1 月 3 日」や「7 月 3 日」のように、毎月 3 日にマッチし ます。

week_day

For date and datetime fields, a ‘day of the week’ match.

Takes an integer value representing the day of week from 1 (Sunday) to 7 (Saturday).

Example:

Entry.objects.filter(pub_date__week_day=2)

(No equivalent SQL code fragment is included for this lookup because implementation of the relevant query varies among different database engines.)

Note this will match any record with a pub_date that falls on a Monday (day 2 of the week), regardless of the month or year in which it occurs. Week days are indexed with day 1 being Sunday and day 7 being Saturday.

Warning

When time zone support is enabled, Django uses UTC in the database connection, which means the year, month, day and week_day lookups are performed in UTC. This is a known limitation of the current implementation.

isnull

True または False を引数にとり、それぞれが IS NULL および IS NOT NULL に対応しています。

使い方の例を示します:

Entry.objects.filter(pub_date__isnull=True)

これは、以下の SQL と等価です:

SELECT ... WHERE pub_date IS NULL;
regex

正規表現による大小文字を区別した検索を行います。

正規表現の構文は各データベースバックエンドで使われているものと同じです。 組み込みの正規表現サポートが無い sqlite バックエンドの場合、 この機能は (Python で書かれた) ユーザ定義の REGEXP 関数で提供され、 したがって正規表現の文法は Python の re モジュールと同じになります。

使い方の例を示します:

Entry.objects.get(title__regex=r'^(An?|The) +')

これは、以下の SQL と等価です:

SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'c'); -- Oracle

SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite

正規表現を指定する場合には raw 文字列を使う ('foo' でなく r'foo' を使う) よう勧めます。

iregex

正規表現による大小文字を区別しない検索を行います。

使い方の例を示します:

Entry.objects.get(title__iregex=r'^(an?|the) +')

これは、以下の SQL と等価です:

SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle

SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
Aggregation functions

Django provides the following aggregation functions in the django.db.models module. For details on how to use these aggregate functions, see the topic guide on aggregation.

Avg
class Avg(field)

Returns the mean value of the given field, which must be numeric.

  • Default alias: <field>__avg
  • Return type: float
Count
class Count(field, distinct=False)

Returns the number of objects that are related through the provided field.

  • Default alias: <field>__count
  • Return type: int

Has one optional argument:

distinct

If distinct=True, the count will only include unique instances. This is the SQL equivalent of COUNT(DISTINCT <field>). The default value is False.

Max
class Max(field)

Returns the maximum value of the given field.

  • Default alias: <field>__max
  • Return type: same as input field
Min
class Min(field)

Returns the minimum value of the given field.

  • Default alias: <field>__min
  • Return type: same as input field
StdDev
class StdDev(field, sample=False)

Returns the standard deviation of the data in the provided field.

  • Default alias: <field>__stddev
  • Return type: float

Has one optional argument:

sample

By default, StdDev returns the population standard deviation. However, if sample=True, the return value will be the sample standard deviation.

SQLite

SQLite doesn’t provide StdDev out of the box. An implementation is available as an extension module for SQLite. Consult the SQlite documentation for instructions on obtaining and installing this extension.

Sum
class Sum(field)

Computes the sum of all values of the given field.

  • Default alias: <field>__sum
  • Return type: same as input field
Variance
class Variance(field, sample=False)

Returns the variance of the data in the provided field.

  • Default alias: <field>__variance
  • Return type: float

Has one optional argument:

sample

By default, Variance returns the population variance. However, if sample=True, the return value will be the sample variance.

SQLite

SQLite doesn’t provide Variance out of the box. An implementation is available as an extension module for SQLite. Consult the SQlite documentation for instructions on obtaining and installing this extension.

リクエストオブジェクトとレスポンスオブジェクト

revision-up-to:17812 (1.4)

簡単な概要

Django は、システム全体にわたって、リクエストとレスポンスオブジェクトを使っ て処理状態を受け渡します。

あるページへのリクエストを受け取ると、Django は HttpRequest オブジェクトを生成します。このオブジェク トにはリクエストのメタデータが入っています。次に Django は適切なビューをロー ドして、 HttpRequest をビュー関数の最初の引数に渡しま す。各ビューは HttpResponse オブジェクトを返さねばな りません。

このドキュメントでは HttpRequest および HttpResponse オブジェクトの API について説明します。

HttpRequest オブジェクト

class HttpRequest
属性

session 以外の属性は全て読み出し専用です。

HttpRequest.body
リリースノートを参照してください

Django 1.4 以前では、HttpRequest.bodyHttpRequest.raw_post_data でした.

生の HTTP リクエストのバイト文字列です。これは従来の HTML フォームと 異なる、バイナリ画像や XML ペイロードのデータを処理するのに便利です。 従来のフォームのデータを処理するためには HttpRequest.POST を 使って下さい。

リリースノートを参照してください

HttpRequest をファイルのようなインターフェースで読むことも出来ます。 後述の HttpRequest.read() も参照して下さい。

HttpRequest.path

リクエストしているページのフルパスを表す、ドメインを含まない文字列です。

例: "/music/bands/the_beatles/"

HttpRequest.path_info

いくつかの Web サーバーの設定において、ホストネーム以降の URL の一部が スクリプトプレフィックスの部分と PATH_INFO の部分に分割されます。 ( 例えば、これが発生するのは、 django.root オプションを Apache と mod_python で Django を動かす で使っている場合 ) path_info 属性には、どの Web サーバーが使われている かに関わらず、常にパスの PATH_INFO の部分が入ります。 path の代わりに使うことで、テストサーバーから本番 サーバーへの移行が簡単なコードにすることが出来ます。

例えば、もしアプリケーションの WSGIScriptAlias"/minfo" に 設定されていた場合、 path"/minfo/music/bands/the_beatles/"path_info"/music/bands/the_beatles/" になるでしょう。

HttpRequest.method

リクエストに使われた HTTP メソッドを表す文字列です。必ず大文字になります。 例:

if request.method == 'GET':
    do_something()
elif request.method == 'POST':
    do_something_else()
HttpRequest.encoding

提出されたフォームデータのデコードに使われる、現在のエンコーディングを 表す文字列です (None の場合もありますが、この場合は DEFAULT_CHARSET を使います)。この属性を変更すれば、フォーム データにアクセスする際に使われるエンコーディングを指定できます。一度エ ンコーディングを変更すると、変更後に (GETPOST の) 属性への アクセスはすべて新しい encoding の値に従って行われます。フォームデー タが DEFAULT_CHARSET 以外の特定のエンコーディングと分かって いる場合に便利です。

HttpRequest.GET

全ての HTTP GET パラメタが入った辞書ライクなオブジェクトです。後述の QueryDict も参照してください。

HttpRequest.POST

全ての HTTP POST パラメタが入った辞書ライクなオブジェクトです。後述の QueryDict も参照してください。

フォームを POST HTTP メソッドで要求し、その際に何らフォームデータを伴わ ないような場合には、リクエストが POST で送られていながらも POST 辞 書が空になることがあります。従って、リクエストが POST メソッドであるか どうかを調べるために if request.POST を使うべきではありません。代わ りに if request.method == "POST" を使ってください (上参照)。

POST にはファイルアップロードに関する情報は 入っていない ので注意 してください。 FILES を参照してください。

HttpRequest.REQUEST

便宜的な辞書オブジェクトで、 POST パラメタをまず検索してから、次に GET パラメタを検索します。 PHP の $_REQUEST にインスパイアされ た機能です。

例えば、 GET = {"name": "john"}POST = {"age": '34'} の場合、 REQUEST["name"]"john" になり、 REQUEST["age"]"34" になります。

通常は GET および POST を使うように強く勧めます。その方が明示的 だからです。

HttpRequest.COOKIES

全てのクッキーが入った標準の Python 辞書オブジェクトです。キーと値は文 字列です。

HttpRequest.FILES

アップロードされた全てのファイルが入っている辞書ライクオブジェクトです。 FILES の各キーは <input type="file" name="" />name に対応しています。 FILES の各値は後述の UploadedFile オブジ ェクトです.

詳しくは ファイルの管理 を参照してください。

FILES にデータが入るのは、リクエストが POST であり、かつリクエ ストをポストした <form>enctype="multipart/form-data がある 場合だけです。それ以外の場合、 FILES は空の辞書ライクオブジェクトに なります。

HttpRequest.META

標準の Python 辞書オブジェクトで、利用できる全ての HTTP ヘッダが入って います。利用可能なヘッダはクライアントとサーバごとに違いますが、例えば 以下のようなヘッダを利用できます:

  • CONTENT_LENGTH – リクエストのボディの長さ(文字列)です。
  • CONTENT_TYPE – リクエストのボディの MIME タイプです。
  • HTTP_ACCEPT_ENCODING – レスポンスとして利用可能な文字コードです。
  • HTTP_ACCEPT_LANGUAGE – レスポンスとして利用可能な言語です。
  • HTTP_HOST – クライアントによって送信された HTTP Host ヘッダです。
  • HTTP_REFERER – リクエスト対象のページを参照しているページが ある場合、そのページの URL です。
  • HTTP_USER_AGENT – クライアントのユーザエージェントの文字列です。
  • QUERY_STRING – パース前の単一のクエリ文字列です。
  • REMOTE_ADDR – クライアントの IP アドレスです。
  • REMOTE_HOST – クライアントのホスト名です。
  • REMOTE_USER – Web サーバーによって認証されたユーザがある場合、 そのユーザです。
  • REQUEST_METHOD"GET""POST" のような文字列です。
  • SERVER_NAME – サーバのホスト名です。
  • SERVER_PORT – サーバのポート番号(文字列)です。

CONTENT_LENGTHCONTENT_TYPE の例外を含め、上に示されたように、 リクエストのどの HTTP ヘッダも、すべての文字を大文字に変換し、すべての ハイフンをアンダーバーに置き換え、 名前に HTTP_ のプレフィックスを 付加して META のキーに変換されます。よって、例えば、 X-Bender というヘッダは METAHTTP_X_BENDER のキーに割り当てられます。

HttpRequest.user

現在ログインしているユーザを表す django.models.auth.models.User オブ ジェクトです。ユーザが現在ログインしていない場合には、 userdjango.contrib.auth.models.AnonymousUser のインスタンスになります。 is_authenticated() を使うと、これら二種類のユーザを区別できます:

if request.user.is_authenticated():
    # Do something for logged-in users.
else:
    # Do something for anonymous users.

user を利用できるのは、 インストールした Django で AuthenticationMiddleware を有効にした場合だけです。詳しくは Django でのユーザ認証 を参照してください。

HttpRequest.session

読み書き可能な辞書ライクオブジェクトで、現在のセッションを表現しています。 この辞書はインストールされている Django でセッションが有効な場合にのみ 利用できます。 詳しくは セッションのドキュメント を 参照してください。

HttpRequest.urlconf

Django 自体はこの属性を設定しませんが、他のコード(自作のミドルウェアな ど)でこの属性を設定した場合、Djangoはその値を ROOT_URLCONF の代わりにルート URLconf モジュール名として使います。 詳しくは 「 Django のリクエスト処理 」を参照してください。

メソッド
HttpRequest.get_host()

HTTP_X_FORWARDED_HOST ヘッダ(USE_X_FORWARDED_HOST が 有効化されている場合)と HTTP_HOST ヘッダを順に調べて、リクエストの 送信元を返します。クライアントがそれらの値を提供していない場合は PEP 3333 に従って、SERVER_NAMESERVER_PORT の組み合わせを 返します。

例: "127.0.0.1:8000"

Note

ホストが複数のプロキシを通しているとき、 get_host() は失敗します。一つの解決策は ロキシヘッダを書き換えるミドルウェアを利用することです。 以下に例を示します:

class MultipleProxyMiddleware(object):
    FORWARDED_FOR_FIELDS = [
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_FORWARDED_HOST',
        'HTTP_X_FORWARDED_SERVER',
    ]

    def process_request(self, request):
        """
        Rewrites the proxy headers so that only the most
        recent proxy is used.
        """
        for field in self.FORWARDED_FOR_FIELDS:
            if field in request.META:
                if ',' in request.META[field]:
                    parts = request.META[field].split(',')
                    request.META[field] = parts[-1].strip()

このミドルウェアは get_host() の値を利用する CommonMiddlewareCsrfViewMiddleware のような 他のミドルウェアの前に置かなければなりません。

HttpRequest.get_full_path()

path と、そのあとに続くクエリ文字列があれば返します。

例: "/music/bands/the_beatles/?print=true"

HttpRequest.build_absolute_uri(location)

location の絶対 URI を計算して返します。引数 location を省略する と、 location の値として request.get_full_path() を使います。

location の値がすでに絶対 URI であれば、値を変更しません。そうでない 場合、リクエスト中のサーバに関する変数を使って URI を構築します。

例: "http://example.com/music/bands/the_beatles/?print=true"

リリースノートを参照してください

署名付きクッキーのクッキーの値を返すか、署名が有効でない場合は BadSignature 例外を発生します。 default 引数を与えた場合は、例外は抑制され、代わりにデフォルトの 値が返されます。

オプションの salt 引数はシークレットキーへのブルートフォース攻撃に 対する追加の防御を与えるために利用されます。引数が与えられた場合、 max_age 引数は、 max_age 秒よりクッキーが古くないかを確認する ために、クッキーの署名されたタイムスタンプに対してチェックされます。

例:

>>> request.get_signed_cookie('name')
'Tony'
>>> request.get_signed_cookie('name', salt='name-salt')
'Tony' # assuming cookie was set using the same salt
>>> request.get_signed_cookie('non-existing-cookie')
...
KeyError: 'non-existing-cookie'
>>> request.get_signed_cookie('non-existing-cookie', False)
False
>>> request.get_signed_cookie('cookie-that-was-tampered-with')
...
 BadSignature: ...
 >>> request.get_signed_cookie('name', max_age=60)
 ...
 SignatureExpired: Signature age 1677.3839159 > 60 seconds
 >>> request.get_signed_cookie('name', False, max_age=60)
 False

詳細は 暗号による署名 を参照して下さい。

HttpRequest.is_secure()

リクエストがセキュアである、すなわち HTTPS を介したリクエストのときに True を返します。

HttpRequest.is_ajax()

リクエストが XMLHttpRequest である場合には True に設定されます。 リクエストが XMLHttpRequest であるかどうかは、 HTTP_X_REQUESTED_WITH ヘッダに文字列 XMLHttpRequest があるかどう かで判別します。このヘッダは、ほとんどのモダンな主要 JavaScript ライブ ラリでサポートされています。 ブラウザ側で XMLHttpRequest を呼び出す独自のコードを書いている場合、 is_ajax() を正しく機能させたいなら、 HTTP_X_REQUESTED_WITH ヘッ ダを適切に設定してください。

HttpRequest.read(size=None)
HttpRequest.readline()
HttpRequest.readlines()
HttpRequest.xreadlines()
HttpRequest.__iter__()
リリースノートを参照してください

HTTPRequest のインスタンスからファイルのようなインターフェースで 読むメソッドです。このメソッドはやってくるリクエストをストリーミング のやり方で消費することを可能にします。一般的な利用事例は大きな XML ペイロードを、反復パーサでメモリ上にすべての XML ツリーを 構築することなく、処理することです。

この標準的なインターフェースを使って、直接 ElementTree のような XML パーサに HTTPRequest インスタンスを渡すことが出来ます:

import xml.etree.ElementTree as ET
for element in ET.iterparse(request):
    process(element)

UploadedFile オブジェクト

class UploadedFile
属性
UploadedFile.name

アップロードされたファイルの名前。

UploadedFile.size

バイト単位でのアップロードされたファイルのサイズ。

メソッド
UploadedFile.chunks(chunk_size=None)

データの連続したチャンクを生成するジェネレータを返します。

UploadedFile.read(num_bytes=None)

引数のバイト数分ファイルを読みます。

QueryDict オブジェクト

HttpRequest オブジェクト内では、 GETPOST 属性は django.http.QueryDict のインスタンスです。 QueryDict は辞書ライクなクラスで、同じキーに対して複 数の値を取り得るようにカスタマイズされています。これは、 HTML のフォーム要 素には、例えば <select multiple="multiple"> のように、同じキーに対して 複数の値を渡すものがあるからです。

QueryDict インスタンスは、 copy() を作らないかぎ り変更できません。これは、 request.POSTrequest.GET の属性を直接 変更できないということです。

メソッド

QueryDict は辞書型のサブクラスなので、全ての標準的な 辞書型のメソッドを実装しています。ただし、以下の点が異なります:

QueryDict.__getitem__(key)

指定のキーに対する値を返します。一つのキーに複数の値が存在する場合、 __getitem__() はリストの末尾の値を返します。キーに対応する値がなけ れば、 django.utils.datastructures.MultiValueDictKeyError を送出 します。 (この例外は KeyError のサブクラスなので、 KeyError` を見張っていれば捕捉できます。)

QueryDict.__setitem__(key, value)

指定のキーに対する値を [value] (value という値が一つだけ入った リスト) にします。副作用をともなう他の関数と同じく、このメソッドを呼び 出せるのは (copy() を使って生成したオブジェクトのような) 変更可能な QueryDict だけです。

QueryDict.__contains__(key)

指定のキーが設定されている場合に True を返します。 if "foo" in request.GET のような書き方を実現します。

QueryDict.get(key, default)

上の __getitem__() と同じロジックですが、キーに対応する値がないとき にデフォルト値を返すフックがあります。

QueryDict.setdefault(key, default)

標準の辞書型の setdefault() と同じですが、内部的に __setitem__() を使います。

QueryDict.update(other_dict)

QueryDict または標準の辞書型を引数にとります。標 準の辞書型の update() メソッドと同じですが、現在の値を置き換えるの ではなく、現在の値のリストに 追加 します。例えば:

>>> q = QueryDict('a=1')
>>> q = q.copy() # to make it mutable
>>> q.update({'a': '2'})
>>> q.getlist('a')
[u'1', u'2']
>>> q['a'] # returns the last
[u'2']
QueryDict.items()

標準の辞書型の items()`() メソッドと同じですが、 __getitem__() と同じ、最後の値を返すロジックを使います。例えば:

>>> q = QueryDict('a=1&a=2&a=3')
>>> q.items()
[(u'a', u'3')]
QueryDict.iteritems()

標準の辞書型の iteritems() によく似ています。 QueryDict.items() と同じく、 QueryDict.__getitem__() で最後の値を返します。

QueryDict.iterlists()

QueryDict.iteritems() に似ていますが、各辞書のメンバの値を全て リストとして返します。

QueryDict.values()

values() – 標準の辞書型の values() メソッドと同じですが、 __getitem__() と同じ、最後の値を返すロジックを使います。例えば:

>>> q = QueryDict('a=1&a=2&a=3')
>>> q.values()
[u'3']
QueryDict.itervalues()

QueryDict.values() と同じですが、イテレータです。

加えて、 QueryDict には以下のメソッドがあります:

QueryDict.copy()

Python 標準ライブラリの copy.deepcopy() を使ってオブジェクトのコピー を生成して返します。コピーは変更可能になり、値を変更できます。

QueryDict.getlist(key, default)

要求されたキーに対して、 Python のリスト型を返します。キーに対応する値 がなく、デフォルトの値が与えられていなければ、空のリストを返します。 このメソッドは、デフォルトの値がリストでない場合を除き、確実に何らかの リストを返します。

default パラメタが追加されました。
QueryDict.setlist(key, list_)

キーに対して list_ を対応づけます (__setitem__() と違います)。

QueryDict.appendlist(key, item)

キーに関連づけられている内部的なリストに要素を追加します。

QueryDict.setlistdefault(key, default_list)

setdefault に似ていますが、単一の値ではなく値のリストを引数にとりま す。

QueryDict.lists()

動作は items() に似ていますが、全ての値をリストで返します。例え ば:

>>> q = QueryDict('a=1&a=2&a=3')
>>> q.lists()
[(u'a', [u'1', u'2', u'3'])]
QueryDict.dict()
リリースノートを参照してください

(キー, リスト) の表現に対し、 dict は (キー, アイテム)を持ちます。 アイテムとなるのはリストのうち、ひとつの要素で、 QueryDict.__getitem__() と同じロジックを用いています。

>>> q = QueryDict('a=1&a=3&a=5')
>>> q.dict()
{u'a': u'5'}
QueryDict.urlencode([safe])

データをクエリ文字列形式にフォーマットした文字列を返します。例えば:

>>> q = QueryDict('a=2&b=3&b=5')
>>> q.urlencode()
'a=2&b=3&b=5'
safe パラメタが追加されました。

オプションで、urlencodeにエンコードする必要がない文字列を渡すことが 出来ます。例えば:

>>> q = QueryDict('', mutable=True)
>>> q['next'] = '/a&b/'
>>> q.urlencode(safe='/')
'next=/a%26b/'

HttpResponse オブジェクト

class HttpResponse

Django によって自動生成される HttpRequest オブジェク トとは対象的に、 HttpResponse オブジェクトは自分で生 成せねばなりません。ビューを書くときにはいつでも、 HttpResponse インスタンスを生成して、値を設定し、戻り 値として返さねばなりません。

HttpResponse クラスは django.http モジュールで 定義されています。

使いかた
文字列を渡す

HttpResponse の典型的な使い方は、ページの内容を文字列 としてコンストラクタに渡すというものです:

>>> response = HttpResponse("Here's the text of the Web page.")
>>> response = HttpResponse("Text only, please.", content_type="text/plain")

コンテンツを累積的に追加していきたい場合には、 response をファイルライ クオブジェクトのようにも使えます:

>>> response = HttpResponse()
>>> response.write("<p>Here's the text of the Web page.</p>")
>>> response.write("<p>Here's another paragraph.</p>")
イテレータを渡す

最後に、ハードコードされた文字列ではなくイテレータも HttpResponse に渡せます。このテクニックを使う場合は以 下のガイドラインに従って下さい:

  • イテレータは文字列を返さねばなりません。
  • イテレータをコンテンツに指定して HttpResponse を初期化した場合、 HttpResponse インスタンスは ファイルライクオブジェクトとして扱えず、ファイルライクオブジェクトと して操作すると Exception を送出します。
ヘッダ情報をセットする

レスポンスのヘッダをセットしたり削除したりするには、レスポンスを辞書の ように扱います:

>>> response = HttpResponse()
>>> response['Cache-Control'] = 'no-cache'
>>> del response['Cache-Control']

辞書と異なり、 もしヘッダーが存在しない場合も、delKeyError を 発生させません。

HTTP ヘッダには改行を含めてはなりません。改行文字 (CR や LF) の入ったヘッダ をセットしようとすると、 BadHeaderError を送出します。

レスポンスをブラウザにファイルアタッチメントとして扱わせる

レスポンスをブラウザにファイルアタッチメントとして扱わせるには、 content_type 引数を使い、 Content-Disposition ヘッダをセットして ください。例えば、 Microsoft Excel のスプレッドシートを返すには、以下の ようにします:

>>> response = HttpResponse(my_data, content_type='application/vnd.ms-excel')
>>> response['Content-Disposition'] = 'attachment; filename=foo.xls'

Content-Disposition ヘッダの利用は Django 固有の仕様ではありませんが、 記法を忘れやすいのでここに示しておきます。

属性
HttpResponse.content

コンテンツを表現する文字列表現です。必要に応じて Unicode オブジェクト からエンコードされます。

HttpResponse.status_code

レスポンスの HTTP Status code です。

メソッド
HttpResponse.__init__(content='', mimetype=None, status=200, content_type=DEFAULT_CONTENT_TYPE)

指定のページコンテンツ (文字列) と MIME タイプで HttpResponse オブジェクトをインスタンス化します。 DEFAULT_CONTENT_TYPE'text/html' です。

content はイタレータまたは文字列でなければなりません。イタレータに する場合、イタレータは文字列を返さねばなりません。イテレータを指定した 場合、レスポンスの内容はイテレータの返す文字列を結合して生成されます。 イタレータまたは文字列でない場合、アクセスした際に文字列に変換される でしょう。

status はレスポンスの HTTP 状態コード です。

content_typemimetype の別名にすぎません。以前、このパラメタ には mimetype という名前しかありませんでしたが、実際のところ、この パラメタに指定する値は HTTP の Content-Type ヘッダに入る内容であり、 MIME タイプ仕様にはない文字セットエンコーディングの指定を含んでいました。 そこで、 mimetype が指定されている (None でない) 場合にはその値 を使い、それ以外の場合には content_type を使うように変更しました。 どちらのパラメタも省略すると、 DEFAULT_CONTENT_TYPE 設定を使 います。

HttpResponse.__setitem__(header, value)

ヘッダ名と値を設定します。 headervalue は文字列にせねばなり ません。

HttpResponse.__delitem__(header)

指定の名前のヘッダを削除します。ヘッダが存在しなければ、暗黙のうちに失 敗します。大小文字を区別しません。

HttpResponse.__getitem__(header)

指定のヘッダ名に対応する値を返します。大小文字を区別しません。

HttpResponse.has_header(header)

大小文字を区別せずに指定の名前のヘッダがあるか調べ、 True または False を返します。

リリースノートを参照してください

expiresdatetime.datetime オブジェクトを指定すると、 max_age が自動的に計算されます。 httponly 引数も追加されました。

リリースノートを参照してください

httponly のデフォルトの値が False から True に変わりました。

クッキーを設定します。パラメタは Python 標準ライブラリの Cookie.Morsel オブジェクトと同じ形式です。

  • max_age には秒数または None (デフォルト値) を指定します。 デフォルト値の場合、クッキーはクライアントのブラウザのセッションの 間だけ持続します。 expires が明示されていない場合、 expires は計算されます。

  • expires には "Wdy, DD-Mon-YY HH:MM:SS GMT" の形式の文字列か UTC での datetime.datetime オブジェクトを指定します。 expiresdatetime オブジェクトの場合、 max_age は 自動的に計算されます。

  • 別のドメインのクッキー (cross-domain cookie) を設定したい場合には、 domain を使います。例えば、 domain=".lawrence.com" にする と、 www.lawrence.com, blogs.lawrence.com, calendars.lawrence.com といったサイトでだけ読めるようになります。それ以外の場合、クッキー はクッキーを設定したドメインでしか読めません。

  • クライアントサイドの JavaScript がクッキーへアクセスすることを 妨げたい場合、 httponly=True を使います。

    HTTPOnly は HTTP レスポンスヘッダの Set-Cookie に含まれるフラグです。 これはクッキーの標準の RFC 2109 の一部ではなく、全てのブラウザに よって常に守られません。しかし守られた場合、これはクライアントサイド スクリプトが、保護されたクッキーのデータにアクセスする危険を緩和す る有用な方法です。

リリースノートを参照してください

set_cookie() と同様のメソッドです。しかし、 セットする前に 暗号による署名 を行って下さい。 HttpRequest.get_signed_cookie() と併せて使って下さい。オプションで 鍵の強化のために salt 引数を使うことが出来ますが、対応する HttpRequest.get_signed_cookie() の呼び出しでも、 salt 引数を 渡す必要があります。

指定のキーに対するクッキーを削除します。キーが存在しなければ、暗黙のう ちに失敗します。

cookie の動作原理上、 pathdomainset_cookie() に指定 した値と同じにしないと、クッキーを削除できなくなります。

HttpResponse.write(content)

HttpResponse インスタンスをファイルライクオブジェ クトのように扱うためのメソッドです。

HttpResponse.flush()

HttpResponse インスタンスをファイルライクオブジェ クトのように扱うためのメソッドです。

HttpResponse.tell()

HttpResponse インスタンスをファイルライクオブジェ クトのように扱うためのメソッドです。

HttpResponse のサブクラス

Django には、様々なタイプの HTTP レスポンスを扱うための HttpResponse のサブクラスがあります。これらのサブクラ スは HttpResponse と同じく django.http モジュー ルにあります。

class HttpResponseRedirect

コンストラクタはリダイレクト先のパスを示す引数を一つだけ取ります。リダ イレクト先は完全指定の URL (例えば "http://www.yahoo.com/search/") でも、ドメイン名のない絶対 URL ( "/search/") でもかまいません。この レスポンスオブジェクトは HTTP 状態コード 302 を返します。

class HttpResponsePermanentRedirect

HttpResponseRedirect と同じですが、”found” リダイレクト (HTTP 状態 コード 302) ではなく永続リダイレクト (状態コード 301) を使います。

class HttpResponseNotModified

コンストラクタは引数をとりません。ユーザが最後にリクエストしたときから ページが変更されていないこと (状態コード 304) を知らせるために使います。

class HttpResponseBadRequest

HttpResponse と同じように振舞いますが、状態コード 400 を使います。

class HttpResponseNotFound

HttpResponse と同じですが、状態コード 404 を使い ます。

class HttpResponseForbidden

HttpResponse と同じですが、状態コード 403 を使い ます。

class HttpResponseNotAllowed

HttpResponse と同じですが、状態コード 405 を使い ます。許可されている HTTP メソッドのリスト (例えば ['GET', 'POST']) を必須の引数としてとります。

class HttpResponseGone

HttpResponse と同じですが、状態コード 410 を使い ます。

class HttpResponseServerError

HttpResponse と同じですが、状態コード 500 を使います。

Note

もし、 HttpResponse のカスタムサブクラスが render メソッドを 実装している場合は、 Django はそれを SimpleTemplateResponse を真似たもの として扱うでしょう、また render メソッドは有効なレスポンスオブジェクトを 返さなければなりません。

settings に設定できる値

revision-up-to:11321 (1.1)

このドキュメントでは、利用可能な全ての設定のリストを示します。リストはアル ファベット順で、デフォルト値も示します。

ABSOLUTE_URL_OVERRIDES

デフォルト値: {} (空の辞書)

モデルオブジェクトのパスを表す文字列 "app_label.model_name" から、モデ ルオブジェクトを引数にとり URL を返すような関数への対応づけを行うための辞書 です。 Django で作成したプロジェクトのインストール先ごとに get_absolute_url() メソッドを上書きするのに役立ちます。例えば:

ABSOLUTE_URL_OVERRIDES = {
    'blogs.weblog': lambda o: "/blogs/%s/" % o.slug,
    'news.story': lambda o: "/stories/%s/%s/" % (o.pub_year, o.slug),
}

もとのモデルクラス名で使っている文字ケースに関係なく、モデル名は小文字にせ ねばならないので注意してください。

ADMIN_FOR

デフォルト値: () (空のタプル)

admin 用サイトの設定モジュールで設定します。このサイトの admin を他のサイト の admin にする場合、設定モジュールを ('foo.bar.baz' の形式のタプルで) 指定します。

admin サイトはこの変数を使って、モデルやビュー、テンプレートタグのドキュメ ントに対するイントロスペクションを自動的に行います。

ADMIN_MEDIA_PREFIX

デフォルト値: '/media/'

Django の管理インタフェース上で使われている CSS, JavaScript, 画像といった、 いわゆる admin メディアへの URL プレフィクスです。必ず末尾にスラッシュをつ けてください。また、この値は MEDIA_URL と同じにしないでください (さもな いと、二つのファイルに同じ URL がマップされてしまいます)。

ADMINS

デフォルト値: () (空のタプル)

コード中で発生したエラーを報告する連絡先を列挙するタプルです。 DEBUG=False の設定で、ビューが例外を送出すると、 Django はこの設定値に 列挙されている相手全てに全ての例外情報の入った通知メールを送ります。タプル に入れる各メンバは、 (Full name, e-mail address) の形式で指定します。例えば:

(('John', 'john@example.com'), ('Mary', 'mary@example.com'))

Django はエラーが生じたときに、このリストに登録されている 全ての 宛先にメー ルを送信します。詳しくは howto-error-reporting を参照してください。

ALLOWED_INCLUDE_ROOTS

デフォルト値: () (空のタプル)

{% ssi %} テンプレートタグで取り込める URL のプレフィクスを表す文字列か らなるタプルです。この設定はセキュリティを高めるためのもので、テンプレート の作者に取り込みを禁じられているファイルにアクセスさせないようにします。

例えば、 ALLOWED_INCLUDE_ROOTS('/home/html', '/var/www') にして おくと、 {% ssi /home/html/foo.txt %} は期待通りに動作しますが、 {% ssi /etc/passwd %} はうまくいきません。

APPEND_SLASH

デフォルト値: True

URL の末尾に常にスラッシュを追加するかどうかを決めます。 CommonMiddleware がインストールされている場合にしか使われません。 (topics-http-middleware を参照してください。) PREPEND_WWW も参照 してください。

AUTHENTICATION_BACKENDS

デフォルト値: ('django.contrib.auth.backends.ModelBackend',)

認証バックエンドのクラス名を (文字列で) 列挙したタプルです。ユーザ認証を試 みる際に使われます。詳しくは 認証バックエンドのドキュメント を参照して ください。

AUTH_PROFILE_MODULE

デフォルト値: 定義されていません

サイト固有のユーザプロファイルモデルです。詳しくは 追加のユーザ情報の保存 を参照してください。

CACHE_BACKEND

デフォルト値: 'locmem://'

利用するキャッシュバックエンドを指定します。 Django のキャッシュフレームワーク を参照して ください。

CACHE_MIDDLEWARE_KEY_PREFIX

デフォルト値: '' (空文字列)

キャッシュミドルウェアが使うキャッシュキープレフィクスを指定します。 Django のキャッシュフレームワーク を参照してください。

CACHE_MIDDLEWARE_SECONDS

デフォルト値: 600

キャッシュミドルウェアや cache_page() デコレータを使うときに、ページを キャッシュしておく秒数のデフォルト値です。

DATABASE_ENGINE

デフォルト値: '' (空文字列)

どのデータベースバックエンドを使うかを指定します。組み込みのデータベースバッ クエンドは、 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3', 'oracle' です。

Django に組み込まれていないデータベースバックエンドを組み込むために、 DATABASE_ENGINE にバックエンドモジュールの完全指定パス (例えば mypackage.backends.whatever) を指定できます。全く新しいデータベースバッ クエンドの作成は、読者の皆さんに委ねます。他のバックエンドの例を参照してく ださい。 .. versionchanged:: 1.0

1.0 で、外部のデータベースバックエンドをサポートしました。

DATABASE_HOST

デフォルト値: '' (空文字列)

データベース接続先のホストを指定します。空にしておくと localhost になります。 SQLite では使いません。

この変数がスラッシュ ('/') で始まっていて、 MySQL を使っている場合、 MySQL は指定された Unix ソケットを介して接続します。例えば:

DATABASE_HOST = '/var/run/mysql'

のように指定します。 MySQL を使っていて、この変数がスラッシュで始まっていな い場合には、この変数はホスト名として扱われます。

PostgreSQL を使っている場合、 DATABASE_HOST に空文字列を指定すると、 Unix ドメインソケットを使った接続を意味します。ローカルホストに対する TCP/IP 接続を指定したければ localhost と指定してください。

DATABASE_NAME

デフォルト値: '' (空文字列)

データベースの名前です。 SQLite の場合は、データベースファイルへのフルパス です。パスを指定するときは、 Windows 環境でも必ずスラッシュ (/) を区 切り文字に使ってください (例: C:/homes/user/mysite/sqlite3.db)。

DATABASE_OPTIONS

デフォルト値: {} (空の辞書)

データベースに接続するときの追加のパラメタです。利用できるキーワードは個々 のバックエンドモジュールのドキュメントを参照してください。

DATABASE_PASSWORD

デフォルト値: '' (空文字列)

データベースに接続するときのパスワードです。SQLite では使いません。

DATABASE_PORT

デフォルト値: '' (空文字列)

データベースに接続するときのポート番号です。空文字を指定するとデフォルトの ポートを使います。SQLite では使いません。

DATABASE_USER

デフォルト値: '' (空文字列)

データベースに接続するときのユーザ名です。SQLite では使いません。

DATE_FORMAT

デフォルト値: 'N j, Y' (e.g. Feb. 4, 2003)

Django の admin サイトの変更履歴ページ (や、システムの他の部分で) 日付フィー ルドの表示に使うデフォルトのフォーマットです。 利用可能な日付フォーマット文字 を参照してください。

DATETIME_FORMAT , TIME_FORMAT , YEAR_MONTH_FORMAT および MONTH_DAY_FORMAT も参照してください。

DATETIME_FORMAT

デフォルト値: 'N j, Y, P' (e.g. Feb. 4, 2003, 4 p.m.)

Django の admin サイトの変更履歴ページ (や、システムの他の部分で) 日時フィー ルドの表示に使うデフォルトのフォーマットです。 利用可能な日付フォーマット文字 を参照してください。

DATE_FORMAT , TIME_FORMAT , YEAR_MONTH_FORMAT および MONTH_DAY_FORMAT も参照してください。

DEBUG

デフォルト値: False

デバッグモードのオンオフを切替えるブール値です。

settings に自作の設定項目を追加する場合、 django/views/debug.pyHIDDEN_SETTINGS に注意してください。この変数は正規表現になっていて、デ フォルトでは 'SECRET', 'PASSWORD', 'PROFANITIES' といった文字列 を含む全ての設定の DEBUG ビューへの表示を抑制して、信頼されていないユーザが バックトレースから重要な (あるいは攻撃的な) 設定項目を見なくてすむようにし ているからです。

とはいえ、デバッグ出力の様々な情報は、いついかなる状況でも衆目に晒すべきも のではないということを心得ておきましょう。ファイルパス、各設定項目などは、 攻撃者に対してサーバの様々な情報を与えてしまいます。

また、 DEBUG をオンにして Django を起動すると、Django は実行した SQL ク エリを全て記憶してしまうことも忘れないでください。この機能はデバッグ時には 便利ですが、運用時に使うとあっという間にメモリを消費してしまうでしょう。

決して DEBUG をオンにしたままサーバを運用しないでください。

DEBUG_PROPAGATE_EXCEPTIONS

デフォルト値: False

True にすると、 Django が通常ビュー関数に対して行っている例外処理が抑制 され、例外がそのまま送出されるようになります。テスト時に便利な機能ですが、 実運用環境で使うべきではありません。

DEFAULT_CHARSET

デフォルト値: 'utf-8'

全ての HttpResponse オブジェクトで、MIME タイプを手動で指定しなかった場 合に使われるデフォルトの文字セットです。 Content-Type ヘッダの生成時に DEFAULT_CONTENT_TYPE とともに使われます。

DEFAULT_CONTENT_TYPE

デフォルト値: 'text/html'

全ての HttpResponse オブジェクトで、MIME タイプを手動で指定しなかった場 合に使われるデフォルトのコンテンツタイプです。 Content-Type ヘッダの生 成時に DEFAULT_CHARSET とともに使われます。

DEFAULT_FILE_STORAGE

デフォルト値: django.core.files.storage.FileSystemStorage

特定のストレージシステムに依存せずにファイル関連の操作を行うときに使う、 デフォルトのファイルストレージクラスです。 topics-files を参照してく ださい。

DEFAULT_FROM_EMAIL

デフォルト値: 'webmaster@localhost'

サイト管理者からのさまざまな自動応答で使われるデフォルトの e-mail アドレス です。

DEFAULT_TABLESPACE

デフォルト値: '' (空文字列)

テーブルスペース名を明示していないモデルに使われるテーブルスペース 名です。バックエンドがサポートしている場合に限って有効です。

DEFAULT_INDEX_TABLESPACE

デフォルト値: '' (空文字列)

テーブルスペース名を明示していないフィールドインデクスに使われるテーブルス ペース名です。バックエンドがサポートしている場合に限って有効です。

DISALLOWED_USER_AGENTS

デフォルト値: () (空のタプル)

システム全体にわたり、ページの閲覧を許さないクライアントの User-Agent を表 すコンパイル済みの正規表現オブジェクトからなるリストです。相手にしたくない ロボットやクローラがいる場合に使って下さい。この設定は CommonMiddleware がインストールされている場合にしか使われません。 (topics-http-middleware を参照してください)。

EMAIL_HOST

デフォルト値: 'localhost'

e-mail の送信に使われるホスト名です。

EMAIL_PORT も参照してください。

EMAIL_HOST_PASSWORD

デフォルト値: '' (空文字列)

EMAIL_HOST に指定した SMTP サーバにアクセスする際のパスワードです。この 設定は EMAIL_HOST_USER と組み合わせて、 SMTP サーバの認証に使われます。 EMAIL_HOST_USEREMAIL_HOST_PASSWORD のどちらかが空文字列の場合、 Django は SMTP への認証を試みません。

EMAIL_HOST_USER も参照してください。

EMAIL_HOST_USER

デフォルト値: '' (空文字列)

EMAIL_HOST で定義されている SMTP サーバへのアクセスに使われるユーザ名で す。空文字列の場合、 Django は SMTP への認証を試みません。

EMAIL_HOST_PASSWORD も参照してください。

EMAIL_PORT

デフォルト値: 25

EMAIL_HOST で定義されている SMTP サーバのポート番号です。

EMAIL_SUBJECT_PREFIX

デフォルト値: '[Django] '

django.core.mail.mail_adminsdjango.core.mail.mail_managers が送 信するメールの題名に使われるプレフィクスです。末尾にはスペースを入れておいた 方がよいでしょう。

EMAIL_USE_TLS

デフォルト値: False

SMTP サーバとの通信に TLS (安全な接続) を使うかどうかを指定します。

FILE_CHARSET

デフォルト値: 'utf-8'

テンプレートファイルや SQL のデータファイルなどのファイルをファイルシステム から読み出すときに使う文字エンコーディングです。

FILE_UPLOAD_HANDLERS

デフォルト値:

("django.core.files.fileuploadhandler.MemoryFileUploadHandler",
 "django.core.files.fileuploadhandler.TemporaryFileUploadHandler",)

ファイルアップロード時に使うハンドラを指定するタプルです。詳しくは topics-files を参照してください。

FILE_UPLOAD_MAX_MEMORY_SIZE

デフォルト値: 2621440 (2.5 MB).

アップロード中のファイルをファイルシステム上にストリーム書き込み開始するま でに受け入れる最大サイズ (単位バイト) です。詳しくは topics-files を 参照してください。

FILE_UPLOAD_TEMP_DIR

デフォルト値: None

アップロード中のファイルを一時的に保存するためのディレクトリです。 None に指定すると、オペレーティングシステムごとに標準の一時ディレクトリを使いま す。例えば、 *nix スタイルのオペレーティングシステムでは ‘/tmp’ です。

詳しくは topics-files を参照してください。

FILE_UPLOAD_PERMISSIONS

デフォルト値: None

アップロードされたファイルに設定するファイルモードで、数字で表現 (例: 0644) します。ファイルモードの意味は os.chmod のドキュメント を 参照してください。

この値を設定しないか、 None にすると、アップロードされたファイルのモー ドはオペレーティングシステムに依存します。ほとんどのプラットフォームでは、 一時ファイルのファイルモードは 0600 で、メモリからファイルにデータを書 き出すときにはシステム標準の umask を使います。

Warning

ファイルモードの先頭には常に ``0`` をつけてください.

ファイルモードにあまりくわしくないのなら、先頭の 0 がとても 重要だということに注意してください。先頭の 0 は、値が 8 進数で あることを示しています。 644 のように指定すると、全くおかし な挙動になってしまうでしょう。

FIXTURE_DIRS

デフォルト値: () (空のタプル)

フィクスチャデータファイルの検索対象ディレクトリを順に挙げたリストです。 パスの表記は (Windows 環境でも) Unix 形式の前向きスラッシュにせねばなりませ ん。 Djangoアプリケーションのテスト も参照してください。

FORCE_SCRIPT_NAME

デフォルト値: None

None に指定すると、 HTTMP リクエストの SCRIPT_NAME 環境変数の代わり に指定値を使います。この設定は、サーバが指定する SCRIPT_NAME の内容を上 書きしたり、 SCRIPT_NAME を空にしたりするために使えます。

IGNORABLE_404_ENDS

デフォルト値: ('mail.pl', 'mailform.pl', 'mail.cgi', 'mailform.cgi', 'favicon.ico', '.php')

IGNORABLE_404_STARTS と 「 電子メールによるエラー通知 」を参照してく ださい。

IGNORABLE_404_STARTS

デフォルト値: ('/cgi-bin/', '/_vti_bin', '/_vti_inf')

404 通知 e-mail を使っている場合、このタプルに指定した文字列から始まる URL は無視されます。 SEND_BROKEN_LINK_EMAILS, IGNORABLE_404_ENDS および 電子メールによるエラー通知 も参照してくださ い。

INSTALLED_APPS

デフォルト値: () (空のタプル)

現在の Django インストール下で有効にしたい全てのアプリケーションを表す文字 列のタプルです。各文字列は、 django-admin.py startapp で作成した Django アプリケーションの入った Python パッケージを示す完全な Python パスでなければなりません。

INTERNAL_IPS

デフォルト値: () (空のタプル)

文字列で表した IP アドレスのタプルです。

  • DEBUGTrue の場合、デバッグコメント中に表示されます。
  • XViewMiddleware がインストールされている場合、X ヘッダを受信しま す。(topics-http-middleware も参照してください。)

LANGUAGE_CODE

デフォルト値: 'en-us'

現在の Django インストールにおける言語コード文字列です。この値は標準の言語 指定形式にせねばなりません。たとえば U.S. English は "en-us" にします。 topics-i18n も参照してください。

LANGUAGES

デフォルト値: 利用可能な言語からなるタプルです。このリストには頻繁に新たな 言語が登場しているので、そのコピーをここに記載していてもすぐに古い情報になっ てしまいます。現在サポートされている言語のリストは手元のソースコード中の django/conf/global_settings.py (または オンラインのソースコード) を 参照してください。

このリストは、例えば ('ja', 'Japanese') のように、 (言語コード, 言語名) の形式のタプルでできており、国際化機能で選択可能な言語を指定するために使い ます。詳しくは topics-i18n を参照してください。

一般に、デフォルト値をいじる必要はありません。Django が提供している言語セッ トの選択肢を狭めたい場合のみ設定してください。

カスタムの LANGUAGE 設定を定義する場合、(上の例に示したように) 各言語を 翻訳文字列として定義してかまいませんが、 django.utils.translationgettext() 関数ではなく、「ダミーの」 gettext() を使うようにしてくだ さい。設定ファイル内では 決して django.utils.translation を import し ないでください。このモジュールは settings の内容に依存しているため、循環 import を引き起こしてしまうからです。

解決方法は、上でも述べたように「ダミーの」 gettext() を使うというもので す。以下に設定ファイルの例を示します:

gettext = lambda s: s

LANGUAGES = (
    ('de', gettext('German')),
    ('en', gettext('English')),
)

このような書き方をした場合、 django-admin.py makemessage は翻訳対象文字 列をきちんと取り出せます。しかし、実行時に翻訳は行われません。従って、実行 時に LANGUAGES を使うようなコードでは、 本当の gettext() を使って 言語名をラップするようにしてください。

LOCALE_PATHS

デフォルト値: () (空のタプル)

Django が翻訳ファイルを探しに行く場所を指定するためのタプルです。 この変数の詳細とデフォルトの動作については、 translations-in-your-own-projects を参照してください。

LOGIN_REDIRECT_URL

デフォルト値: '/accounts/profile/'

controb.auth.login ビューに next パラメタが指定されていない場合の、 デフォルトのリダイレクト先 URL です。

login_required() デコレータを利用する ときなどに使う設定です。

LOGIN_URL

デフォルト値: '/accounts/login/'

login_required() デコレータを利用す るときなどに、ログインページへのリダイレクト先として使う設定です。

LOGOUT_URL

デフォルト値: '/accounts/logout/'

LOGIN_URL の対極にあたる、ログアウトページへのリダイレクト URL です。

MANAGERS

デフォルト値: () (空のタプル)

ADMINS と同じ形式のタプルで、 SEND_BROKEN_LINK_EMAILS=True の時に壊 れたリンクの通知を受けるメンバを指定します。

MEDIA_ROOT

デフォルト値: '' (空文字列)

現在の Django インストールにおいて、メディアファイルを収めているディレクト リへの絶対パスです。例えば "/home/media/media.lawrence.com/" です。 MEDIA_URL も参照してください。

MEDIA_URL

デフォルト値: '' (空文字列)

MEDIA_ROOT で提供されているメディアファイルを扱う URL です。例えば "http://media.lawrence.com" です。

URL にパス部を含める場合、末尾はスラッシュにせねばなりません。

良い例: "http://www.example.com/static/" 悪い例: "http://www.example.com/static"

MIDDLEWARE_CLASSES

デフォルト値:

('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',)

利用するミドルウェアクラスの Python パス名からなるタプルです。 topics-http-middleware も参照してください。.

MONTH_DAY_FORMAT

デフォルト値: 'F j'

Django の admin サイトにおける変更リストの日付フィールドの他、システムの各 所で月と日だけを表示する際に使われるデフォルトのフォーマットです。

例えば、 Django の admin サイトにおける変更リストページを日付による絞り込み でフィルタする場合、指定日のヘッダには日と月が表示されます。ロケールによっ ては異なったフォーマットになります。例えば、 U.S. English での “January 1” は、スペイン語では “1 Enero.” です。

利用可能な日付フォーマット文字 を参照してください。 DATE_FORMAT, DATETIME_FORMAT , TIME_FORMAT , YEAR_MONTH_FORMAT も参照してください。

PREPEND_WWW

デフォルト値: False

URL にサブドメイン名 “www.” が付いていない場合に付加するかどうかを決めます。 CommonMiddleware がインストールされている場合にのみ使われる設定です (topics-http-middleware を参照してください)。 APPEND_SLASH も参 照してください。

PROFANITIES_LIST

非道徳的な言葉 (profanity) のタプルです。 hasNoProfanities バリデータが 呼び出された際に、エラーを引き起こす単語のリストに使われます。

デフォルト値はここでは示しません。不道徳な言葉が入っているからです。デフォ ルト値を見たければ、 django/conf/global_settings.py を参照してください。

ROOT_URLCONF

デフォルト値: 定義されていません

ルート URLconf への完全な Python import パスを表す表す文字列です。例えば、 "mydjangoapps.urls" です。ルート URLconf は、 HttpRequest オブジェ クトに urlconf 属性を設定することで変更できます。 詳しくは Django のリクエスト処理 を参照してください。

SECRET_KEY

デフォルト値: '' (空文字列)

Django インストール毎に固有の秘密の鍵です。秘密鍵を使ったハッシュアルゴリズ ムのシードを生成するために使います。この値はランダムな文字列に指定してくだ さい。長ければ長いほど好ましくなります。 django-admin.py startproject を実行すると、自動的に値を生成します。

SERIALIZATION_MODULES

デフォルト値: 定義されていません

シリアライザのモジュールパスを (文字列) 指定した辞書です。辞書のキーはシリ アライザの識別名にします。例えば、 YAML のシリアライザを定義するには以下の ようにします:

SERIALIZATION_MODULES = { 'yaml' : 'path.to.yaml_serializer' }

SERVER_EMAIL

デフォルト値: 'root@localhost'

ADMINSMANAGERS にエラーメッセージを送信するときの送信元の e-mail アドレスです。

SESSION_ENGINE

デフォルト値: django.contrib.sessions.backends.db

Django がセッションデータを保存する方法を指定します。利用できる値は以下の通 りです:

  • 'django.contrib.sessions.backends.db'
  • 'django.contrib.sessions.backends.file'
  • 'django.contrib.sessions.backends.cache'

詳しくは セッションの使い方 を参照してください。

SESSION_EXPIRE_AT_BROWSER_CLOSE

デフォルト値: False

ブラウザを閉じたときにセッションを期限切れにするかどうかを決めます。 セッションの使い方 を参照してください。

SESSION_FILE_PATH

デフォルト値: None

ファイルベースのセッションストレージを使っている場合、この値でセッションデー タの保存場所を指定します。詳しくは セッションの使い方 を参照してく ださい。デフォルト値 (None) にすると、システム標準の一時ディレクトリを 使います。

SESSION_SAVE_EVERY_REQUEST

デフォルト値: False

リクエストごとにセッションデータを保存するかどうかを決めます。 セッションの使い方 も参照してください。

SITE_ID

デフォルト値: 定義されていません

django_sites データベース中で現在のサイトを示す ID の整数値です。この値 は、アプリケーションデータが特定のサイトに対してフックできるようにし、一つ のデータベースで複数のサイトのコンテンツを管理できるようにするためのもので す。

“sites” フレームワーク を参照してください。

TEMPLATE_CONTEXT_PROCESSORS

デフォルト値:

("django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media")

RequestContext のコンテキストに値を入れてゆく際に使われる呼び出し可能オ ブジェクトからなるタプルです。これらの呼び出し可能オブジェクトはリクエスト オブジェクトを引数にとり、コンテキストに統合する項目からなる辞書を返します。

TEMPLATE_DEBUG

デフォルト値: False

テンプレートのデバッグモードのオンオフを切替えるブール値です。この値を True にすると、 TemplateSyntaxError を報告する際にファンシーなエラー ページを出力します。この報告にはエラーに関係するテンプレートの一部分が表示 され、問題のある部分がハイライト表示されます。

Django は DEBUGTrue の場合にのみエラーページを表示するので、こ の設定の恩恵をうけたければ DEBUG を設定しておく必要があります。

DEBUG も参照してください。

TEMPLATE_DIRS

デフォルト値: () (空のタプル)

テンプレートソースファイルの入っている場所を検索順に並べたリストです。パス の区切りには Windows であっても Unix 形式のスラッシュを使って下さい。

Django テンプレート言語 も参照してください。.

TEMPLATE_LOADERS

デフォルト値:

('django.template.loaders.filesystem.load_template_source',
 'django.template.loaders.app_directories.load_template_source')

様々なソースからのテンプレートの import を実装している、呼び出し可能オブジェ クト (を指す文字列) のタプルです。 Python プログラマのための Django テンプレート言語ガイド も参照してくだ さい。

TEMPLATE_STRING_IF_INVALID

デフォルト値: '' (空文字列)

誤った (スペルを間違えたなど) 変数名に対してテンプレートシステムが出力する 文字列です。 無効な値の扱い を参照してください。

TEST_DATABASE_CHARSET

デフォルト値: None

テストデータベースの作成に使われている文字セットエンコーディングです。この 文字列の値はデータベースバックエンドに直接渡されるので、エンコーディングの 名前や書式はバックエンドごとに異なります。

この設定をサポートしているバックエンドは、 PostgreSQL (postgresql, postgresql_psycopg2) と MySQL (mysql) です。

TEST_DATABASE_COLLATION

デフォルト値: None

テストデータベースを生成する際のコレーション (collation) です。この値はデー タベースバックエンドに直接渡されるので、値の書式はバックエンドごとに異なり ます。

mysql バックエンドだけでサポートされています(くわしくは、MySQLマニュア ルの 10.3.2節 を参照してください)

TEST_DATABASE_NAME

デフォルト値: None

テストスイートを実行するときに使うデータベースの名前です。

データベースエンジンが SQLite のときにデフォルト値 (None) を指定すると、 テストのためのデータベースはメモリ上に展開されます。他のデータベースエンジ ンの場合、テストデータベースの名前として 'test_' + settings.DATABASE_NAME を使います。

Djangoアプリケーションのテスト を参照してください。

TEST_RUNNER

デフォルト値: 'django.test.simple.run_tests'

テストスイートを起動するためのメソッドの名前です。 Djangoアプリケーションのテスト を 参照してください。

TIME_FORMAT

デフォルト値: 'P' (e.g. 4 p.m.)

Django の admin サイトの変更履歴ページ (や、システムの他の部分で) 時刻フィー ルドの表示に使うデフォルトのフォーマットです。 利用可能な日付フォーマット文字 を参照してください。

DATE_FORMAT , DATETIMETIME_FORMAT , YEAR_MONTH_FORMAT および MONTH_DAY_FORMAT も参照してください。

TIME_ZONE

デフォルト値: 'America/Chicago'

現在の Django インストールが使うタイムゾーンを表す文字列です。 利用可能な選択肢 を参照してください。(利用可能な選択肢には、同じ行に複数 の選択肢をリストしていることに注意してください。あるタイムゾーンを表すには いずれか一つを選ぶことになります。例えば、ある行に 'Europe/London GB GB-Eire' と書かれている場合、 TIME_ZONE の設定には、最初の部分である 'Europe/London' だけを使います)。

この値は Django が全ての日付/時刻の変換に使うタイムゾーンであり、かならずし もサーバのタイムゾーンとは一致しないことに注意して下さい。例えば、一つのサー バで複数の Django サイトを運営し、個々に別々のタイムゾーン設定を持たせても かまいません。

通常、 Django は TIME_ZONE の設定に従って os.environ['TZ'] 変数を設 定します。そのため、ビューやモデルは自動的に正しいタイムゾーンを扱えるよう になります。しかしながら、 手動で設定する 場合には、 Django は TZ 環境変数を 操作しない ので、ユーザは自分の責任でプロセス を正しい環境の下で動作させねばなりません。

Note

Windows 環境では、 Django は信頼性のある方法でタイムゾーンを変更できま せん。 Windows で Django を動作させる場合、この変数はシステムのタイムゾー ンと一致させねばなりません。

URL_VALIDATOR_USER_AGENT

デフォルト値: Django/<version> (http://www.djangoproject.com/)

特定の URL が実在するかを Django が調べにゆく際に使う User-Agent ヘッダ の値です。 (URLFieldverify_exists を参照 してください。)

USE_ETAGS

デフォルト値: False

出力に “Etag” ヘッダを含めるかどうかを決めるブール値です。 “Etag” を含める と帯域の節約になりますが、パフォーマンスは低下します。この設定は CommonMiddleware がインストールされている場合にしか使われません。 (topics-http-middleware を参照してください。)

USE_I18N

デフォルト値: True

国際化システムを有効にするかどうかを決めるブール値です。この設定を使うと、 パフォーマンス向上のために簡単に国際化システムを無効化できます。この値を False にすると、 Django は国際化機構をロードしないような最適化を行いま す。

YEAR_MONTH_FORMAT

デフォルト値: 'F Y'

Django の admin サイトにおける変更リストの日付フィールドの他、システムの各 所で年と月だけを表示する際に使われるデフォルトのフォーマットです。

例えば、 Django の admin サイトにおける変更リストページを日付による絞り込み でフィルタする場合、指定月のヘッダには月と年が表示されます。ロケールによっ ては異なったフォーマットになります。例えば、 U.S. English での “January 2006” は、別のロケールでは “2006/January” になるかもしれません。

利用可能な日付フォーマット文字 を参照してください。 DATE_FORMAT , DATETIME_FORMAT , TIME_FORMAT および MONTH_DAY_FORMAT も参照してください。

シグナル

revision-up-to:17812 (1.4) unfinished

ここでは、 Django が送信する組み込みのシグナルについて解説します。

See also

See the documentation on the signal dispatcher for information regarding how to register for and receive signals.

コメントフレームワーク は、 コメントに関するシグナル を送信し ます。

The authentication framework sends signals when a user is logged in / out.

モデル関連のシグナル

django.db.models.signals モジュールでは、モデルシステムから送信され るシグナルを定義しています。

Warning

ここに挙げるシグナルの多くは、 __init__()save() といった、オーバライド可能な様々 なメソッドから送信されます。

従って、これらのメソッドをオーバライドする場合、親クラスのメソッドを呼 び出して、シグナルが送信されるようにせねばなりません。

Note also that Django stores signal handlers as weak references by default, so if your handler is a local function, it may be garbage collected. To prevent this, pass weak=False when you call the signal’s connect().

pre_init
django.db.models.signals.pre_init

Django モデルをインスタンス化するとき、モデルの __init__() 処理の最初の段階で送信されます。

シグナルの引数は以下の通りです:

sender
インスタンスを作成したモデルクラスです。
args
__init__() に渡された固定引数のリスト です。
kwargs
__init__() に渡されたキーワード引数の リストです。

例えば、 チュートリアル には以下のような行があり ます:

p = Poll(question="What's up?", pub_date=datetime.now())

この行の中で送信されるシグナルを pre_init ハンドラで受けたときの引 数は以下の通りです:

引数
sender Poll (クラス自体)
args [] (__init__ には固定引数がないので空)
kwargs {'question': "What's up?", 'pub_date': datetime.now()}
post_init
django.db.models.signals.post_init

pre_init とほぼ同じですが、 __init__() の処理が終る直前に送信されます。

引数は以下の通りです:

sender
pre_init と同じ、インスタンスを生成したモデルクラスです。
instance
実際に生成されたモデルインスタンスです。
pre_save
django.db.models.signals.pre_save

モデルインスタンスの save() の処理の最初に呼 び出されます。

引数は以下の通りです:

sender
モデルクラスです。
instance
これから保存されるインスタンスです。
raw
A boolean; True if the model is saved exactly as presented (i.e. when loading a fixture). One should not query/modify other records in the database as the database might not be in a consistent state yet.
リリースノートを参照してください
using
The database alias being used.
post_save
django.db.models.signals.post_save

pre_save に似ていますが、 save() メソッ ドの処理の最後に呼び出されます。

引数は以下の通りです

sender
モデルクラスです。
instance
保存されたインスタンスです。
created
ブール値で、レコードが新たに作成されたときに True を返します。
raw
A boolean; True if the model is saved exactly as presented (i.e. when loading a fixture). One should not query/modify other records in the database as the database might not be in a consistent state yet.
リリースノートを参照してください
using
The database alias being used.
pre_delete
django.db.models.signals.pre_delete

モデルインスタンスの delete() メソッド、 およびクエリーセットの delete() メソッド の処理の先頭で呼出されます。

引数は以下の通りです:

sender
モデルクラスです。
instance
削除されるインスタンスです。
リリースノートを参照してください
using
The database alias being used.
post_delete
django.db.models.signals.post_delete

pre_delete に似ていますが、 delete() メソッドおよびクエリーセットの delete() メソッドの処理の最後に呼び出されます。

引数は以下の通りです:

sender
モデルクラスです。
instance

削除されたインスタンスです。

オブジェクトはもはやデータベース上に存在しないので、このインスタン スの扱いには十分注意してください。

リリースノートを参照してください
using
The database alias being used.
m2m_changed
django.db.models.signals.m2m_changed
リリースノートを参照してください

Sent when a ManyToManyField is changed on a model instance. Strictly speaking, this is not a model signal since it is sent by the ManyToManyField, but since it complements the pre_save/post_save and pre_delete/post_delete when it comes to tracking changes to models, it is included here.

Arguments sent with this signal:

sender
The intermediate model class describing the ManyToManyField. This class is automatically created when a many-to-many field is defined; you can access it using the through attribute on the many-to-many field.
instance
The instance whose many-to-many relation is updated. This can be an instance of the sender, or of the class the ManyToManyField is related to.
action

A string indicating the type of update that is done on the relation. This can be one of the following:

"pre_add"
Sent before one or more objects are added to the relation.
"post_add"
Sent after one or more objects are added to the relation.
"pre_remove"
Sent before one or more objects are removed from the relation.
"post_remove"
Sent after one or more objects are removed from the relation.
"pre_clear"
Sent before the relation is cleared.
"post_clear"
Sent after the relation is cleared.
reverse
Indicates which side of the relation is updated (i.e., if it is the forward or reverse relation that is being modified).
model
The class of the objects that are added to, removed from or cleared from the relation.
pk_set

For the pre_add, post_add, pre_remove and post_remove actions, this is a list of primary key values that have been added to or removed from the relation.

For the pre_clear and post_clear actions, this is None.

リリースノートを参照してください
using
The database alias being used.

For example, if a Pizza can have multiple Topping objects, modeled like this:

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

If we would do something like this:

>>> p = Pizza.object.create(...)
>>> t = Topping.objects.create(...)
>>> p.toppings.add(t)

the arguments sent to a m2m_changed handler would be:

Argument Value
sender Pizza.toppings.through (the intermediate m2m class)
instance p (the Pizza instance being modified)
action "pre_add" (followed by a separate signal with "post_add")
reverse False (Pizza contains the ManyToManyField, so this call modifies the forward relation)
model Topping (the class of the objects added to the Pizza)
pk_set [t.id] (since only Topping t was added to the relation)
using "default" (since the default router sends writes here)

And if we would then do something like this:

>>> t.pizza_set.remove(p)

the arguments sent to a m2m_changed handler would be:

Argument Value
sender Pizza.toppings.through (the intermediate m2m class)
instance t (the Topping instance being modified)
action "pre_remove" (followed by a separate signal with "post_remove")
reverse True (Pizza contains the ManyToManyField, so this call modifies the reverse relation)
model Pizza (the class of the objects removed from the Topping)
pk_set [p.id] (since only Pizza p was removed from the relation)
using "default" (since the default router sends writes here)
class_prepared
django.db.models.signals.class_prepared

モデルクラスの「準備が完了した」ときに呼び出されます。準備の完了とは、モデ ルの定義が読み込まれ、 Django のモデルシステムに組み込まれたことを示します。 Django はこのシグナルを内部的に使っています。通常は、サードパーティ製のアプ リケーションでは使いません。

引数は以下の通りです:

sender
準備の完了したモデルクラスです。

管理コマンド関連のシグナル

django-admin の送信するシグナルです。

post_syncdb
django.db.models.signals.post_syncdb

syncdb コマンドがアプリケーションをインストールした後、または flush コマンドによって送信されます。

このシグナルを待ち受けるハンドラは、 INSTALLED_APPS に登録されて いるいずれかのアプリケーションの management モジュール内に定義せねばな りません。それ以外の場所にハンドラを定義しても、 syncdb がそれらを ロードしないかもしれません。このシグナルのハンドラが行う変更がべき等である (つまりデータベースの変更を伴わない) ことは重要です。 syncdb コマンド の最中に実行されると flush 管理コマンドが失敗するかもしれない からです。

引数は以下の通りです:

sender
インストールされた models モジュールです。つまり、 syncdb"foo.bar.myapp" という名前のアプリケーショ ンをインストールすると、 sender には foo.bar.myapp.models モジュールが入ります。
app
sender と同じです。
created_models
syncdb が生成した全てのモデルクラスからなるリストです。
verbosity

manage.py がどれくらいの情報をスクリーンに表示しているかを示す値で す。詳しくは --verbosity` フラグを参照してください。

post_syncdb を待ち受けている関数は、この引数の値に従って、 スクリーンに表示するメッセージの量を調整してください。

interactive

interactiveTrue の場合、ユーザにコマンドプロンプトを提 示してもかまいません。 interactiveFalse であれば、シグ ナルを待ち受ける関数は、ユーザにプロンプトを表示してはなりません。

たとえば、 django.contrib.auth アプリケーションは、 interactiveTrue の時にしかスーパユーザを作成しません。

For example, yourapp/management/__init__.py could be written like:

from django.db.models.signals import post_syncdb
import yourapp.models

def my_callback(sender, **kwargs):
    # Your specific logic here
    pass

post_syncdb.connect(my_callback, sender=yourapp.models)

リクエスト/レスポンス関連のシグナル

コアフレームワークがリクエストを処理する際に送信するシグナルです。

request_started
django.core.signals.request_started

Djang が HTTP リクエストを送信する直前に送信されます。

引数は以下の通りです:

sender
リクエストを処理するハンドラクラス、たとえば django.core.handlers.wsgi.WsgiHandler です。
request_finished
django.core.signals.request_finished

Django が HTTP リクエストの処理を終了した直後に呼び出されます。

引数は以下の通りです:

sender
上と同じく、ハンドラクラスです。
got_request_exception
django.core.signals.got_request_exception

このシグナルは、 Django が HTTP リクエストの処理中に例外に遭遇したときに送 信されます。

引数は以下の通りです:

sender
上と同じく、ハンドラクラスです。
request
HttpRequest オブジェクトです。

テスト関連のシグナル

テストの実行中 にのみ送信されるシグナルです。

setting_changed
リリースノートを参照してください
django.test.signals.setting_changed

This signal is sent when the value of a setting is changed through the django.test.TestCase.setting() context manager or the django.test.utils.override_settings() decorator/context manager.

It’s actually sent twice: when the new value is applied (“setup”) and when the original value is restored (“teardown”).

Arguments sent with this signal:

sender
The settings handler.
setting
The name of the setting.
value
The value of the setting after the change. For settings that initially don’t exist, in the “teardown” phase, value is None.
template_rendered
django.test.signals.template_rendered

テストシステムがテンプレートをレンダするときに送信されます。このシグナルは、 通常の Django サーバの操作では送信されず、テスト中しか使えません。

引数は以下の通りです:

sender
これからレンダされる Template テンプレー トオブジェクトです。
template
sender と同じ値です。
context
テンプレートをレンダするときに渡される Context です。

Database Wrappers

Signals sent by the database wrapper when a database connection is initiated.

connection_created
django.db.backends.signals.connection_created
The connection argument was added

Sent when the database wrapper makes the initial connection to the database. This is particularly useful if you’d like to send any post connection commands to the SQL backend.

Arguments sent with this signal:

sender
The database wrapper class – i.e. django.db.backends.postgresql_psycopg2.DatabaseWrapper or django.db.backends.mysql.DatabaseWrapper, etc.
connection
The database connection that was opened. This can be used in a multiple-database configuration to differentiate connection signals from different databases.

テンプレートシステムリファレンス

revision-up-to:17812 (1.4)

Django のテンプレートエンジンは、アプリケーションの中でもユーザの目に触れる レイヤを定義する、強力ながらコンパクトな言語を提供しています。テンプレート 言語によって、アプリケーションとプレゼンテーションのロジックをきれいに分割 できます。テンプレートは HTML を理解していれば誰でも編集でき、 Python の知 識は必要ありません。

組み込みタグ/フィルタリファレンス

revision-up-to:11321 (1.1) unfinished

このドキュメントでは、 Django の組み込みテンプレートタグおよびフィルタにつ いて解説しています。 また、 自動生成ドキュメント を使えば、インストールされている組み込みタグ とカスタムタグのドキュメントを読めるのでお勧めです。

組み込みタグリファレンス
autoescape

自動エスケープ機能を制御します。このタグは引数に on または off を取 り、ブロック内の自動エスケープの有効・無効を決定します。

自動エスケープがオンの場合、変数の値は全て、最終的な文字列出力になる直前に HTML エスケープされます (他のフィルタは先に適用されます)。この動作は、 変数に escape フィルタを手動で適用した場合と同じです。

例外として、変数をテンプレートに挿入するコードや、 safe, escape と いったフィルタの適用によって、 “safe” マーク済みの変数はエスケープされませ ん。

block

子テンプレートでオーバライドできるブロックを定義します。 テンプレートの継承 を参照してください。

comment

{% comment %} から {% endcomment %} までの内容を全て無視します。

cycle
タグを処理するごとに、指定した文字列や変数を循環して返します。

ループの中では、ループごとに指定した文字列や変数を循環して返します:

{% for o in some_list %}
    <tr class="{% cycle 'row1' 'row2' rowvar %}">
        ...
    </tr>
{% endfor %}

You can use variables, too. For example, if you have two template variables, rowvalue1 and rowvalue2, you can cycle between their values like this:

{% for o in some_list %}
    <tr class="{% cycle rowvalue1 rowvalue2 %}">
        ...
    </tr>
{% endfor %}

Yes, you can mix variables and strings:

{% for o in some_list %}
    <tr class="{% cycle 'row1' rowvalue2 'row3' %}">
        ...
    </tr>
{% endfor %}

In some cases you might want to refer to the next value of a cycle from outside of a loop. To do this, just give the {% cycle %} tag a name, using “as”, like this:

{% cycle 'row1' 'row2' as rowcolors %}

From then on, you can insert the current value of the cycle wherever you’d like in your template:

<tr class="{% cycle rowcolors %}">...</tr>
<tr class="{% cycle rowcolors %}">...</tr>

You can use any number of values in a {% cycle %} tag, separated by spaces. Values enclosed in single (') or double quotes (") are treated as string literals, while values without quotes are treated as template variables.

Note that the variables included in the cycle will not be escaped. This is because template tags do not escape their content. If you want to escape the variables in the cycle, you must do so explicitly:

{% filter force_escape %}
    {% cycle var1 var2 var3 %}
{% endfilter %}

For backwards compatibility, the {% cycle %} tag supports the much inferior old syntax from previous Django versions. You shouldn’t use this in any new projects, but for the sake of the people who are still using it, here’s what it looks like:

{% cycle row1,row2,row3 %}

In this syntax, each value gets interpreted as a literal string, and there’s no way to specify variable values. Or literal commas. Or spaces. Did we mention you shouldn’t use this syntax in any new projects?

debug

現在のコンテキストや import されたモジュールなどを含んだデバッグ情報ひと揃 いを出力します。

extends

このテンプレートが親テンプレートに対する拡張であることを指示します。

このタグには 2 種類の使い方があります:

  • {% extends "base.html" %} (引用符つき) のような場合、リテラル値 "base.html" を親テンプレートの名前として使います。
  • {% extends variable %} のようにすると、 variable の値を親テンプ レートの名前として使います。 variable の値が文字列の場合、 Django はその文字列を親テンプレートの名前として使います。値が Template オ ブジェクトの場合、Django はそのオブジェクトを親テンプレートにします。

詳しくは テンプレートの継承 を参照してください。

filter

タグのコンテンツを変数フィルタ (variable filter) を使ってフィルタします。

フィルタはパイプでつないで連鎖でき、引数をもたせることができます。

使用例:

{% filter force_escape|lower %}
    This text will be HTML-escaped, and will appear in all lowercase.
{% endfilter %}
firstof

タグに渡された変数のうち、False でない最初の変数の値を出力します。全ての変 数が False であった場合、何も出力しません。

使用例:

{% firstof var1 var2 var3 %}

上は、以下のテンプレートと等価です:

{% if var1 %}
    {{ var1 }}
{% else %}{% if var2 %}
    {{ var2 }}
{% else %}{% if var3 %}
    {{ var3 }}
{% endif %}{% endif %}{% endif %}

また、全ての変数が False の場合のフォールバック値としてリテラル文字列を指定 できます:

{% firstof var1 var2 var3 "fallback value" %}

Note that the variables included in the firstof tag will not be escaped. This is because template tags do not escape their content. If you want to escape the variables in the firstof tag, you must do so explicitly:

{% filter force_escape %}
    {% firstof var1 var2 var3 "fallback value" %}
{% endfilter %}
for

アレイの各要素に渡ってループします。例えば、アスリート (athlete) のリストを athlete_list で渡して表示するには:

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>

{% for obj in list reversed %} のようにすると、リストに対して逆順のルー プを実行できます。

リストのリストにわたってループ処理を行う場合、各サブリストをアンパックして、 個別に名前を割り当てられます。例えば、座標 (x, y) のリストが入った points というコンテキスト変数があり、各座標を出力したい場合には以下のよ うにします:

{% for x, y in points %}
    座標 {{ x }},{{ y }} が登録されています。
{% endfor %}

この方法は、辞書の各要素にアクセスしたい場合にも便利です。例えば、コンテキ スト変数 data に辞書が入っている場合。以下のようにすれば辞書内のキーと 値を表示できます:

{% for key, value in data.items %}
    {{ key }}: {{ value }}
{% endfor %}

for ループは、ループの各回ごとに使える変数を設定します:

変数名 説明
forloop.counter 現在のループ回数番号 (1 から数えたもの)
forloop.counter0 現在のループ回数番号 (0 から数えたもの)
forloop.revcounter 末尾から数えたループ回数番号 (1 から数えたもの)
forloop.revcounter0 末尾から数えたループ回数番号 (0 から数えたもの)
forloop.first 最初のループであれば True になります
forloop.last 最後のループであれば True になります
forloop.parentloop 入れ子のループの場合、一つ上のループを表します
for ... empty

The for tag can take an optional {% empty %} clause that will be displayed if the given array is empty or could not be found:

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% empty %}
    <li>Sorry, no athlete in this list!</li>
{% endfor %}
<ul>

The above is equivalent to – but shorter, cleaner, and possibly faster than – the following:

<ul>
  {% if athlete_list %}
    {% for athlete in athlete_list %}
      <li>{{ athlete.name }}</li>
    {% endfor %}
  {% else %}
    <li>Sorry, no athletes in this list.</li>
  {% endif %}
</ul>
if

変数を評価して、値が「真」 (値が存在して、空の配列でなく、ブール値が偽でな い) の場合、ブロック内のコンテンツを出力します:

{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% else %}
    No athletes.
{% endif %}

上の例では、 athlete_list が空でなければ、アスリートの人数を {{ athlete_list|length }} で表示します。

例にもあるように、 if タグにはオプションの {% else %} 節があり、テ ストに失敗した場合に表示されるコンテンツを定義できます。

andor で複数の変数をチェックしたり、 not で否をとったりでき ます:

{% if athlete_list and coach_list %}
    Both athletes and coaches are available.
{% endif %}

{% if not athlete_list %}
    There are no athletes.
{% endif %}

{% if athlete_list or coach_list %}
    There are some athletes or some coaches.
{% endif %}

{% if not athlete_list or coach_list %}
    There are no athletes or there are some coaches (OK, so
    writing English translations of boolean logic sounds
    stupid; it's not our fault).
{% endif %}

{% if athlete_list and not coach_list %}
    There are some athletes and absolutely no coaches.
{% endif %}

{% if athlete_list and not coach_list %}
    There are some athletes and absolutely no coaches.
{% endif %}

andor 節を同じタグの中に入れると、ロジックの優先順位があいまい になるため、 同じ if タグには入れられません。例えば、以下のテンプレート は無効です:

{% if athlete_list and coach_list or cheerleader_list %}

and タグと or タグを使ったロジックを行いたければ、以下の例のように if タグを入れ子にしてください:

{% if athlete_list %}
    {% if coach_list or cheerleader_list %}
        We have athletes, and either coaches or cheerleaders!
    {% endif %}
{% endif %}

同じ論理記号はいくつでも並べられます。ただし、同じ演算子を使う場合に限りま す。例えば、以下は有効なテンプレートです:

{% if athlete_list or coach_list or parent_list or teacher_list %}
ifchanged

ブロック内のコンテンツが直前のループと違う値になるかどうか調べます。

ifchanged ブロックタグはループの中で使います。このタグには二通りの使い 方があります。

  1. ブロック内のレンダリング対象コンテンツを直前のループでの状態と比較して、 内容が変化している場合にのみコンテンツを表示する場合です。たとえば、日付 のリストを表示するときに、月が変わったときだけ月名を表示したければ以下の ようにします:

    <h1>Archive for {{ year }}</h1>
    
    {% for date in days %}
        {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
        <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
    {% endfor %}
    
  2. タグに引数を指定すると、変数が変化したかどうかを調べます。例えば、以下の 例では日付が変化したときに日付を表示し、日付と時刻が同時に変化したときの み時刻も表示します:

    {% for date in days %}
        {% ifchanged date.date %} {{ date.date }} {% endifchanged %}
        {% ifchanged date.hour date.date %}
            {{ date.hour }}
        {% endifchanged %}
    {% endfor %}
    

The ifchanged tag can also take an optional {% else %} clause that will be displayed if the value has not changed:

{% for match in matches %}
    <div style="background-color:
        {% ifchanged match.ballot_id %}
            {% cycle "red" "blue" %}
        {% else %}
            grey
        {% endifchanged %}
    ">{{ match }}</div>
{% endfor %}
ifequal

2 つの引数が互いに等しい場合にブロックの内容を出力します。

例:

{% ifequal user.id comment.user_id %}
    ...
{% endifequal %}

{% if %} タグと同様、オプションで {% else %} 節を使えます。

引数はハードコードされた文字列でもよいので、以下のような表現は有効です:

{% ifequal user.username "adrian" %}
    ...
{% endifequal %}

引数と比較できるのは、テンプレート変数または文字列だけです。 TrueFalse のような、 Python オブジェクトに対する等価比較は行えません。 TrueFalse との比較を行いたければ if を使ってください。

ifnotequal

2 つの引数が互いに等しくない場合にブロックの内容を出力します。

include

テンプレートをロードして、現在のコンテキストを使ってレンダリングします。あ るテンプレートに別のテンプレートを取り込む (“include”) 方法の一つです。

テンプレート名はハードコードされた (引用符で囲った) 文字列でもよく、引用符 は一重でも二重でもかまいません。

以下の例では、 "foo/bar.html" という名前のテンプレートを取り込みます:

{% include "foo/bar.html" %}

次の例では、 変数 template_name に入っている名前のテンプレートを取り込 みます:

{% include template_name %}

取り込まれたテンプレートは、取り込んだ側で使われているコンテキストの下でレ ンダリングされます。下の例では "Hello, John" を出力します:

  • コンテキスト: 変数 person"john" に設定

  • テンプレート:

    {% include "name_snippet.html" %}
    
  • name_snippet.html テンプレート:

    Hello, {{ person }}
    

{% ssi %} も参照してください。

load

カスタムのテンプレートタグリストを読み込みます。

詳しくは カスタムタグとカスタムフィルタのライブラリ を参照してください。

now

指定したフォーマット文字列にしたがって現在の日時を表示します。

フォーマットは PHP の date() 関数 (http://php.net/date) と同じで、いく つかの点で拡張されています。

利用できるフォーマットを示します:

フォーマット文字 説明 出力例
a 'a.m.' または 'p.m.' (Associated Press に合わせるため、’.’ が入っている点 が PHP と違います)。 'a.m.'
A 'AM' または 'PM' です。 'AM'
b 3 文字の小文字で表した月名です。 'jan'
B 実装されていません。  
d 月の中の日。 2 桁のゼロ詰めです。 '01' から '31'
D 週の中の日。 3 文字のテキスト形式です。 'Fri'
f 12 時間表記の時と分。ただし、ゼロ分の 場合には表示しません。独自の拡張です。 '1', '1:30'
F 月名を長いテキスト形式で表したものです。 'January'
g 12 時間表記の時。ゼロ詰めはしません。 '1' から '12'
G 24 時間表記の時。ゼロ詰めはしません。 '0' から '23'
h 12 時間表記の時です。 '01' から '12'
H 24 時間表記の時です。 '00' から '23'
i 分です。 '00' から '59'
I 実装されていません。  
j 月の中の日。ゼロ詰めしません。 '1' から '31'
l 週の中の曜日。長いテキスト形式です。 'Friday'
L 閏年かどうかを表すブール値です。 True または False
m 月です。2 桁でゼロ詰めしたものです。 '01' から '12'
M 月です。3 文字のテキスト形式です。 'Jan'
n 月です。ゼロ詰めしません。 '1' から '12'
N Associated Press スタイルの月の省略表記 です。独自の拡張です。 'Jan.', 'Feb.', 'March', 'May'
O グリニッジ標準時からの時差です。 '+0200'
P 時刻です。12 時間表記の時、分、 そして ‘a.m.’/’p.m.’ です。分がゼロの 場合には省略され、必要に応じて ‘midnight’ または ‘noon’ になります。 独自の拡張です。 '1 a.m.', '1:30 p.m.', 'midnight', 'noon', '12:30 p.m.'
r RFC 2822に従ったフォーマットの日時です。 'Thu, 21 Dec 2000 16:01:07 +0200'
s 秒です。 2 桁のゼロ詰めです。 '00' から '59'
S 月の中の日につける 2 文字の序数接尾辞 です。 'st', 'nd', 'rd' or 'th'
t 月の日数です。 28 から 31
T 計算機のタイムゾーン設定です。 'EST', 'MDT'
U 実装されていません。  
w 週の中の曜日です。ゼロ詰めしません。 '0' (Sunday) to '6' (Saturday)
W ISO-8601 に従った年の中の週番号です。 週は月曜日から始まります。 1, 53
y 2 桁の年です。 '99'
Y 4 桁の年です。 '1999'
z 年の中の日 0 から 365
Z タイムゾーンオフセットを秒であらわした ものです。UTC よりも西側のタイムゾーン値 は全て負の値になり、東側の値は常に正に なります。 -43200 から 43200

例:

It is {% now "jS F Y H:i" %}

フォーマット文字列中で普通の文字列を使いたければ、バックスラッシュでエスケー プできます。下の例では、”f” が時刻を表すフォーマット指定子として解釈されな いようにエスケープしています。 “o” はフォーマット指定子ではないのでエスケー プしていません:

It is the {% now "jS o\f F" %}

このテンプレートをレンダすると “It is the 4th of September” になります。

regroup

オブジェクトのリストから、属性値によって同種のオブジェクトをまとめます。

この難解なタグを説明するには、例を使うのが一番でしょう: 仮に、複数人の情報 の入った people というリストがあり、各人の情報は first_name, last_name, および gender といったキーを持つ辞書で表されているとしま しょう:

people = [
    {'first_name': 'George', 'last_name': 'Bush', 'gender': 'Male'},
    {'first_name': 'Bill', 'last_name': 'Clinton', 'gender': 'Male'},
    {'first_name': 'Margaret', 'last_name': 'Thatcher', 'gender': 'Female'},
    {'first_name': 'Condoleezza', 'last_name': 'Rice', 'gender': 'Female'},
    {'first_name': 'Pat', 'last_name': 'Smith', 'gender': 'Unknown'},
]

このデータを、以下のように性別ごとに階層化して表示したいとします:

* Male:
    * George Bush
    * Bill Clinton
* Female:
    * Margaret Thatcher
    * Condoleezza Rice
* Unknown:
    * Pat Smith

{% regroup %} タグを使うと、 people を性別ごとにグループ化できます。 以下のようなテンプレートを使って実現します:

{% regroup people by gender as gender_list %}
<ul>
{% for gender in gender_list  %}
    <li>{{ gender.grouper }}
    <ul>
        {% for item in gender.list %}
        <li>{{ item.first_name }} {{ item.last_name }}</li>
        {% endfor %}
    </ul>
    </li>
{% endfor %}
</ul>

例を順番に見てゆきましょう。 {% regroup %} は 3 つの引数をとります。最 初は再グループ化 (regroup) したいリスト、二つめはグループ化に使う属性やキー の名前、そして最後は再グループ化後のリストにつける名前です。ここでは、 gender キーを使って people を再グループ化し、 gender_list とい う名前で参照できるようにしています。

{% regroup %}グループオブジェクト のリストを生成して返します (この場合は gender_list です)。グループオブジェクトには二つの属性があり ます:

  • grouper – グループ化している項目 (例えば “Male” や “Female” といっ た文字列) です。
  • list – グループ内の全ての要素からなるリスト (例えば、 gender='Male' の人全員からなるリスト) です。

{% regroup %} は入力をソートしないので注意してください! 上の例では、 リスト people はあらかじめ gender でソート済みという前提に立ってい ます。 peoplegender の順に並んで いない 場合、再グループは何 も考えずに一つの性別のグループを複数つくってしまいます。例えば、 people が以下のように ('Male' がリスト内でまとまっていない状態に) なっていたと しましょう:

people = [
    {'first_name': 'Bill', 'last_name': 'Clinton', 'gender': 'Male'},
    {'first_name': 'Pat', 'last_name': 'Smith', 'gender': 'Unknown'},
    {'first_name': 'Margaret', 'last_name': 'Thatcher', 'gender': 'Female'},
    {'first_name': 'George', 'last_name': 'Bush', 'gender': 'Male'},
    {'first_name': 'Condoleezza', 'last_name': 'Rice', 'gender': 'Female'},
]

この people を入力に使うと、上の {% regroup %} のテンプレートコード 例は以下のような出力を生成します:

* Male:
    * Bill Clinton
* Unknown:
    * Pat Smith
* Female:
    * Margaret Thatcher
* Male:
    * George Bush
* Female:
    * Condoleezza Rice

こうした落し穴を解決したければ、ビューコード内であらかじめデータを表示した い順番に並べておくのが最も簡単でしょう。

データが辞書の列の場合には、もう一つの解決策として、テンプレートの中で dictsort フィルタを使ってデータを並べ変えられます:

{% regroup people|dictsort:"gender" by gender as gender_list %}
spaceless

ブロック内の HTML タグ間にある空白文字を除去します。タブ文字や改行も含みま す。

使用例:

{% spaceless %}
    <p>
        <a href="foo/">Foo</a>
    </p>
{% endspaceless %}

上の例は下のような HTML になります:

<p><a href="foo/">Foo</a></p>
タグ間の 空白だけが正規化されます – タグとテキストの間のスペースは正規化

しません。下の例では、 Hello の周りの空白をはぎとりません:

{% spaceless %}
    <strong>
        Hello
    </strong>
{% endspaceless %}
ssi

指定したファイルの内容をページ内に取り込みます。

“inlcude” タグと同様、 {% ssi %} は別のファイルの内容を取り込みます。引 数は絶対パスで指定せねばなりません:

{% ssi /home/html/ljworld.com/includes/right_generic.html %}

オプションの “parsed” パラメタを指定すると、取り込まれたファイルを現在のコ ンテキストのテンプレートコードとして評価します:

{% ssi /home/html/ljworld.com/includes/right_generic.html parsed %}

{% ssi %} を使う場合には、セキュリティの観点から、 Django の設定に ALLOWED_INCLUDE_ROOTS を定義しておく必要があるでしょう。

{% include %} も参照してください。

templatetag

テンプレートタグの構成に使われる文字自体を出力します。

Django のテンプレートには「エスケープ」の概念がないので、テンプレートタグの 構成に使われている要素を出力したければ {% templatetag %} タグを使わねば なりません。

引数にはどの要素出力するかを指定します:

Argument Outputs
openblock {%
closeblock %}
openvariable {{
closevariable }}
openbrace {
closebrace }
opencomment {#
closecomment #}
url

ビュー関数とオプションのパラメタを指定すると、絶対 URL (ドメイン名のない URL) を返します。これによって、テンプレートに URL をハードコードするような DRY 則の侵犯を避けられます:

{% url path.to.some_view arg1,arg2,name1=value1 %}

第一引数はビュー関数へのパスで、 package.module.function のよう な形式で指定します。それ以降の引数はオプションで、カンマで区切って指定しま す。引数はそれぞれビューの固定引数やキーワード引数になります。 URLconf に指 定されている引数全てを指定せねばなりません。

例えば、 app_views.client という名前のビューがあり、クライアントの ID を引数に取るとしましょう (client()app_views.py で定義されている メソッドです)。 URLconf は以下のようになるはずです:

('^client/(\d+)/$', 'app_views.client')

あるアプリケーションの URLconf が、プロジェクトの URLconf に以下のような形 で include されていたとします:

('^clients/', include('project_name.app_name.urls'))

テンプレート内では、以下のようにしてビューへのリンクを生成できます:

{% url app_views.client client.id %}

結果的に、テンプレートは /clients/client/123/ のような文字列を生成しま す。

名前つき URL パターン を使っている場合、 url タグにはビューのパス名の代わりにパターン名を指定できます。

逆変換しようとしている URL が存在しない場合、 NoReverseMatch 例外を 送出するため、エラーページが表示されます。

URL を表示せず、取り出したいだけなら、以下のような形式で呼び出せます:

{% url path.to.view arg, arg2 as the_url %}

<a href="{{ the_url }}">I'm linking to {{ the_url }}</a>

{% url ... as var %} の形式は、 URL からビューを解決できなくてもエラー を送出 しません 。従って、ビューへのリンクは以下のようにも書けます:

{% url path.to.view as the_url %}
{% if the_url %}
  <a href="{{ the_url }}">Link to optional stuff</a>
{% endif %}

If you’d like to retrieve a namespaced URL, specify the fully qualified name:

{% url myapp:view-name %}

This will follow the normal namespaced URL resolution strategy, including using any hints provided by the context as to the current application.

widthratio

バーチャートなどを生成する場合のために、指定した値と最大値との比を計算し、 定数に掛けた値を返します。

例えば:

<img src="bar.gif" height="10"
 width="{% widthratio this_value max_value 100 %}" />

のようにすると、 this_value が 175 で max_value が 200 の場合には、 (175/200 = .875; .875 * 100 = 87.5 で、88 に丸めた結果) 画像の幅は 88 ピク セルになります。

with

複雑な表記の変数の値をキャッシュします。また、簡単な名前で参照できるように します。呼出しコストの高いメソッド (例えばデータベースを操作するようなメソッ ド) に何度もアクセスする際に便利です。

以下に例を示します:

{% with business.employees.count as total %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

値を組み込んだ変数 (上の例でいえば total) は {% with %}{% endwith %} タグの間でだけ使えます。

組み込みフィルタリファレンス
add

入力値に対して引数の値を加算します。

使用例:

{{ value|add:"2" }}

value4 なら、出力は 6 になるでしょう。

addslashes

入力値のクオートの前にスラッシュを追加します。CSV などの文字列をエスケープ する際に便利です。

capfirst

入力値の先頭の文字を大文字に変換します。

center

入力値を引数に指定された幅のフィールド内に中央寄せします。

cut

入力値の中から引数に指定した値を全て除去します。

使用例:

{{ value|cut:" "}}

value"String with spaces" なら、出力は "Stringwithspaces" に なるでしょう。

date

引数に指定した書式で日付をフォーマットします。 (now タグと同じです)

使用例:

{{ value|date:"D d M Y" }}

valuedatetime オブジェクト (例えば、 datetime.datetime.now() の戻り値) ならば、 出力は文字列 'Wed 09 Jan 2008' になります。

When used without a format string:

{{ value|date }}

...the formatting string defined in the DATE_FORMAT setting will be used.

default

入力の評価値が False の場合、引数に指定したデフォルト値を使います。そうで なければ、入力値を使います。

使用例:

{{ value|default:"nothing" }}

value"" (空文字列)ならば、出力は nothing になります。

default_if_none

値が None の場合、かつその場合のみ、引数に指定したデフォルト値を使いま す。そうでなければ、入力値を使います。

空文字列を入力した場合には、デフォルト値を使わ ない ので注意してくださ い。空文字列をフォールバックしたければ default フィルタを使ってください。

使用例:

{{ value|default_if_none:"nothing" }}

valueNone ならば、出力は文字列 "nothing" になります。

dictsort

辞書のリストを入力に取り、引数に指定したキーでリストをソートして返します。

使用例:

{{ value|dictsort:"name" }}

value が以下のようだったとします:

[
    {'name': 'zed', 'age': 19},
    {'name': 'amy', 'age': 22},
    {'name': 'joe', 'age': 31},
]

出力は以下のようになるでしょう。:

[
    {'name': 'amy', 'age': 22},
    {'name': 'joe', 'age': 31},
    {'name': 'zed', 'age': 19},
]
dictsortreversed

辞書のリストを入力に取り、引数に指定したキーでリストを逆順にソートして返し ます。上のフィルタと全く同じ処理をしますが、返す値は逆順です。

divisibleby

値を引数で除算できる場合に True を返します。

使用例:

{{ value|divisibleby:"3" }}

value21 なら、出力は True になります。

escape

入力文字中の HTML 特有の文字をエスケープします。具体的には、以下のような置 換を行います:

  • <"&lt;" に変換されます。
  • >"&gt;" に変換されます。
  • "'" (クオート) は '&#39;' に変換されます。
  • '"' (二重クオート) は '&quot;' に変換されます。
  • "&""&amp;" に変換されます。

エスケープは最終的な文字列出力を生成する時に適用されます。従って、フィルタ を連鎖している場合、連鎖のどこにフィルタが置かれていても、フィルタの最後の 段階でエスケープ処理が行われます。エスケープを即座に適用したければ、 force_escape フィルタを使ってください。

すでに自動エスケープが施された変数に escape を適用しても、結果的には一 度しかエスケープを行いません。従って、自動エスケープ環境で escape を呼び出しても問題はありません。意図的に複数回エスケープを施したければ、 force_escape フィルタを使ってください。

自動エスケープの導入によって、このフィルタの挙動は少し変更されました。 フィルタによる置き換えは、他の (前後のフィルタを含め)全てのフィルタを適 用した後に一度だけ行われます。
escapejs

JavaScript の文字列リテラルとして扱うために文字エスケープを行います。エスケー プ結果は、 HTML としては安全 ではありません が、JavaScrpt/JSON を生成する テンプレートの出力が構文エラーを引き起こすのを防げます。

filesizeformat

ファイルサイズを「目に優しい (human-readable)」表現 ('13 KB', '4.1 MB', '102 bytes' など) に変換します。

使用例:

{{ value|filesizeformat }}

value が 123456789 なら、出力は 117.7 MB になります。

first

リスト中の最初の要素を返します。

使用例:

{{ value|first }}

value がリスト ['a', 'b', 'c'] なら、出力は 'a' になります。

fix_ampersands

アンパーサンド (“&”) を &amp; エンティティで置き換えます。

使用例:

{{ value|fix_ampersands }}

valueTom & Jerry なら、出力は Tom &amp; Jerry になります。

floatformat

引数を指定せずに使うと、小数部がある場合に限り、浮動小数点数を小数点以下ひ と桁でまるめます。例えば:

value テンプレート 出力
34.23234 {{ value|floatformat }} 34.2
34.00000 {{ value|floatformat }} 34
34.26000 {{ value|floatformat }} 34.3

整数の引数を指定すると、 floatformat は小数部を指定の桁数で丸めます。例 えば:

value テンプレート 出力
34.23234 {{ value|floatformat:3 }} 34.232
34.00000 {{ value|floatformat:3 }} 34.000
34.26000 {{ value|floatformat:3 }} 34.260

floatformat の引数に負の数を指定した場合、小数部がある場合に限り、小数 部を指定の桁数で丸めます。例えば:

value テンプレート 出力
34.23234 {{ value|floatformat:"-3" }} 34.232
34.00000 {{ value|floatformat:"-3" }} 34
34.26000 {{ value|floatformat:"-3" }} 34.260

従って、引数なしの floatformat-1 を引数に指定した場合と同じにな ります。

force_escape

文字列に HTML エスケープを適用します。 (詳しくは escape フィルタを参照 してください)。フィルタは 即座に 適用され、新たなエスケープ済みの文字列を 返します。このタグが有用なケースは稀で、エスケープ済みの結果に対して他のフィ ルタを適用したいような、複数回エスケープが必要な場合に使われるにすぎません。 通常は escape フィルタをつかうことになるでしょう。

get_digit

入力が整数の場合、引数に指定した桁の数字を返します。 1 は右はじの桁、2 は右 から 2 つ目の桁、といった具合に指定します。入力が整数でない場合には、入力値 をそのまま返します。

使用例:

{{ value|get_digit:"2" }}

value123456789 なら、出力は 8 になります。

iriencode

IRI (国際化リソース識別子 Internationalized Resource Identifier) を URL 埋め込みに適した文字列に変換します。非 ASCII 文字列を URL に埋め込む 場合に必要なフィルタです。

urlencode フィルタを通した文字列をこのフィルタに通しても問題はありませ ん。

join

Python の str.join(list) と同じく、リストを文字列でつなぎます。

使用例:

{{ value|join:" // " }}

value がリスト ['a', 'b', 'c'] なら、出力は文字列 "a // b // c" に なります。

last

リストの末尾の要素を返します。

使用例:

{{ value|last }}

value がリスト ['a', 'b', 'c', 'd'] なら、出力は文字列 "d" になり ます。

length

入力値の長さを返します。文字列とリストいずれにも作用します。

使用例:

{{ value|length }}

value['a', 'b', 'c', 'd'] なら、出力は 4 になります。

length_is

入力値の長さと引数が等しければ True を返し、そうでなければ False を 返します。

使用例:

{{ value|length_is:"4" }}

value['a', 'b', 'c', 'd'] なら、出力は True になります。

linebreaks

プレーンテキストの改行を適切な HTML タグに変換します。 改行 1 つは HTML 改行 (<br />) タグ、改行と空行はパラグラフ 改行 (<p>) に変換します。

使用例:

{{ value|linebreaks }}

valueJoel\nis a slug なら、出力は <p>Joel<br>is a slug</p> になります。

linebreaksbr

プレーンテキストの改行を HTML の改行 (<br />) タグに変換します。

linenumbers

テキストを行番号付きで表示します。

ljust

入力値を指定幅のフィールド内に左詰めします。

引数: フィールドの幅

lower

文字列を全て小文字に変換します。

使用例:

{{ value|lower }}

valueStill MAD At Yoko なら、出力は still mad at yoko にな ります。

make_list

入力値をリストに変換します。整数の場合には各桁の数字からなるリストに、文字 列の場合は各文字からなるリストに変換します。

使用例:

{{ value|make_list }}

value が文字列 "Joel" なら、出力はリスト [u'J', u'o', u'e', u'l'] です。 value123 なら、出力はリスト [1, 2, 3] です。

phone2numeric

電話番号 (文字を含む場合もあります) を数値だけの番号に変換します。例えば、 '800-COLLECT''800-2655328' になります。

入力値は正しい電話番号でなくてもかまいません。このフィルタはどんな文字列で も変換します。

pluralize

値が 1 でない場合に、複数形を表す接尾辞を付けます。デフォルトでは、接尾辞は 's' です。

例:

You have {{ num_messages }} message{{ num_messages|pluralize }}.

's' 以外の接尾辞が必要な場合、フィルタのパラメタに指定できます。

例:

You have {{ num_walruses }} walrus{{ num_walrus|pluralize:"es" }}.

単なる接尾辞だけで複数形化できない場合、単数形と複数形の接尾辞の両方をコン マで区切って指定できます。

例:

You have {{ num_cherries }} cherr{{ num_cherries|pluralize:"y,ies" }}.
pprint

pprint.pprint のラッパです – 単なるデバッグ用にすぎません。

random

与えられたリストからランダムな要素を返します。

使用例:

{{ value|random }}

value がリスト ['a', 'b', 'c', 'd'] なら、出力は "b" かもしれません。

removetags

入力から引数に指定された [X]HTML タグを除去します。タグはスペースで区切って 指定します。

使用例:

{{ value|removetags:"b span"|safe }}

value"<b>Joel</b> <button>is</button> a <span>slug</span>" なら、 出力は "Joel <button>is</button> a slug" になります。

rjust

指定幅のフィールドに右詰めします。

引数: フィールドの幅

safe

文字列に対して、さらなるエスケープが必要でないことをマークするのに使います。 autoescaping がオフの場合、このフィルタは何もしません。

safeseq

Applies the safe filter to each element of a sequence. Useful in conjunction with other filters that operate on sequences, such as join. For example:

{{ some_list|safeseq|join:", " }}

You couldn’t use the safe filter directly in this case, as it would first convert the variable into a string, rather than working with the individual elements of the sequence.

slice

リストに対するスライスを返します。

Python におけるリストのスライスと同じ構文を使います。スライスについて学びた ければ、 http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice を読んで下さい。

例:

{{ some_list|slice:":2" }}
slugify

入力を小文字に変換し、語でない (英数字またはアンダースコアでない) 文字を除 去し、スペースをハイフンに変換します。また、先頭と末尾の空白をはぎとります。

使用例:

{{ value|slugify }}

value"Joel is a slug" なら、出力は "joel-is-a-slug" になり ます。

stringformat

引数に指定されたフォーマット指示子に従って変数をフォーマットします。フォー マット指示子は Python のフォーマット指示構文と同じですが、先頭の “%” は必要 ありません。

Python の文字列フォーマットについては http://www.python.jp/doc/release/lib/typesseq-strings.html を参照してくださ い。

使用例:

{{ value|stringformat:"s" }}

value"Joel is a slug" なら、出力は "Joel is a slug" になり ます。

striptags

[X]HTML タグを全てはぎとります。

使用例:

{{ value|striptags }}

value"<b>Joel</b> <button>is</button> a <span>slug</span>" なら、 出力は "Joel is a slug" になります。

time

時刻を指定の書式でフォーマットします (now タグと同じです)。 time フィルタの引数は、時刻に関するフォーマット文字しか受け付けません (理由は言うまでもありませんよね)。日付のフォーマットを行いたければ date フィルタを使ってください。

使用例:

{{ value|time:"H:i" }}

valuedatetime.datetime.now() と同等な値なら、出力は文字列 "01:23" なります。

When used without a format string:

{{ value|time }}

...the formatting string defined in the TIME_FORMAT setting will be used.

timesince

日付を経過時間の形式にフォーマットします (例えば、 “4 days, 6 hours”) 。

オプションの引数として、 比較対象として使う時刻をとります (引数を省略すると 現在時刻 を使います)。例えば、 blog_date1 June 2006 を表す日 付オブジェクトで、 comment_date08:00 on 1 June 2006 を表す日時 オブジェクトの場合、 {{ blog_date|timesince:comment_date }} は “8 hours” を返します。

Comparing offset-naive and offset-aware datetimes will return an empty string.

最小の単位は分で、比較対象の時刻より以前の時刻に対しては “0 minutes” を返します。

timeuntil

timesince に似ていますが、現在時刻から指定の日付または日時までの時刻を 計算します。

例えば、現在の日付が 1 June 2006 で、 conference_date29 June 2006 の場合、 {{ conference_date|timeuntil }} は “4 weeks” を返します。

オプションの引数として、 (現在時刻 の代わりに) 比較対象として使う時刻をと ります。 例えば、 from_date22 June 2006 の場合、 {{ conference_date|timeuntil:from_date }} は “1 week” を返します。

オフセットつきの時刻とオフセットなしの時刻を比較すると、空の文字列を返しま す。

最小の単位は分で、比較対象の時刻より以前の時刻に対しては “0 minutes” を返します。

title

文字列をタイトルケースに変換します。

truncatewords

文字列を指定語数以下になるように切り詰めます。

引数: 文字列を切り詰めるまでの語数

使用例:

{{ value|truncatewords:2 }}

value"Joel is a slug" なら、出力は "Joel is ..." になります。

truncatewords_html

truncatewords に似ていますが、 HTML タグを正しく扱えます。切り詰めを行 う時点で閉じていないタグがあれば、切り詰めた文字の直後に全て閉じます。

このタグの処理は truncatewords よりもやや非効率なので、 HTML テキストを 渡す場合にだけ使うようにしてください。

unordered_list

再帰的に入れ子になったリストを入力にとり、 HTML の無番号リスト (UL, unordered list) に変換します。ただし、最も外側の <ul> タグは表示しませ ん。

unordered_list の引数の形式は、より分かりやすく変更されました。

リストは適切な形式になっているものとみなします。例えば、 var['States', ['Kansas', ['Lawrence', 'Topeka'], 'Illinois']] であれば、 {{ var|unordered_list }} は以下のようになります:

<li>States
<ul>
        <li>Kansas
        <ul>
                <li>Lawrence</li>
                <li>Topeka</li>
        </ul>
        </li>
        <li>Illinois</li>
</ul>
</li>

ノート: 以前の、より杓子定規で冗長な形式、 ['States', [['Kansas', [['Lawrence', []], ['Topeka', []]]], ['Illinois',[]]]] も継続してサポートしています。

upper

入力値をすべて大文字に変換します。

使用例:

{{ value|upper }}

value"Joel is a slug" なら、出力は "JOEL IS A SLUG" になり ます。

urlencode

入力値を URL で使えるようにエスケープします。

urlize

平文で書かれた URL をクリック可能なリンクに変換します。

HTML マークアップの入ったテキストに urlize を適用すると、予想通りの出力 を得られない場合があるので注意してください。このフィルタは 素の テキスト に対してだけ使ってください。

使用例:

{{ value|urlize }}

value"Check out www.djangoproject.com" なら、出力は "Check out <a href="http://www.djangoproject.com">www.djangoproject.com</a>" になります。

urlizetrunc

URL をクリック可能なリンクに変換します。このとき、指定の文字数以上の URL を 切り詰めます。

urlize と同様、このフィルタは 素の テキストに対してだけ使ってください。

引数: URL を切り詰める長さ

使用例:

{{ value|urlizetrunc:15 }}

value"Check out www.djangoproject.com" なら、出力は 'Check out <a href="http://www.djangoproject.com">www.djangopr...</a>' になります。

wordcount

語数を返します。

wordwrap

指定した行幅で語列をラップします。

引数: テキストをラップするまでの語数

使用例:

{{ value|wordwrap:5 }}

valueJoel is a slug なら、出力はこうなります:

Joel
is a
slug
yesno

入力値 (真、偽、オプションで None) に応じて、引数に指定した文字のいずれかを 返します。

入力値 引数 出力
True "yeah,no,maybe" yeah
False "yeah,no,maybe" no
None "yeah,no,maybe" maybe
None "yeah,no" "no" (None に対応する値が ない場合は False 扱いになります)
その他のタグとフィルタライブラリ

Django には他にも二つのテンプレートタグライブラリがついてきます。これらのラ イブラリは INSTALLED_APPS 設定で明示的に有効化した上で、 {% load %} タグを使ってテンプレート上にロードせねばなりません。

django.contrib.humanize

データを「ヒトにやさしい」表現にする上で便利な Django テンプレートフィルタ です。 django.contrib.humanize を参照してください。

django.contrib.markup

以下のマークアップ言語を実装したテンプレートフィルタのコレクションです:

  • Textile
  • Markdown
  • ReST (ReStructured Text)

詳しくは ref-contrib-markup を参照してください。

django.contrib.webdesign

「Lorem Ipsum...」のような例文を出力するタグなど、ウェブサイトをデザインす るときに役立つテンプレートタグを集めたものです。 django.contrib.webdesign も参照してください。

Python プログラマのための Django テンプレート言語ガイド

revision-up-to:11321 (1.1) unfinished

このドキュメントでは、 Django のテンプレートシステムを技術的な側面、すなわ ちどのように動作し、どうやって拡張するかという観点から解説します。テンプレー ト言語の構文リファレンスを探しているのなら、 Django テンプレート言語 を参照 してください。

Django テンプレートシステムを他のアプリケーションの部品として使いたい場合、 すなわち Django フレームワークの他の部分は必要ない場合、このドキュメントの 後の方にある 設定 の節に必ず目を 通して下さい。

基礎

テンプレート (template) とは、 Django テンプレート言語を使ってマークアッ プしたテキストドキュメントや Python 文字列です。テンプレートには ブロックタグ (block tag)変数 (variable) を入れられます。

ブロックタグ はテンプレート中で何らかの処理を行う部分を表すシンボルです。

とはいえ、この定義はいささか曖昧ですね。例えば、ブロックタグを使うと、何ら かのコンテンツを出力したり、制御構造 (“if” 文や “for” ループ) を記述したり、 データベースからコンテンツを取り出したり、他のテンプレートタグにアクセスし たりします。

ブロックタグは "{%""%}" で囲みます。

ブロックタグを使ったテンプレートの例を示します:

{% if is_logged_in %}Thanks for logging in!{% else %}Please log in.{% endif %}

変数 はテンプレート中で何らかの値を出力する部分を表すシンボルです。

変数は "{{""}}" で囲みます。

変数を使ったテンプレートの例を示します。:

My first name is {{ first_name }}. My last name is {{ last_name }}.

コンテキスト (context) はテンプレートに渡される「変数名」から「変数の値」 へのマッピングです。

テンプレートの レンダリング (rendering) では、コンテキストから値を取り 出して変数という「穴」に埋め、全てのブロックタグを実行します。

テンプレートシステムの利用
class django.template.Template

Python でテンプレートを使うには、以下の 2 段階のプロセスを踏みます:

  • 生のテンプレートをコンパイルして Template オブジェクトを生成しま す。
  • コンテキストを指定して、 Template オブジェクトの render() メ ソッドを呼び出します。
文字列のコンパイル

Template オブジェクトを作成するには、直接インスタンスを生成する方法が最 も簡単です。 Template クラスは django.template.Template にあります。 コンストラクタは引数に生のテンプレートコードを取ります:

>>> from django.template import Template
>>> t = Template("My name is {{ my_name }}.")
>>> print t
<django.template.Template instance>

舞台裏

このシステムは Template オブジェクトを生成するときに生のテンプレー トコードを一度しか解析しません。コンパイル後のテンプレートはパフォーマ ンス上の目的から “node” データ構造に保存されます。

テンプレートコードの解析自体もきわめて高速です。解析のほとんどは短い正 規表現を一つ呼び出すだけで終わります。

コンテキストのレンダリング
render(context)

コンパイル済みの Template オブジェクトを作成したら、オブジェクトを使っ てコンテキストをレンダリングできるようになります。 Context クラスは django.template.Context にあります。コンテキストクラスのコンストラクタ は二つの (省略可能な) 引数をとります:

  • 変数名と変数値を対応づける辞書
  • 現在のアプリケーション名。このアプリケーション名は 名前空間による URL の解決 で役立ちます。もし名前空間化 された URL を使用していなければ、この引数は無視して問題ありません。

Template オブジェクトの render() メソッドを呼び出すと、コンテキス トの値でテンプレートを「埋め」て出力します:

>>> from django.template import Context, Template
>>> t = Template("My name is {{ my_name }}.")

>>> c = Context({"my_name": "Adrian"})
>>> t.render(c)
"My name is Adrian."

>>> c = Context({"my_name": "Dolores"})
>>> t.render(c)
"My name is Dolores."

変数名には、任意の文字 (A-Z)、数字 (0-9)、アンダースコアまたはドットしか 使えません (ただしアンダースコアで始めてはいけません)。

ドットはテンプレートレンダリングにおいて特殊な意味を持ちます。変数名中の ドットは、 値の照合 (lookup) を意味します。もっと詳しく言えば、テンプレー トシステムが変数名中にドットを見つけた場合、以下の順で値の照合を試みます:

  • foo["bar"] のような辞書としての照合。
  • foo.bar のような属性値の照合。
  • foo[bar] のようなリストのインデクス指定。

テンプレートシステムは最初に成功した照合結果を使います。いわば短絡的ロジッ ク (short-circuit logic) です。いくつか例を示します:

>>> from django.template import Context, Template
>>> t = Template("My name is {{ person.first_name }}.")
>>> d = {"person": {"first_name": "Joe", "last_name": "Johnson"}}
>>> t.render(Context(d))
"My name is Joe."

>>> class PersonClass: pass
>>> p = PersonClass()
>>> p.first_name = "Ron"
>>> p.last_name = "Nasty"
>>> t.render(Context({"person": p}))
"My name is Ron."

>>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
>>> t.render(c)
"The first stooge in the list is Larry."

もし変数 (のいずれかの部分) が呼び出し可能オブジェクト (callable) である場合、 テンプレートシステムはそれを呼び出そうとします。たとえば:

>>> class PersonClass2:
...     def name(self):
...         return "Samantha"
>>> t = Template("My name is {{ person.name }}.")
>>> t.render(Context({"person": PersonClass2}))
"My name is Samantha."
以前は、呼び出し可能オブジェクトは「ある変数の属性として照合された場合 にだけ」テンプレートシステムから呼び出されていました。この仕様は、 照合方法に一貫性を持たせるために変更されました。

呼び出し可能な変数の場合、ただ照会すれば良い普通の変数に比べるとちょっと 複雑になります。いくつか心に留めておくべきことを挙げておきます:

  • もし変数呼び出し時に例外が送出された場合、その例外に silent_variable_failure という属性があり、かつ値が True``に設 定されている場合を除き、例外はそのまま伝播します。例外が ``silent_variable_failure という属性を持つ場合、変数は空文字列にレ ンダリングされます。例えば:

    >>> t = Template("My name is {{ person.first_name }}.")
    >>> class PersonClass3:
    ...     def first_name(self):
    ...         raise AssertionError, "foo"
    >>> p = PersonClass3()
    >>> t.render(Context({"person": p}))
    Traceback (most recent call last):
    ...
    AssertionError: foo
    
    >>> class SilentAssertionError(Exception):
    ...     silent_variable_failure = True
    >>> class PersonClass4:
    ...     def first_name(self):
    ...         raise SilentAssertionError
    >>> p = PersonClass4()
    >>> t.render(Context({"person": p}))
    "My name is ."
    

    全ての Django データベース API の DoesNotExist 例外の基底クラスで ある django.core.exceptions.ObjectDoesNotExist では silent_variable_failure = True になっているので注意してください。 つまり、 Django テンプレートと Django モデルオブジェクトを使っている 限り、 DoesNotExist 例外が出ても暗黙のうちに失敗するだけなのです。

  • 呼び出し可能な変数は、指定必須の引数が無い場合にだけ呼び出されます。 指定必須の引数がある場合は、空の文字列になります。
  • 言うまでもないことですが、呼び出すと副作用を起こす変数もあります。 副作用のある変数にテンプレートからアクセスできるようにしておくと、 間抜けな結果になったりセキュリティホールを作ったりしてしまうことがある ので注意して下さい。

    分かりやすい例に、 Django モデルオブジェクトの delete() メソッドがあります。テンプレート システムでは、以下のような書き方を許すべきではありません:

    大事なデータを消しちゃいますよ。 {{ data.delete }}
    
  • ときにはデータ変更を防ぐ以外の目的で、この機能を無効化してテンプレート システムから変数を一切呼び出さないで欲しいと思うこともあるでしょう。 そうするには、その呼び出し可能オブジェクトに do_not_call_in_templates 属性を設定し、その値を True にします。こうするとテンプレートシステムは あたかもその変数が呼び出し可能オブジェクトではない場合と同じように扱います (その呼び出し可能オブジェクトの属性へのアクセスなども可能になります)。
無効な値の扱い

基本的に、変数が存在しなければ、 テンプレートシステムは TEMPLATE_STRING_IF_INVALID の設定値を挿入します。この値のデフォルトは '' (空文字列) です。

無効な値に対してフィルタが適用されるのは、 TEMPLATE_STRING_IF_INVALID の値が '' に設定されている場合だ けです。 TEMPLATE_STRING_IF_INVALID'' 以外の値になってい ると、フィルタは無視されます。

ただし、 if, for, regroup といったテンプレートタグの中では、少 し違った挙動になります。これらのテンプレートタグ中では、無効な値は None であると解釈されます。また、これらのテンプレートタグ中のフィルタは、無効な 値に対しも常に適用されます。

TEMPLATE_STRING_IF_INVALID にフォーマット指示文字の '%s' が 入っている場合、 '%s' は不正な変数の変数名で置き換えられます。

デバッグ専用です!

TEMPLATE_STRING_IF_INVALID はデバッグには便利ですが、「開発 時のデフォルトの設定」としてオンにするのはよい考えではありません。

Admin サイトのテンプレートをはじめとする多くのテンプレートは、実在し ない値を呼び出しても何も出力しないという動作を前提に作られています。 '' 以外の値を TEMPLATE_STRING_IF_INVALID に指定した場合、 こうしたテンプレートやサイトのレンダリングで問題が生じるかもしれません。

一般に、 TEMPLATE_STRING_IF_INVALID を有効にするのは特定のテ ンプレートに対する問題を解決したいときだけにして、デバッグが終わったら すぐに無効にしておくべきです。

コンテキストオブジェクトの操作
class django.template.Context

皆さんはほとんどの場合、全ての値を入れた辞書を Context() に渡して Context オブジェクトのインスタンスを生成していることでしょう。しかし、 Context オブジェクトはインスタンス化した後にも、通常の辞書と同じように 値を追加したり削除したりできます:

>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> del c['foo']
>>> c['foo']
''
>>> c['newvariable'] = 'hello'
>>> c['newvariable']
'hello'
pop()
push()
exception django.template.ContextPopException

Context オブジェクトは一種のスタックです。すなわち、 push()pop() 操作を行えます。 pop() しすぎると、 django.template.ContextPopException を送出します:

>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.push()
>>> c['foo'] = 'second level'
>>> c['foo']
'second level'
>>> c.pop()
>>> c['foo']
'first level'
>>> c['foo'] = 'overwritten'
>>> c['foo']
'overwritten'
>>> c.pop()
Traceback (most recent call last):
...
django.template.ContextPopException
update(other_dict)

push()pop() に加え、 Context オブジェクトは update() メソッドも定義しています。これは push() と同じように動作しますが、 空の辞書ではなく引数で受け取った辞書をスタックに追加します。

>>> c = Context()
>>> c['foo'] = 'first level'
>>> c.update({'foo': 'updated'})
{'foo': 'updated'}
>>> c['foo']
'updated'
>>> c.pop()
{'foo': 'updated'}
>>> c['foo']
'first level'

Context をスタック的に使うと、後述するカスタムテンプレートタグで便利な ことがあります。

コンテキストのサブクラス: RequestContext
class django.template.RequestContext

Django には django.template.RequestContext という特別なコンテキストクラ スがあります。このクラスは通常の django.template.Context とは少し異なる 部分があります。まず、 RequestContext は第一引数に HttpRequest をとります。例えば:

c = RequestContext(request, {
    'foo': 'bar',
})

第二に、 RequestContextTEMPLATE_CONTEXT_PROCESSORS 設定 に従っていくつかの値を自動的にコンテキストに入れます。

TEMPLATE_CONTEXT_PROCESSORS 設定は呼び出し可能オブジェクトのタプルになっ ています。個々の呼び出し可能オブジェクトは コンテキストプロセッサ と呼 ばれ、リクエストオブジェクトを引数にとって。何らかの値を要素に持った辞書を 返します。この辞書はコンテキストオブジェクトに統合されます。デフォルトでは、 TEMPLATE_CONTEXT_PROCESSORS は以下のようになっています:

("django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.contrib.messages.context_processors.messages")
これらに加えて RequestContext は常に django.core.context_processors.csrf を使用します。これはセキュリティ関係 のコンテキストプロセッサで、admin やその他の contrib アプリケーションが 必要としており、そして誤って設定ミスをした場合に備えて意図的にハードコードさ れていて、 TEMPLATE_CONTEXT_PROCESSORS の設定で無効化できません。
'messages' コンテキストプロセッサが追加されました。詳細については メッセージフレームワーク を参照してください。
auth コンテキストプロセッサは django.core.context_processors.auth から django.contrib.auth.context_processors.auth へと移動しました。

各プロセッサはタプルに列挙した順に適用されます。従って、あるプロセッサが ある変数をコンテキストに入れた後、別のプロセッサが同じ名前の変数を入れれば、 後者が前者の内容を上書きします。デフォルトのプロセッサについては後で説明し ます。

コンテキストプロセッサが適用されるタイミング

RequestContext には、最初にあなた自身が提供する変数がまず追加され、 その後にコンテキストプロセッサの提供する変数が追加されます。したがって、 コンテキストプロセッサはあなたが提供した変数を上書きする可能性がありますの で、コンテキストプロセッサが提供する変数と同じ変数名を避けるよう気をつけて ください。

RequestContext にはオプションの第三引数 processors に追加のプロセッ サのリストを指定できます。下記の例では、 RequestContextip_address 変数が入ります:

def ip_address_processor(request):
    return {'ip_address': request.META['REMOTE_ADDR']}

def some_view(request):
    # ...
    c = RequestContext(request, {
        'foo': 'bar',
    }, [ip_address_processor])
    return HttpResponse(t.render(c))

Note

Django の render_to_response() ショートカットを 使っていて、辞書オブジェクトを渡してコンテキストの変数を追加している場合、 テンプレートはデフォルトで (RequestContext ではなく) Context になります。テンプレートのレンダリングに RequestContext を使うには、 render_to_response() の 3 つめの引数に RequestContext インスタンスを指定します。 コードは以下のようになるでしょう:

def some_view(request):
    # ...
    return render_to_response('my_template.html',
                              my_data_dictionary,
                              context_instance=RequestContext(request))

各デフォルトプロセッサの動作を以下に示します:

django.contrib.auth.context_processors.auth

このプロセッサが TEMPLATE_CONTEXT_PROCESSORS にある場合、以下の 3 つの変数が RequestContext に入ります:

  • user – 現在ログインしているユーザを表す auth.User インスタン ス (クライアントがログインしていない場合には AnonymousUser インス タンス) です。
  • perms – 現在ログインしているユーザが有しているパーミッションを表 す、 django.contrib.auth.context_processors.PermWrapper のインス タンスです。
このコンテキストプロセッサは django.core.context_processors.auth から現在の場所に移動されました。
バージョン 1.3 より前では、 PermWrapperdjango.contrib.auth.context_processors にありました。
django.core.context_processors.debug

このプロセッサが TEMPLATE_CONTEXT_PROCESSORS にある場合、以下の 2 つの変数が RequestContext に入ります。ただし、 DEBUG の設定が True で、リクエストの IP アドレス (request.META['REMOTE_ADDR']) が INTERNAL_IPS 設定に入っている場合だけです:

  • debugTrue です。 DEBUG モードかどうかをテスト するのに使えます。
  • sql_queries{'sql': ..., 'time': ...} 辞書のリストです。 このリストはリクエスト処理中に実行された SQL クエリと、それにかかった 時間を表しています。リストはクエリの実行順にならんでいます。
django.core.context_processors.i18n

このプロセッサが TEMPLATE_CONTEXT_PROCESSORS にある場合、以下の 2 つの変数が RequestContext に入ります:

  • LANGUAGESLANGUAGES 設定の値です。
  • LANGUAGE_CODErequest.LANGUAGE_CODE が存在する場合、その値 です。値がなければ LANGUAGE_CODE 設定の値になります。

詳しくは 国際化とローカライズ を参照してください。

django.core.context_processors.media

TEMPLATE_CONTEXT_PROCESSORS にこのコンテキストプロセッサを入れる と、 RequestContextMEDIA_URL というコンテキスト変数が入ります。 MEDIA_URL には MEDIA_URL 設定の値が入っています。

django.core.context_processors.static
django.core.context_processors.static()
リリースノートを参照してください

TEMPLATE_CONTEXT_PROCESSORS にこのコンテキストプロセッサを入れる と、 RequestContextSTATIC_URL というコンテキスト変数が入ります。 STATIC_URL には STATIC_URL 設定の値が入っています。

django.core.context_processors.csrf
リリースノートを参照してください

このコンテキストプロセッサは csrf_token テンプレートタグが クロスサイトリクエストフォージェリ 対策のために 必要とするトークンを追加します。

django.core.context_processors.request

このプロセッサが TEMPLATE_CONTEXT_PROCESSORS にある場合、変数 requestRequestContext に入ります。この変数は現在の HttpRequest を表現します。このプロセッサはデフォルト では有効でないので注意してください。利用したければ有効にせねばなりません。

django.contrib.messages.context_processors.messages

このプロセッサが TEMPLATE_CONTEXT_PROCESSORS にある場合、変数が 一つ RequestContext に追加されます:

  • messages – ユーザモデルを通して (user.message_set.create を使って) 設定されたか、 メッセージフレームワーク を 通して設定されたメッセージ (文字列) のリスト。
このテンプレートコンテキスト変数はこれまで 'auth' コンテキストプロセッサ が提供してきました。後方互換性のため 'auth' コンテキストプロセッサは Django 1.4 までは messages 変数を提供し続けます。もし messages 変数を使う場合、あなたのプロジェクトはどちらの (または両方の) コンテキスト プロセッサを使っても動作するでしょうけれども、将来のアップグレードに備えて django.contrib.messages.context_processors.messages を追加することを 推奨します。
コンテキストプロセッサを自作する

コンテキストプロセッサのインタフェースはとても簡単です。コンテキストプロセッ サは単なる Python の関数で、 HttpRequest オブジェクトを 引数にとり、テンプレートコンテキストに追加できるような辞書を返します。 コンテキストプロセッサは、 必ず 辞書型を返さねばなりません。

自分のコードベースに自作のコンテキストプロセッサを入れてもかまいません。 Django 側からは、自作のコンテキストプロセッサを TEMPLATE_CONTEXT_PROCESSORS 設定で指定するようにしてください。

テンプレートのロード

一般的には、低水準の Template API を自分で使うことはほとんどなく、テン プレートはファイルの形でファイルシステム上に保存することになるでしょう。 テンプレートディレクトリ に指定したディレクトリにテンプレートファイルを 保存してください。

Django はテンプレートローダの設定 (「Loader 型」を参照してください) に従って、いくつものテンプレートディレクトリを検索しますが、最も基本的なテ ンプレートディレクトリ指定方法は TEMPLATE_DIRS を使う方法です。

TEMPLATE_DIRS 設定

設定ファイル中で、 TEMPLATE_DIRS 設定を使ってどのディレクトリに テンプレートが収められているかを指定してください。この値は文字列のリストか タプルで指定します。文字列にはテンプレートディレクトリへの完全なパスを指定 せねばなりません。例えば:

TEMPLATE_DIRS = (
    "/home/html/templates/lawrence.com",
    "/home/html/templates/default",
)

Web サーバがテンプレートディレクトリの中身を読みだせる限り、テンプレートは どこにでも置けます。拡張子はなんでもよく、 .html でも .txt でも かまいませんし、拡張子を付けなくてもかまいません。

Windows を使っている場合でも、パスは Unix 形式のスラッシュを使った表記法で 指定せねばならないので注意して下さい。

Python API

Django でファイルからテンプレートを読み出すには二通りの方法があります:

django.template.loader.get_template(template_name)

get_template は、指定した名前のテンプレートに対応したコンパイル済み のテンプレート (Template オブジェクト) を返します。テンプレートが存 在しなければ django.template.TemplateDoesNotExist を送出します。

django.template.loader.select_template(template_name_list)

select_templateget_template と同じです。ただし、テンプレー ト名のリストを引数にとります。リストの中で最初に見つかったテンプレート を返します。

例えば get_template('story_detail.html') を呼び出した場合、前述のような TEMPLATE_DIRS の設定をしていれば、Django は以下のような順番でテ ンプレートファイルを探します:

  • /home/html/templates/lawrence.com/story_detail.html
  • /home/html/templates/default/story_detail.html

select_template(['story_253_detail.html', 'story_detail.html']) なら、 以下の順で探します:

  • /home/html/templates/lawrence.com/story_253_detail.html
  • /home/html/templates/default/story_253_detail.html
  • /home/html/templates/lawrence.com/story_detail.html
  • /home/html/templates/default/story_detail.html

テンプレートが見つかった時点で Django は検索を停止します。

Tip

select_template() を使うと、極めて柔軟な「テンプレート構成機能 (templatability)」を実現できます。例えば、あるニュース記事を書いていて、 記事によってはカスタムのテンプレートを使いたいとします。 select_template(['story_%s_detail.html' % story.id, 'story_detail.html']) のようにすると、個々の記事にカスタムのテンプレートを使いながら、カスタ ムのテンプレートがない記事に対してはフォールバックのテンプレートを用意 できるというわけです。

サブディレクトリの使用

テンプレートディレクトリを複数のサブディレクトリで構成するのは可能ですし、 お勧めでもあります。慣習的には各 Django アプリケーション毎にサブディレク トリを作成します。必要に応じてさらにサブディレクトリを作成します。

精神衛生のためにもぜひテンプレートを階層化しましょう。一つのディレクトリの ルートレベルに全てのテンプレートを保存するのは、だらしないことこの上ありま せん。

サブディレクトリ下にあるテンプレートをロードするには、以下のようにスラッシュ を使って指定します:

get_template('news/story_detail.html')

この例の get_template() は、上の TEMPLATE_DIRS と同じ設定を 使った場合、以下の順番でテンプレートをロードしようと試みます:

  • /home/html/templates/lawrence.com/news/story_detail.html
  • /home/html/templates/default/news/story_detail.html
Loader 型

デフォルトでは、 Django はファイルシステムベースのテンプレートローダを使っ ていますが、 Django には他のテンプレートローダも付属しており、その他のデー タソースからテンプレートをロードできるようになっています。

ファイルシステムベース以外のテンプレートローダはデフォルトでは無効化されて いますが、 TEMPLATE_LOADERS 設定を編集して有効にできます。 TEMPLATE_LOADERS は文字列のタプルで、各文字列がテンプレートロー ダクラスを表します。組み込みのテンプレートローダを以下に示します:

1.2 より前の Django ではテンプレートローダは呼び出し可能オブジェクト (普通 は関数) をベースにしていましたが、 1.2 リリースからは新しいクラスベースの API が提供され、以下で説明するすべてのローダーはこの新しい API を実装して います。
django.template.loaders.filesystem.Loader
TEMPLATE_DIRS の設定に従って、ファイルシステムからテンプレー トをロードします。
django.template.loaders.app_directories.Loader

ファイルシステム上の Django アプリケーションからテンプレートをロードし ます。このローダは INSTALLED_APPS の各アプリケーションについ て templates サブディレクトリを探します。ディレクトリが存在すれば、 Django はその中からテンプレートを探します。

これはすなわち、個々のアプリケーションにテンプレートを保存しておけると いうことです。このローダを使うと、 Django アプリケーションをデフォルト のテンプレート付きで配りやすくなります。

例えば、以下のように設定します:

INSTALLED_APPS = ('myproject.polls', 'myproject.music')

get_template('foo.html') は以下のディレクトリを順番に探します:

  • /path/to/myproject/polls/templates/foo.html
  • /path/to/myproject/music/templates/foo.html

このローダは最初に import した時に最適化処理を行います。すなわち、 INSTALLED_APPS パッケージリストの中で、 templates サブディ レクトリを持つものをキャッシュします。

このローダはデフォルトで有効化されています。

django.template.loaders.eggs.Loader

app_directories と同じですが、ファイルシステムではなく Python eggs からテンプレートをロードします。

このローダはデフォルトで無効化されています。

django.template.loaders.cached.Loader

デフォルトでは、テンプレートシステムはレンダリングが必要になるたびにテンプ レートを読み出してコンパイルします。 Django のテンプレートシステムは非常に 高速ですが、読み出しとコンパイルのオーバーヘッドが積み重なっていく可能性は あります。

キャッシュドテンプレートローダ (cached template loader) はクラスベースの ローダで、ラッピングする他のローダのリストを指定して設定します。ラッピング されたローダは、未知のテンプレートが初めて現れたときに、その場所を特定する ために使われます。そしてキャッシュドテンプレートローダはコンパイルされた Template をメモリ上に格納します。キャッシュされた Template のインスタンスは、以後の同一テンプレートに対するリクエストで返されます。

たとえば、 filesystemapp_directories テンプレートローダの テンプレートをキャッシュするには次のように設定します:

TEMPLATE_LOADERS = (
    ('django.template.loaders.cached.Loader', (
        'django.template.loaders.filesystem.Loader',
        'django.template.loaders.app_directories.Loader',
    )),
)

Note

すべての組み込み Django テンプレートタグはキャッシュされたローダで 安全に扱えますが、もしサードパーティ製あるいはあなた自身が書いた カスタムテンプレートタグを使っている場合、各タグの Node の実装が スレッドセーフになっていることを確認しておくべきでしょう。詳細について は、 テンプレートタグのスレッドセーフ性を考慮する を参照してください。

このローダはデフォルトで無効化されています。

Django はテンプレートローダを TEMPLATE_LOADERS 設定の順番に従っ て試してゆき、マッチするテンプレートが見つかるまで探します。

render_to_string ショートカット
django.template.loader.render_to_string(template_name, dictionary=None, context_instance=None)

テンプレートのロードとレンダの反復を減らすため、 Django は作業を自動化する ためのショートカットとして、 django.template.loaderrender_to_string() を提供しています。このショートカットは、テンプレート をロードし、レンダして、結果を文字列として返します:

from django.template.loader import render_to_string
rendered = render_to_string('my_template.html', { 'foo': 'bar' })

render_to_string ショートカットは、必須の引数として、レンダリング時にロー ドするテンプレートの名前 template_name (またはテンプレート名のリスト。 この場合 Django はリスト中で最初に現れた、存在するテンプレートを使用します) をとります。また、オプション引数を二つとります:

dictionary
テンプレートのコンテキストとして使う値の入った辞書です。第二固定引 数として渡しても構いません。
context_instance
Context またはサブクラス (例えば RequestContext) のインスタ ンスです。テンプレートのコンテキストとして使われます。第三固定引数 として渡してもかまいません。

render_to_response() ショートカットも参照してくだ さい。このショートカットは、結果を HttpResponse に入れて、ビューからレンダ内容を直接返せるようにしています。

テンプレートシステムをスタンドアロンモードに設定する

Note

この節は、テンプレートシステムを他のアプリケーションの出力用コンポーネ ントとして使ってみたいと考えている人のためのものです。テンプレートシス テムを Django の一部として使っている人には、この節の内容はあてはまりま せん。

通常、 Django は必要な全ての設定情報を、デフォルトの設定ファイル上の設定と 環境変数 DJANGO_SETTING_FILE に指定したファイル上の設定を合わせ たものからロードします。ただし、 Django の他の部分からテンプレートシステム を切り離して使いたい場合は、環境変数を介して設定ファイルを扱うよりも、アプ リケーション内でテンプレートシステムを初期化したいでしょうから、環境変数を 使う方法はあまり便利とはいえないでしょう。

この問題を解決するためには、 DJANGO_SETTINGS_MODULE を使わない設定方法 に書かれている手動設定の方法を使う必要があります。テンプレートシステムの必 要な部分を import して、何らかのテンプレート関連の関数を呼ぶ 前に 、指定 したい設定を引数にして django.conf.settings.configure() を呼び出して下さ い。少なくとも TEMPLATE_DIRS (テンプレートローダを使いたい場合), DEFAULT_CHARSET (通常はデフォルトの utf-8 で十分です), TEMPLATE_DEBUG などを設定することになるでしょう。設定可能な変数 は、 設定ファイルのドキュメント に書かれています。関 係のある変数は TEMPLATE_ で始まっている設定です。

異なるテンプレート言語を使う
リリースノートを参照してください

Django の Template クラスと Loader クラスはテンプレートをロード・レンダ リングするためのシンプルな API を実装しています。この API を実装するシンプルな ラッパークラスを提供すれば、 Jinja2Cheetah といったサードパーティのテンプレートシステ ムを使用することも可能です。こうすることで、 Context オブジェクトや render_to_response() などの使いやすいショートカットと いった Django の役立つ機能をあきらめることなくサードパーティのテンプレートライ ブラリを使うことができます。

Django のテンプレートシステムのコアコンポーネントは Template クラスです。 このクラスは非常にシンプルなインタフェースを備えています: テンプレート文字列を 指定する引数を一つ取るコンストラクタと、 Context オブジェクトを受け取りレンダリングされたレスポンスを文字列を返す render() メソッドです。

たとえば、Context オブジェクトではなく辞書オブジェクトを受け取るような render() メソッドを備えた Template オブジェクトを定義しているテンプレー ト言語を私たちが使っているとしましょう。その場合、 Django の Template のイ ンタフェースを実装する次のような簡単なラッパーを書くことができます:

import some_template_language
class Template(some_template_language.Template):
    def render(self, context):
        # flatten the Django Context into a single dictionary.
        context_dict = {}
        for d in context.dicts:
            context_dict.update(d)
        return super(Template, self).render(context_dict)

これだけで、私たちの空想の Template クラスを Django のロード・レンダリングの システムで使えるようになります!

次のステップは、標準の Template のかわりに私たちの カスタムテンプレートクラスのインスタンスを返す Loader クラスを書くことです。 カスタム Loader クラスは django.template.loader.BaseLoader を継承し、 load_template_source() メソッドをオーバーライドするべきです。このメソッドは template_name 引数を受け取ってテンプレートをディスク (または他のどこか) からロードし、次のタプルを返します: (template_string, template_origin)

Loader クラスの load_template() メソッドは、テンプレート文字列を load_template_source() を呼び出して取得し、テンプレートソースから Template をインスタンス化して、次のタプルを返します: (template, template_origin)。実際には Template はこのようにインスタンス 化されるので、カスタムテンプレートクラスを代わりに使うためには load_template_source() メソッドのオーバーライドが必要、というわけです。 また django.template.loaders.app_directories.Loader を継承すると、 その load_template_source() メソッドの実装を利用することもできます:

from django.template.loaders import app_directories
class Loader(app_directories.Loader):
    is_usable = True

    def load_template(self, template_name, template_dirs=None):
        source, origin = self.load_template_source(template_name, template_dirs)
        template = Template(source)
        return template, origin

最後に、 Django にカスタムローダを使わせるようプロジェクト設定を変更する 必要があります。以上で、 Django の他の機能を使いつつ、異なるテンプレート言語で すべてのテンプレートを書けるようになりました。

See also

タグやフィルタの自作方法は テンプレートタグやフィルタを自作する を参照して ください。

Django での Unicode の扱い

revision-up-to:17812 (1.4)

Django はネイティブで Unicode データをサポートしています。データベースの設 定を正しく行っている限り、テンプレートやモデル、データベース間で Unicode 文 字列を問題なく受渡しできます。

このドキュメントでは、非 ASCII の文字コードでエンコードされたデータやテンプ レートを扱うアプリケーションを作成するときに知っておくべきことを説明します。

データベースの作成

まず、データベースが任意の文字列データを保存できるように設定してください。 通常、これは UTF-8 または UTF-16 を使うことを意味します。 latin1 (iso8859-1) のような、より文字セットの制約が強いエンコーディングを使ってい ると、一部の文字をデータベースに保存できず、情報が失われるかもしれません。

Django のデータベースバックエンドは、データベースにクエリを発行する際に、 Unicode 文字列を自動的に適切なエンコーディングに変換します。また、データベー スから文字列データを取り出す時にも、適切なエンコーディングで Python の Unicode 文字列に変換します。変換の際に、いちいち Django にデータベースの使っ ているエンコーディングを指定する必要はなく、透過的に操作できます。

詳しくは、後述の「データベース API」を参照してください。

一般的な文字列の操作

データベースの照合やテンプレートのレンダリングなど、 Django 内で文字列を使 う場面では、 Unicode 文字列と UTF-8 でエンコードされた (string 型の) 文字列 の 2 通りを選択できます。

注意

バイト文字列 (string 型) 自体にはエンコーディングに関する情報は付随して いません。そのため、 Django は全てのバイト文字列を UTF-8 でエンコードさ れているとみなします。

UTF-8 以外の文字セットを使ってエンコードされた文字列を Django に渡すと、 内部のどこかでまずいことが起きるでしょう。その結果、 Django はたいてい UnicodeDecodeError をどこかで送出するはずです。

ASCII は UTF-8 のサブセットに相当するので、コード内で ASCII のデータしか扱 わないのなら、通常の文字列を使って、自由に受渡ししてかまいません。

DEFAULT_CHARSET 設定を 'utf-8' にすれば、バイト文字列の変換 に他の文字セットを使えるかも、なんて考えるのはやめましょう! DEFAULT_CHARSET は、テンプレートのレンダリング結果 (とメール送信) の文字列のエンコーディングにしか使われません。 Django は常に内部のバイト文 字列のエンコーディングにUTF-8 を使います。その理由は、 DEFAULT_CHARSET というものは、アプリケーションの開発者が自由にい じってよいものではなく、アプリケーションをインストールして使うユーザが自由 に設定して使うためのものだからです。ユーザが:setting:DEFAULT_CHARSET をど んな値に設定しても、あなたのコードは正しく動かねばなりません。そのため、 DEFAULT_CHARSET に依存したコードを書いてはならないのです。

ほとんどの場合、 Django は文字列を扱う際に、まず Unicode 文字列に変換してか ら処理を行います。従って、一般的なルールとして、バイト文字列を渡すときには、 戻り値が Unicode 文字列となって戻ってくると想定しておいてください。

翻訳された文字列

Django を使っていると、 Unicode 文字列とバイト文字列の他に、文字列ライクな 第三の型、すなわち「翻訳された文字列」を目にするはずです。Django フレームワー クの国際化機能には、文字列を翻訳用としてマークはするけれども、実際の翻訳結 果はその文字列を使うときまで決定しないという、「遅延翻訳 (lazy translation)」 の概念があります。この機能は、文字列を実際に使用するまでに翻訳ロケールがはっ きり決まらない一方で、コードを import する時にはもとの文字列を生成しておき たい場合に便利です。

通常は、遅延翻訳文字列について心配する必要はありません。ただ、このオブジェ クトを評価すると、遅延翻訳を表す django.utils.functional.__proxy__ オブ ジェクトになっているということを覚えておいてください。また、 unicode() の引数に遅延翻訳オブジェクトを指定して呼び出すと、現在のロケールでの翻訳結 果を Unicode 文字列で返すということも覚えておいてください。

遅延翻訳オブジェクトの詳細は、 国際化のドキュメント を 参照してください。

便利なユーティリティ関数

文字列の操作は何度も何度も必要になるので、 Django では Unicode 文字列型やバ イト文字列型オブジェクトの操作を少しだけ簡単にするユーティリティ関数を提供 しています。

変換用の関数

django.utils.encoding モジュールには、 Unicode 文字列とバイト文字列との 間で相互に変換を行うための関数が入っています。

  • smart_unicode(s, encoding='utf-8', string_only=False, errors='strict') は、入力 s を Unicode 文字列に変換します。 encoding パラメタ には入力文字列のエンコーディングを指定します。(例えば、 Django はフォー ムから入力された UTF-8 でエンコードされていないデータを内部的に処理す る際にこの関数を使っています。) strings_only パラメタが True の場合、数値型、ブール型、 None といった値を s に渡しても文字列 に変換しません (もとの型のままで値を返します) 。 errors はエラー 処理時の動作を指定するためのパラメタで、Python の unicode() 関数 で使われているのと同じ値を受け取ります。

    __unicode__ メソッドを実装しているオブジェクトを smart_unicode() に渡すと、 __unicode__ メソッドを使って変換を 行います。

  • force_unicode(s, encoding='utf-8', string_only=False, errors='strict') は、ほとんどの場合 smart_unicode() と同じように動作します。ただし、 第一引数が 遅延翻訳オブジェクト の場合には 動作が異なります。 smart_unicode() は遅延翻訳オブジェクトをそのままにしておきますが、 force_unicode() を使うと、(その場で翻訳を行って) Unicode 文字列を 返します。通常は smart_unicode() を使った方がよいでしょう。とはい え、テンプレートタグやフィルタは、「後で文字列になる何か」ではなく、 「文字列」を扱わねばならない ので、 force_unicode() を使った方 が有意義です。

  • smart_str(s, encoding='utf-8', strings_only=False, errors='strict') は本質的に smart_unicode() の対極にあたるメソッドです。このメソッ ドは、第一引数をバイト文字列に変換します。 strings_only パラメタ の意味は、 smart_unicode() および force_unicode() の同名のパ ラメタと同じです。これは Python の組み込み関数 str() と少し違った 仕様ですが、 Django 内部のいくつかの場所で必要な機能として実装されて います。

普段は、 smart_unicode() しか必要ないでしょう。入力データが Unicode か バイト文字列であるような場合には、早い段階でこのメソッドを使って Unicode 化 を行い、その後の操作ではつねに Unicode を扱うようにしてください。

URI および IRI の処理

Web フレームワークは (IRI の一形式である) URL を扱えねばなりません。 URL の必要条件の一つとして、 URL は全て ASCII 文字セットで構成せねばなりま せん。しかし、国際化環境では、 URL を IRI で構築せねばならない、ざっくりと 言えば、Unicode 文字を含んだ URI を構築せねばならない場合もあるでしょう。 IRI から URI へのクオート処理や変換処理はやや厄介なので、 Django は補助にな る機能をいくつか提供しています。

  • django.utils.encoding.iri_to_uri() は (RFC 3987 準拠の) IRI から URI への変換を実装しています。
  • django.utils.http.urlquote() および django.utils.http.urlquote_plus() は、 Python の標準ライブラリで 提供している urllib.quote() および urllib.quote_plus() に手を 加えて、(データをエンコーディング前に UTF-8 文字列に変換することで)非 ASCII 文字を扱えるようにしています。

これらの関数は、それぞれのグループごとに少し違った目的があり、きちんとした 使い分けが必要です。通常、IRI や URI パスを構成する個々の部分文字列には urlquote() を使い、 '&''%' といった予約文字が正しくエンコー ドされるようにします。その後、 iri_to_uri を IRI 全体に適用して、非 ASCII 文字が正しい値にエンコードされるようにしてください。

Note

技術的には、 iri_to_uri() は IRI 仕様に準拠した完全なアルゴリズムを 実装しているわけではありません。このメソッドは、(いまのところ) 国際化ド メイン名のエンコーディングを行っていないからです。

iri_to_uri() は、 URL 内での使用を許されている ASCII 文字を一切変換しま せん。従って、例えば '%' のような文字を iri_to_url() に渡してもエン コーディングは起こりません。つまり、この関数に完全な URL を渡しても、クエリ 文字列部分などを壊してしまうことはありません。

以下の例を見ればわかりやすいでしょう:

>>> urlquote(u'Paris & Orléans')
u'Paris%20%26%20Orl%C3%A9ans'
>>> iri_to_uri(u'/favorites/François/%s' % urlquote(u'Paris & Orléans'))
'/favorites/Fran%C3%A7ois/Paris%20%26%20Orl%C3%A9ans'

注意深く見れば、二つ目の例では、 urlquote() が生成した URL を iri_to_uri() が誤って二重クオートしていないことがわかるでしょう。これは 非常に重要かつ有用な機能です。つまり、非 ASCII 文字列が入っているかどうかを 気にせず IRI を構築してもかまわず、最後に iri_to_uri() を呼び出しさえす ればよいということなのです。

iri_to_uri() は等冪性がある (何度適用しても同じ結果になる) ので、以下の ような関係が常に成立します:

iri_to_uri(iri_to_uri(some_string)) = iri_to_uri(some_string)

従って、 iri_to_uri() は同じ IRI に対して二重クオート問題を気にせず何度 でも呼び出せます。

モデル

データベースから返される文字列は全て Unicode 文字列です。文字ベースのモデル フィールド (CharField, TextField, URLField など) の値をデータベースから取り 出すと、データが ASCII バイト文字列の範疇に収まるかどうかに関わらず、常に Unicode 型の値になります。

バイト文字列を渡してモデルを作成したり、フィールドに値を入れたりしてもよく、 その場合には Django が必要に応じてデータを Unicode 型に変換します。

__str__()__unicode__() のどちらを使うべきか

デフォルトで Unicode を使うようにした結果、モデルのデータを出力するときに 注意せねばならない点が一つ増えました。

具体的には、モデルに __str__() メソッドを定義する代わりに __unicode__() メソッドを実装するよう推奨します。 __unicode__() メソッ ドの中では、モデルのフィールド値を使って好きな値を作成でき、その値がバイト 文字列として適切に表現されるかを気にせず返してかまいません (たとえ __str__() に Unicode オブジェクトを返させるように実装したとしても、 Python の仕様によって、 __str__()常に バイト文字列を返します)。

もちろん、必要であれば、モデルに __str__() メソッドを定義してもかまいま せんが、明確な理由がないかぎりそうするべきではありません。 Django の モデルクラスのベースクラスでは、自動的にモデルに __str__() メソッドを追 加するようになっていて、この __str__() 実装は内部で __unicode__() を呼び出し、その結果を UTF-8 で返します。つまり、 __unicode__() メソッ ドだけを定義しておけば、 Django が自動的にバイト文字列への型強制を処理して くれるのです。

get_absolute_url() に注意

URL に含めてよい文字は ASCII 文字だけです。従って、非 ASCII 文字を含むよう なデータから URL を構築する場合、 URL として適切な値になるようにエンコード する必要があります。 django.db.models.permalink() デコレータはこの処理 を自動的に行います。

URL を手動で生成する場合 (permalink() デコレータを 使わない 場合)、 作り手が自分でエンコーディングに気を配らねばなりません。この場合、 前述の iri_to_uri() および urlquote() 関数を使ってください。例えば:

from django.utils.encoding import iri_to_uri
from django.utils.http import urlquote

def get_absolute_url(self):
    url = u'/person/%s/?x=0&y=0' % urlquote(self.location)
    return iri_to_uri(url)

この関数は、 self.location に “Jack visited Paris & Orléans” のような文 字列が入っていてもただしくエンコードされた URL を返します。 (実際、上の例で は、最初の行のクオート処理で非 ASCII 文字が落ちるので、厳密には iri_to_uri() の呼び出しは不要です)

データベース API

filter() メソッドなどのデータベース API の引数には、 Unicode 文字列と、 UTF-8 でエンコードされたバイト文字列のどちらを渡してもかまいません。以下の 二つのクエリセットは全く同じです:

qs = People.objects.filter(name__contains=u'Å')
qs = People.objects.filter(name__contains='\xc3\85') # UTF-8 encoding of Å

テンプレート

テンプレートの手動生成には、 Unicode とバイト文字列のどちらでも使えます:

from django.template import Template
t1 = Template('バイト文字列のテンプレートだよ。')
t2 = Template(u'Unicode のテンプレートだよ。')

とはいえ、ほとんどのケースではファイルシステムからテンプレートを読み出して いることでしょう。そして、ここにはちょっと難しい問題があります。というのも、 ファイルシステム上のファイルが常に UTF-8 でエンコードされているとは限らない からです。ファイルシステム上のテンプレートファイルが UTF-8 でエンコードされ ていない場合は、 FILE_CHARSET を該当ファイルのエンコードに設定し てください。 Django はテンプレートファイルを読み出すときに、設定値に基づい てテンプレートの内容をデコードして Unicode オブジェクトに変換します (FILE_CHARSET のデフォルト値は 'utf-8' です。)

レンダリング済みのテンプレートのエンコーディングは DEFAULT_CHARSET 設定で制御されています。この設定のデフォルト値は UTF-8 です。

テンプレートタグとフィルタ

テンプレートタグやフィルタを定義する場合、以下の 2 点に注意してください:

  • テンプレートタグの render() メソッドやテンプレートフィルタの戻 り値には、常に Unicode 文字列を使ってください。
  • smart_unicode() よりも force_unicode() を使うようにしてくださ い。タグのレンダリングやフィルタの呼び出しはテンプレートのレンダリン グ中に行われるので、遅延翻訳オブジェクトから文字列への変換を遅らせる 意味がないからです。また、この時点では、 Unicode 文字列だけを扱うよう にした方が簡単です。

電子メール

Django の電子メール送信フレームワーク (django.core.mail) は、透過的に Unicode をサポートしており、メッセージ本体やヘッダに Unicode データを指定で きます。ただし、メールアドレスには ASCII 文字しか使わないといったように、一 般の電子メールの仕様は守るよう気を配るべきでしょう。

以下のコード例では、メールアドレス以外が非 ASCII 文字列であるような電子メー ルを送信しています:

from django.core.mail import EmailMessage

subject = u'My visit to Sør-Trøndelag'
sender = u'Arnbjörg Ráðormsdóttir <arnbjorg@example.com>'
recipients = ['Fred <fred@example.com']
body = u'...'
msg = EmailMessage(subject, body, sender, recipients)
msg.attach(u"Une pièce jointe.pdf", "%PDF-1.4.%...", mimetype="application/pdf")
msg.send()

フォームから提出されたデータ

HTML フォームから提出されたデータの扱いはいささか厄介な問題です。提出データ にエンコーディング情報が入っている保証がないため、結局フレームワーク側でデー タのエンコーディングを推定することになるからです。

Django はフォームデータのデコードに「遅延的」アプローチを取っています。 HttpRequest オブジェクト内のデータは、データにアクセスする瞬間にのみデ コードされます。実際には、ほとんどのデータはまったくデコードされず、 HttpRequest.GETHttpRequest.POST データ構造の一部がデコードされ ることになるでしょう。これら二つの辞書は、そのメンバを常に Unicode データと して返します。対して、 HttpRequest の他の属性やメソッドの値はクライアン トから送信されたそのままの値になります。

デフォルトでは、データのエンコーディングは DEFAULT_CHARSET 設定 値であると想定しています。特定のフォームに対してエンコーディングを変えたけ れば、以下のように HttpRequest インスタンスの encoding 属性を変更し ます:

def some_view(request):
    # (何かの理由で) データが必ず KOI8-R でエンコードされている場合
    request.encoding = 'koi8-r'
    ...

request.GETrequest.POST にアクセスした後に encoding を変更 してもかまいません。変更すると、それ以後のアクセス時に新しいエンコーディン グを使ってデータをデコードします。

ほとんどの開発者は、フォームのエンコーディングについて心配することはないで しょう。とはいえ、エンコーディングを制御できないような古いシステムを相手に するアプリケーションを開発する際には、この機能は有用なはずです。

Django はアップロードされたファイルの内容をデコードしません。通常、ファイル 上のデータは文字列ではなく単なるバイト列とみなすべきだからです。自動的にデ コードを行って、バイトストリームの意味が変わってしまうのはまずいですよね。

ドキュメントのドキュメント、その他

revision-up-to:17812 (1.4)

ここには、他に適切な置場のないドキュメントがあります。ハサミや養生テープや がらくたがごっちゃになったキッチンの引きだしのようなものです。

API の安定性

revision-up-to:17812 (1.4)

Django 1.0 のリリース によって、 API の安定性と互換性 に一定の保証が与えられました。これはつまり、 Django 1.0 用に書いたコードは 何も変更せずに 1.1 でも動作し、以後の 1.X リリースではほんのわずかな変更し か必要ないということです。

APIの安定性とは

ここでいう「安定」とは、以下のような意味です:

  • 公開 API – リンクからたどれるドキュメント内で開設されていて、メソッド 名がアンダースコアで始まらないもの – の配置や名前を変更する場合には、 以前のバージョンとの互換性のための別名のメソッドを提供します。

  • API に新たな機能を追加する場合 – これはよくあることですが – でも、 既存のメソッドの意味を無くしたり、変えたりすることはありません。換言す れば、「安定」していても (必ずしも) 「完全」ではない、ということです。

  • すでに安定と宣言されている API を何らかの理由で削除したり移動したりせ ねばならない場合、それらのメソッドは撤廃 (deprecated) とみなされ、少な くとも二つのマイナーバージョン変更までは API 中に残します。撤廃された メソッドを呼び出した場合には警告メッセージを表示します。

    Django のバージョン番号の定義と、どの機能が撤廃されているかは、 公式リリース を参照してください。

  • 深刻なバグやセキュリティホールによってやむを得ない場合に限り、これらの API に対して互換性のない変更を行います。

安定な API

全般的に、 内部仕様 の中にあるドキュメントを除き、 ドキュメント中でカバーされている機能は、 1.0 の時点で安定な API と考えてか まいません。安定な API を以下に示します:

django.utils

django.utils 以下のモジュールの大半は内部使用向けに設計されています。以 下のモジュールのみが、安定とされています:

  • django.utils.cache
  • django.utils.datastructures.SortedDictSortedDict クラスの み。モジュールの他の部分は内部使用向けです。
  • django.utils.encoding
  • django.utils.feedgenerator
  • django.utils.http
  • django.utils.safestring
  • django.utils.translation
  • django.utils.tzinfo

例外

安定性や互換性の維持には、いくつか例外を設けています。

セキュリティ上の問題の修正

セキュリティ上の問題を認識した (理想的には セキュリティレポートのポリシ に基づいて 報告された) 場合、必要な修正を行います。その結果、互換性が失われる可能性が あります。セキュリティ上の問題の解決は、互換性の保証よりも優先です。

コントリビュートアプリケーション (django.contrib)

私達は API を安定に保とうとあらゆる努力を注いでおり、現状では contrib のア プリケーションを変更するつもりはありませんが、 contrib はリリース間で変更さ れやすい分野ではあります。ウェブが進化すれば、Django もそれに合わせて進化せ ねばならないからです。

とはいえ、 contrib のアプリケーションの変更について保証していることがありま す。まず、 contrib のアプリケーションに変更を行う必要があった場合、古いバー ジョンのアプリケーションも使えるようにします。すなわち、仮に Django 1.5 で 以前のバージョンと互換性のない django.contrib.flatpages を出した場合、 Django 1.4 版の django.contrib.flatpages も Django 1.5 で使えるようにし ます。この措置によって、アップグレードを容易にします。

歴史的に、これまで django.contrib のアプリケーションはコア部分よりも安 定でした。したがって、おそらく上記のような例外的なことは起きないでしょう。 とはいえ、 django.contrib に依存してアプリケーションを開発しているなら、 覚えておくにこしたことはありません。

内部 API

API の中には、以下の二つの理由から「内部使用 (internal)」とマークされている ものがあります:

  • ドキュメント内で、内部使用の API について触れていることがあります。 ドキュメント上で内部使用であると書かれていれば、将来変更される余地が あると考えてください。
  • アンダースコア (_) で始まる関数、メソッド、その他のオブジェクト。 アンダースコアを先頭に付けるのは、 Python でプライベートなものを示す のに使われる方法です。メソッドが _ 一つで開始していたら、内部 API です。
ローカルフレーバ
リリースノートを参照してください

django.contrib.localflavor は様々な国や文化のための有用なコードが 寄せ集められています。このデータは本質的にローカルであり、時代の移り変わり によって変化しがちで、これはほぼ Django のリリーススケジュールと相関するこ とはありません。例えば、よくある変更としては、州などが2つに分かれたり、名 前が変更されることが挙げられます。

この変更は2つの競合する互換性の問題を提起します。将来 、 廃止予定の、名前が変更された、または消滅した州などを選択ウェジェット に表示することは、ユーザーインターフェースの観点から良くないことです。 しかしながら、すべての後方互換を維持するためには、我々が値 - もう有効 でないものも含めて - の履歴をデータベースなどで保存しておくような サポートが必要です。

そのため、ローカルフレーバでの変更に関して Django は以下のポリシーを 持っています:

  • Django のリリース時に、 django.contrib.localflavor に含まれる データとアルゴリズムは、できるかぎり、その地域の適切な政府当局から 公式に公示されたものを反映します。もし州などが追加、変更、または削除 された場合は、その変更は Django の localflavor に反映されます。
  • この変更は以前の安定リリースに移植されることは ありません。 Django のマイナーバージョンのアップデートは、データのマイグレーション や UI が変更されたかどうかの監査を必要とするべきではありません。その ため、もし最新の州のリストを入手したい場合は、 Django のバージョンをあ げるか、必要なリストを移植する必要があります。
  • リリースごとに、アップデートされた localflavor モジュールはインポート された時に RuntimeWarning をレイズします。
  • 変更はリリースノートにて、注意が必要な後方互換が保証されない変更と して告知されます。この変更は localflavor モジュールのドキュメント でも告知されます。
  • 必要かつ可能であれば、マイグレーションスクリプトはマイグレーション 作業補助のために提供されます。

例えば、 Django 1.2 はインドネシアのローカルフレーバを含んでいます。これ は “Nanggroe Aceh Darussalam (NAD)” を州として含む州のリストを持っていま す。インドネシア政府は、この州の公式名称を “Aceh (ACE)” へと変更しました。 結果として、 Django 1.3 は “Nanggroe Aceh Darussalam (NAD)” を含んで おらず 、 “Aceh (ACE)” を含んで います

Django の設計思想

revision-up-to:17812 (1.4)

このドキュメントでは、 Django の開発者たちがフレームワークの構築に取り入れ ている根本的な設計思想についていくつか解説します。それによって、 Django の これまでの経緯に説明を与えつつ、将来への指針にしたいと思います。

全体的な設計思想

ルースカップリング

Django のスタックが目指す基本的なゴールは ルースカップリングとタイトコヒージョン の実現にあります。 フレームワークの様々なレイヤは、本当に必要な場合を除き、お互いの事情を 知らなくてもよいという考え方です。

例えば、テンプレートシステムは Web リクエストがどのようなものか関知せず、 データベースレイヤはデータをどう表示するかに関知せず、ビューシステムはプロ グラマがどんなテンプレートシステムを使うかに関知しません。

利便性のため、 Django には全てのスタックがついてきますが、スタックの各部分 は可能な限り互いに独立しています。

コード量の低減

Django アプリケーションのコードは可能なかぎり少なくし、冗長な決まり文句を排 除します。 Django では、イントロスペクションのような Python の動的な決定機 能を積極的に活用します。

迅速な開発

21 世紀の Web フレームワークのポイントは、Web 開発の単調でのろくさい部分を 高速化することにあります。 Django は Web 開発を信じられないくらいに迅速化し ます。

DRY (Don’t repeat yourself) 則

個別のコンセプトやデータは、一つの、ただ一つの場所に置かねばなりません。冗 長は悪、正規化は善です。

こうした理由から、フレームワークは可能な限り小さくせねばなりません。

暗示的より明示的に

この思想は PEP 20 にも挙げられている Python のコア思想で、 Django はで きるだけ「黒魔術」を避けるべきという意味です。どうしても必要な理由がない かぎり魔術的な処理を取り入れません。魔術的な処理を取り入れる価値があるの は、他の方法では実現し得ない多大な利便性が生まれ、かつその機能の使い方を 学ぼうとする開発者が混乱しないような形で実装できる場合だけです。

一貫性

フレームワークは全ての水準で一貫性を保たねばなりません。この一貫性は低水準 (Python のコーディングスタイル) から高水準 (Djangoの「使用感:experience」) にいたる全てにあてはまります。

モデル

暗示的より明示的に

データの挙動をフィールド名だけから決定してはなりません。さもなければ必要以 上にシステムを熟知せねばならず、エラーのもとになります。 その代り、データの挙動はキーワード引数や、場合によってはフィールドのタイプ に基づいて決定します。

関連領域のロジックは全てまとめる

モデルは「オブジェクト」としての様々な側面をカプセル化し、いわゆる Martin Fowler の アクティブレコード デザインパターンに従わねばなりません。

そのため、モデルの表現するデータや、モデル自身の情報 (人間可読な名前、デフォ ルトの整列順など) は、モデルクラスで定義されています。あるモデルを理解する のに必要な情報は、全てモデルの 中に 入っているのです。

データベース API

データベース API の主要な目的を示します:

SQL を効率化する

SQL 文の実行は可能な限り少なくし、内部的に最適化せねばなりません。

データの保存をフレームワークに背後で暗黙のうちに行わせず、開発者に save() を明示的に呼び出させるのはこのためです。

また、 QuerySetselect_related() メソッドが存在するのもこのため です。 select_related は「関連する全てのオブジェクト」を select すると いう、よくあるケースに対してパフォーマンス向上をもたらします。

むだのない強力な構文

データベース API は、高機能かつ表現性に富み、可能な限り小さな構文でなければ なりません。 API は他のモジュールやヘルパオブジェクトに依存してはなりません。

join は必要に応じて舞台裏で自動的に行われねばなりません。

システム全体にわたって、各オブジェクトは自分とリレーションにあるオブジェク トにアクセスできねばなりません。リレーションの追跡は双方向に行われねばなり ません。

必要なら生の SQL も簡単に使えるようにする

データベース API の設計では、ショートカットとして便利でありながらも、必ずし も全ての機能に手がとどかなくてもよいということを理解していなければなりませ ん。フレームワークは SQL 文全体、あるいは WHERE 節だけのカスタムの SQL を簡単に書けるようにせねばなりません。

URL の設計

ルースカップリング

Django アプリケーションでは、 URL を特定の Python コードとカップリングして はなりません。 URL と Python 関数名の関連づけは、間違っており、美しくありま せん。

同様に、 Django の URL システムは同じアプリケーションを異なるコンテキストで 使えねばなりません。例えば、あるサイトで記事 (story) にアクセスするのに /stories/ を使っていたとしても、別のところで /news/ という URL で記 事にアクセスできねばなりません。

無限の柔軟性

URL には可能な限り柔軟性をもたせねばなりません。考えられるいかなる URL 設計 も使えねばなりません。

王道を進みやすく

フレームワークはすっきりとした URL 設計を (汚い設計よりも) 簡単におこなえね ばなりません。

Web ページの URL にファイル拡張子を使うのは避けねばなりません。

URL にカンマを入れる Vignette スタイルは厳しく禁じねばなりません。

URL ははっきりと

技術的には、 foo.com/barfoo.com/bar/ は別個の URL であり、検索 エンジンロボット (や Web トラフィック解析ツール) はこれらのページを別々のも のとして扱わねばなりません。 Django は URL を「正規化」して、検索エンジンロ ボットを混乱させないようにせねばなりません。

これは APPEND_SLASH 設定の根底にある考えです。

テンプレートシステム

プレゼンテーションとロジックの分離

私達は、テンプレートシステムはプレゼンテーションとプレゼンテーション関係の ロジックを制御するためのツールであり、それ以上のものではないと考えています。 その本分をこえた機能をテンプレートシステムに求めるべきではありません。

何もかもテンプレートに押し込みたかったのなら、今ごろ PHP を使っていたでしょ う。かつてそうしていましたが、今はやめ、そこから学んだのです。

冗長さを防ぐ

大多数の動的な Web サイトでは、ヘッダやフッタ、ナビゲーションバーといった部 分のデザインをサイト全体で共通にしています。 Django テンプレートシステムは、 こうしたサイトの構成要素を一箇所に保存しやすくし、コードの複製を無くさねば なりません。

これは テンプレートの継承 の根底にある考え方で す。

HTML に縛られない

HTML だけを出力するようにテンプレートシステムを設計すべきではありません。 他のテキストベース形式や単なる平文テキストの生成もうまく実現できねばなりま せん。

XML をテンプレート言語に使わない

テンプレートのパージングに XML エンジンを使うと、テンプレート編集における 人為エラーという新たな問題に直面します。それに、テンプレート処理に受け入れ がたいオーバヘッドを被ることになります。

ページデザイナの有能さを前提にする

必ずしも Dreamweaver のような WYSIWYG エディタでうまく表示できるように テンプレートシステムを設計する必要はありません。そのような要求は制限が 厳しすぎ、本来あるべきすっきりした構文を実現できなくなります。 Django では 直接 HTML を編集する作業に慣れたテンプレート作者を想定しています。

空白の扱いはわかりやすく

テンプレートシステムは魔法的な空白の処理を行ってはなりません。テンプレート に空白をいれた場合、システムは空白部分を普通のテキストと同じように扱う、 すなわちそのまま表示せねばなりません。逆に、テンプレートタグにない空白を 表示すべきでもありません。

プログラミング言語を作り直さない

テンプレートシステムでは、以下の機能を意図的に使えないようにしています:

  • 変数の代入
  • 高度なロジック

テンプレートシステムが目的とするのは新たなプログラミング言語の発明では ありません。目的は、分岐やループといった、プレゼンテーションまわりの判定で 必須のプログラム機能の提供だけです。

Django テンプレートシステムでは、最もテンプレートを良く書くのは プログラマ ではなく デザイナ とみなしており、 Python の知識を前提には していません。

安全性とセキュリティ

テンプレートシステムは、使い始めの時点で、外部コマンドの実行やデータベース レコードの削除といった悪意あるコードを取り込めないようになっていなければなり ません。

これは、テンプレートシステムが任意の Python コードにアクセスできるように してはならないもう一つの理由でもあります。

拡張性

テンプレートシステムは、高度なテンプレート作者によるテクノロジの拡張に配慮 せねばなりません。

これはカスタムテンプレートタグやフィルタの根底にある哲学です。

ビュー

簡潔性

ビューは Python の関数として可能な限りシンプルに書きます。開発者は関数でで きることを実現するために、クラスのインスタンスを生成する必要はありません。

リクエストオブジェクトの利用

ビューはリクエストオブジェクトにアクセスします。リクエストオブジェクトとは、 現在のリクエストに関するメタデータを入れるオブジェクトです。ビューはこのオ ブジェクトをグローバル変数経由でアクセスするのではなく、引数として直接受け 取るようにすべきです。それにより、「偽の」リクエストオブジェクトを渡してビュー を簡単かつクリーンにテストできるようになります。

ルースカップリング

ビューは開発者がどのテンプレートシステムを使うか関知すべきではなく、使って いるテンプレートシステムがいくつかすら関知すべきではありません。

GET と POST の使い分け

GET と POST は全く違います。開発者はこれらを明示的に使い分けねばなりません。 フレームワークはデータの GET と POST を容易に判別できねばなりません。

サードパーティによる Django ディストリビューション

revision-up-to:17812 (1.4)

最近、サードパーティのディストリビューションプロバイダの中に、パッケージ管 理システムで Django を提供するものが出てきました。パッケージ管理システムを 使うと、Django の動作に必要な依存関係のあるコンポーネント (データベースアダ プタなど) を自動的にインストールできるため、インストールやアップグレードの 作業が大幅に簡単化されます。

通常、サードパーティのディストリビューションパッケージは最近の安定版リリー スの Django をもとに作成されます。このため、開発版の Django を使いたければ、 開発バージョンのインストール方法 の説明に従って、Subversion リポジトリから取得する必要があるでしょう。

Linux や、 OpenSolaris のような Unix を使っているのなら、ディストリビュータ がパッケージ版の Django を作成していないか調べてみてください。 Linux のディ ストリビューションを使っていて、特定のパッケージがあるかどうか分からないの なら、いい機会なので勉強しましょう。 Django の Wiki には便利な サードパーティディストリビューション の一覧があります。

ディストリビューション作成者のための情報

ディストリビューションパッケージを作成したいと考えているなら、喜んでお手伝 いします。まずは django-developers メーリングリスト に入って自己紹介してください。

また、ディストリビューション作成者は、 django-announce メーリングリスト にも入っておくよう勧めます。このメーリングリストは (とても) 流量の少ないメー リングリストで、 Django の新しいリリースやバグフィクスに関するアナウンスが 流れます。

用語集

revision-up-to:11321 (1.1)
field

model 内のアトリビュートです。通常、一つのフィールドが一つ のデータベースカラムに対応しています。

モデルの作成 を参照してください。

generic view

ビューを開発するときによくあるロジックやパターンを抽象化・一般化 して実装した、高水準の ビュー 関数です。

汎用ビュー を参照してください。

model

モデル (Model) は、アプリケーションのデータを保存します。

モデルの作成 を参照してください。

MTV

ソフトウェアパターンの「モデル・テンプレート・ビュー (Model-template-view)」の略で、 MVC スタイルに似ていますが Django のやり 方をより良く表現しています。

関連 FAQ エントリ も参照してください。

MVC
ソフトウェアパターンの「 モデル・ビュー・コントローラ (Model-view-controller)」の略です。 Django は ある程度 MVC 的です
project
Python のパッケージ、すなわちコードの入ったディレクトリです。プロジェ クトには、一つの Django インスタンスを動かすために必要な全ての情報、 たとえばデータベースの設定、 Django 固有のオプション、アプリケーショ ン固有の設定などが収められています。
property

Python バージョン 2.2 から導入された機能で、「マネージドアトリビュー ト (managed attribute)」ともいいます。これはアトリビュートそっくりに アクセスできるのに実はメソッド呼び出しで実装されているアトリビュートを 実装する上品な方法です。

property() を参照してください。

queryset

データベースから取り出した一連のレコード行を表現するオブジェクトで す。

クエリを生成する を参照してください。

slug

英文字と数字、アンダースコア、ハイフンだけからなる短いラベル文字列 です。 URL の中で使われます。例えば、以下の URL :

https://www.djangoproject.com/weblog/2008/apr/12/spring/

の中で、最後の部分 (spring) がスラグです。

template

ドキュメントのデータと表現を分離するためのテキストです。テンプレー トを使えば、データの表現方法を抽象化して、データ自体から切り離せま す。

Django テンプレート言語 を参照してください。

view
ページのレンダリングを実行する関数です。
クエリセット
queryset を参照してください。
スラグ
slug を参照してください。
テンプレート
template を参照してください。
汎用ビュー
generic view を参照してください。
ビュー
view を参照してください。
フィールド
field を参照してください。
プロジェクト
project を参照してください。
プロパティ
property を参照してください。
モデル
model を参照してください。

リリースノート

revision-up-to:17812 (1.4)

ここにあるのは、 Django の公式リリースのリリースノートです。各リリースノー トでは、新たなバージョンで登場した機能や、以前のバージョンに対する互換性の ない変更について解説しています。

Django の新しいバージョンへのアップグレードをするには、上位互換性のない 変更や複雑な機能の追加が、今使用している最新の Django から、 ‘最後の’ リリースまでになされているかを確認する必要があります。

最終更新

1.4 release

1.3 release

1.2 release

Django 1.2.1 リリースノート

revision-up-to:17812 (1.4)

Django 1.2.1 は 1.2.0 をリリースした直後に 2 つの小さなバグを修正するために リリースされました。1 つはドキュメントのパッケージ用スクリプトに存在し、 もう 1 つはローカライズが有効化された日付フィールド用フォームウィジェットに 影響を与える バグ でした。

1.1 release

Django 1.1.2 リリースノート

revision-up-to:17812 (1.4)

Django 1.1.2 にようこそ!

これは Django 1.1 シリーズ 2 回目の「バグ修正」リリースで、安定性とパフォーマン スを向上します。

Django 1.1.2 は Django 1.1.0 との後方互換性を維持していますが、いくつかの修正と 改善を含んでいます。Django 1.1 を使用中、あるいは Django 1.1 をターゲットに開発・ デプロイしている場合、Django 1.1.2 へのアップグレードを推奨します。

1.1 ブランチでの新機能、後方互換性が維持されない点、そして非推奨になる機能の 詳細については Django 1.1 release notes を参照してください。

1.1.2 における後方互換性の無い変更点
テストランナの終了ステータスコード

テストランナ (tests/runtests.pypython manage.py test) の終了ステータ スコードは、失敗したテストの数を表すものではなくなりました。256 回以上テストに 失敗すると不正なステータスコードになってしまうからです。今後、テストランナの 終了ステータスコードは、0 が成功 (失敗したテストが無い) 、1 が (任意の数の) テスト失敗を表します。もし失敗したテストの数が必要でしたら、テストランナの出力の 最後で確認できます。

クッキーのエンコーディング

Internet Explorer、 Safari の (もしかすると他のブラウザにもあるかもしれませんが) クッキーのバグを修正するため、コンマとセミコロンが安全でない文字として扱われ、そ れぞれ \054 および \073 とエンコードされるようにクッキー値のエンコーディ ング方法を変更しました。特にコンマやセミコロンをクッキーに入れており、クライアン トサイトでクッキー値を解析・操作するような javascript コードがある場合、この変更 は後方互換性を破壊するかもしれません。

新しい一つの機能

通常、ポイントリリース (訳注: マイクロリリース) は新機能を含みませんが、私達は Django 1.1.2 をこのルールの例外としました。Django 1.2 (次の Django のメジャー リリース) はクロスサイトリクエストフォージェリ (CSRF) 攻撃に対するより良い防御を 含みます。この機能では、Django がレンダリングするすべてのフォームにて新しい csrf_token テンプレートタグを使う必要があります。

1.1.X と 1.2.X の両バージョンの Django が同じテンプレートを簡単にサポートできる ようにするため、私達は新しい csrf_token テンプレートタグを 1.1.X ブランチに導入することを決めました。1.1.X ブランチでは、 csrf_token は 何もしません - フォーム処理にもテンプレートにも一切影響を与えません。しかし、 これはつまり Django 1.2 で同じテンプレートが動作することを意味しています。

Django 1.1 release notes

revision-up-to:11366 (1.1) unfinished

July 29, 2009

Welcome to Django 1.1!

Django 1.1 includes a number of nifty new features, lots of bug fixes, and an easy upgrade path from Django 1.0.

Backwards-incompatible changes

Django has a policy of API stability. This means that, in general, code you develop against Django 1.0 should continue to work against 1.1 unchanged. However, we do sometimes make backwards-incompatible changes if they’re necessary to resolve bugs, and there are a handful of such (minor) changes between Django 1.0 and Django 1.1.

Before upgrading to Django 1.1 you should double-check that the following changes don’t impact you, and upgrade your code if they do.

Changes to constraint names

Django 1.1 modifies the method used to generate database constraint names so that names are consistent regardless of machine word size. This change is backwards incompatible for some users.

If you are using a 32-bit platform, you’re off the hook; you’ll observe no differences as a result of this change.

However, users on 64-bit platforms may experience some problems using the reset management command. Prior to this change, 64-bit platforms would generate a 64-bit, 16 character digest in the constraint name; for example:

ALTER TABLE myapp_sometable ADD CONSTRAINT object_id_refs_id_5e8f10c132091d1e FOREIGN KEY ...

Following this change, all platforms, regardless of word size, will generate a 32-bit, 8 character digest in the constraint name; for example:

ALTER TABLE myapp_sometable ADD CONSTRAINT object_id_refs_id_32091d1e FOREIGN KEY ...

As a result of this change, you will not be able to use the reset management command on any table made by a 64-bit machine. This is because the the new generated name will not match the historically generated name; as a result, the SQL constructed by the reset command will be invalid.

If you need to reset an application that was created with 64-bit constraints, you will need to manually drop the old constraint prior to invoking reset.

Test cases are now run in a transaction

Django 1.1 runs tests inside a transaction, allowing better test performance (see test performance improvements for details).

This change is slightly backwards incompatible if existing tests need to test transactional behavior, if they rely on invalid assumptions about the test environment, or if they require a specific test case ordering.

For these cases, TransactionTestCase can be used instead. This is a just a quick fix to get around test case errors revealed by the new rollback approach; in the long-term tests should be rewritten to correct the test case.

Removed SetRemoteAddrFromForwardedFor middleware

For convenience, Django 1.0 included an optional middleware class – django.middleware.http.SetRemoteAddrFromForwardedFor – which updated the value of REMOTE_ADDR based on the HTTP X-Forwarded-For header commonly set by some proxy configurations.

It has been demonstrated that this mechanism cannot be made reliable enough for general-purpose use, and that (despite documentation to the contrary) its inclusion in Django may lead application developers to assume that the value of REMOTE_ADDR is “safe” or in some way reliable as a source of authentication.

While not directly a security issue, we’ve decided to remove this middleware with the Django 1.1 release. It has been replaced with a class that does nothing other than raise a DeprecationWarning.

If you’ve been relying on this middleware, the easiest upgrade path is:

  • Examine the code as it existed before it was removed.
  • Verify that it works correctly with your upstream proxy, modifying it to support your particular proxy (if necessary).
  • Introduce your modified version of SetRemoteAddrFromForwardedFor as a piece of middleware in your own project.
Names of uploaded files are available later

In Django 1.0, files uploaded and stored in a model’s FileField were saved to disk before the model was saved to the database. This meant that the actual file name assigned to the file was available before saving. For example, it was available in a model’s pre-save signal handler.

In Django 1.1 the file is saved as part of saving the model in the database, so the actual file name used on disk cannot be relied on until after the model has been saved saved.

Changes to how model formsets are saved

In Django 1.1, BaseModelFormSet now calls ModelForm.save().

This is backwards-incompatible if you were modifying self.initial in a model formset’s __init__, or if you relied on the internal _total_form_count or _initial_form_count attributes of BaseFormSet. Those attributes are now public methods.

Fixed the join filter’s escaping behavior

The join filter no longer escapes the literal value that is passed in for the connector.

This is backwards incompatible for the special situation of the literal string containing one of the five special HTML characters. Thus, if you were writing {{ foo|join:"&" }}, you now have to write {{ foo|join:"&amp;" }}.

The previous behavior was a bug and contrary to what was documented and expected.

Permanent redirects and the redirect_to() generic view

Django 1.1 adds a permanent argument to the django.views.generic.simple.redirect_to() view. This is technically backwards-incompatible if you were using the redirect_to view with a format-string key called ‘permanent’, which is highly unlikely.

Features deprecated in 1.1

One feature has been marked as deprecated in Django 1.1:

  • You should no longer use AdminSite.root() to register that admin views. That is, if your URLconf contains the line:

    (r'^admin/(.*)', admin.site.root),
    

    You should change it to read:

    (r'^admin/', include(admin.site.urls)),
    

You should begin to remove use of this features from your code immediately.

AdminSite.root will will raise a PendingDeprecationWarning if used in Django 1.1. This warning is hidden by default. In Django 1.2, this warning will be upgraded to a DeprecationWarning, which will be displayed loudly. Django 1.3 will remove AdminSite.root() entirely.

For more details on our deprecation policies and strategy, see Django のリリースプロセス.

What’s new in Django 1.1

Quite a bit: since Django 1.0, we’ve made 1,290 code commits, fixed 1,206 bugs, and added roughly 10,000 lines of documentation.

The major new features in Django 1.1 are:

ORM improvements

Two major enhancements have been added to Django’s object-relational mapper (ORM): aggregate support, and query expressions.

Aggregate support

It’s now possible to run SQL aggregate queries (i.e. COUNT(), MAX(), MIN(), etc.) from within Django’s ORM. You can choose to either return the results of the aggregate directly, or else annotate the objects in a QuerySet with the results of the aggregate query.

This feature is available as new QuerySet.aggregate()`() and QuerySet.annotate()`() methods, and is covered in detail in the ORM aggregation documentation.

Query expressions

Queries can now refer to a another field on the query and can traverse relationships to refer to fields on related models. This is implemented in the new F object; for full details, including examples, consult the documentation for F expressions.

Model improvements

A number of features have been added to Django’s model layer:

“Unmanaged” models

You can now control whether or not Django manages the life-cycle of the database tables for a model using the managed model option. This defaults to True, meaning that Django will create the appropriate database tables in syncdb and remove them as part of the reset command. That is, Django manages the database table’s lifecycle.

If you set this to False, however, no database table creating or deletion will be automatically performed for this model. This is useful if the model represents an existing table or a database view that has been created by some other means.

For more details, see the documentation for the managed option.

Proxy models

You can now create proxy models: subclasses of existing models that only add Python-level (rather than database-level) behavior and aren’t represented by a new table. That is, the new model is a proxy for some underlying model, which stores all the real data.

All the details can be found in the proxy models documentation. This feature is similar on the surface to unmanaged models, so the documentation has an explanation of how proxy models differ from unmanaged models.

Deferred fields

In some complex situations, your models might contain fields which could contain a lot of data (for example, large text fields), or require expensive processing to convert them to Python objects. If you know you don’t need those particular fields, you can now tell Django not to retrieve them from the database.

You’ll do this with the new queryset methods defer() and only().

Testing improvements

A few notable improvements have been made to the testing framework.

Test performance improvements

Tests written using Django’s testing framework now run dramatically faster (as much as 10 times faster in many cases).

This was accomplished through the introduction of transaction-based tests: when using django.test.TestCase, your tests will now be run in a transaction which is rolled back when finished, instead of by flushing and re-populating the database. This results in an immense speedup for most types of unit tests. See the documentation for TestCase and TransactionTestCase for a full description, and some important notes on database support.

Test client improvements

A couple of small – but highly useful – improvements have been made to the test client:

  • The test Client now can automatically follow redirects with the follow argument to Client.get() and Client.post(). This makes testing views that issue redirects simpler.
  • It’s now easier to get at the template context in the response returned the test client: you’ll simply access the context as request.context[key]. The old way, which treats request.context as a list of contexts, one for each rendered template in the inheritance chain, is still available if you need it.
New admin features

Django 1.1 adds a couple of nifty new features to Django’s admin interface:

Editable fields on the change list

You can now make fields editable on the admin list views via the new list_editable admin option. These fields will show up as form widgets on the list pages, and can be edited and saved in bulk.

Admin “actions”

You can now define admin actions that can perform some action to a group of models in bulk. Users will be able to select objects on the change list page and then apply these bulk actions to all selected objects.

Django ships with one pre-defined admin action to delete a group of objects in one fell swoop.

Conditional view processing

Django now has much better support for conditional view processing using the standard ETag and Last-Modified HTTP headers. This means you can now easily short-circuit view processing by testing less-expensive conditions. For many views this can lead to a serious improvement in speed and reduction in bandwidth.

URL namespaces

Django 1.1 improves named URL patterns with the introduction of URL “namespaces.”

In short, this feature allows the same group of URLs, from the same application, to be included in a Django URLConf multiple times, with varying (and potentially nested) named prefixes which will be used when performing reverse resolution. In other words, reusable applications like Django’s admin interface may be registered multiple times without URL conflicts.

For full details, see the documentation on defining URL namespaces.

GeoDjango

In Django 1.1, GeoDjango (i.e. django.contrib.gis) has several new features:

  • Support for SpatiaLite – a spatial database for SQLite – as a spatial backend.
  • Geographic aggregates (Collect, Extent, MakeLine, Union) and F expressions.
  • New GeoQuerySet methods: collect, geojson, and snap_to_grid.
  • A new list interface methods for GEOSGeometry objects.

For more details, see the GeoDjango documentation.

Other improvements

Other new features and changes introduced since Django 1.0 include:

  • The CSRF protection middleware has been split into two classes – CsrfViewMiddleware checks incoming requests, and CsrfResponseMiddleware processes outgoing responses. The combined CsrfMiddleware class (which does both) remains for backwards-compatibility, but using the split classes is now recommended in order to allow fine-grained control of when and where the CSRF processing takes place.
  • reverse() and code which uses it (e.g., the {% url %} template tag) now works with URLs in Django’s administrative site, provided that the admin URLs are set up via include(admin.site.urls) (sending admin requests to the admin.site.root view still works, but URLs in the admin will not be “reversible” when configured this way).
  • The include() function in Django URLconf modules can now accept sequences of URL patterns (generated by patterns()) in addition to module names.
  • Instances of Django forms (see the forms overview now have two additional methods, hidden_fields() and visible_fields(), which return the list of hidden – i.e., <input type="hidden"> – and visible fields on the form, respectively.
  • The redirect_to generic view (see the generic views documentation) now accepts an additional keyword argument permanent. If permanent is True, the view will emit an HTTP permanent redirect (status code 301). If False, the view will emit an HTTP temporary redirect (status code 302).
  • A new database lookup type – week_day – has been added for DateField and DateTimeField. This type of lookup accepts a number between 1 (Sunday) and 7 (Saturday), and returns objects where the field value matches that day of the week. See the full list of lookup types for details.
  • The {% for %} tag in Django’s template language now accepts an optional {% empty %} clause, to be displayed when {% for %} is asked to loop over an empty sequence. See the list of built-in template tags for examples of this.
  • The dumpdata management command now accepts individual model names as arguments, allowing you to export the data just from particular models.
  • There’s a new safeseq template filter which works just like safe for lists, marking each item in the list as safe.
  • Cache backends now support incr() and decr() commands to increment and decrement the value of a cache key. On cache backends that support atomic increment/decrement – most notably, the memcached backend – these operations will be atomic, and quite fast.
  • Django now can easily delegate authentication to the web server via a new authentication backend that supports the standard REMOTE_USER environment variable used for this purpose.
  • There’s a new django.shortcuts.redirect() function that makes it easier to issue redirects given an object, a view name, or a URL.
  • The postgresql_psycopg2 backend now supports native PostgreSQL autocommit. This is an advanced, PostgreSQL-specific feature, that can make certain read-heavy applications a good deal faster.
What’s next?

We’ll take a short break, and then work on Django 1.2 will begin – no rest for the weary! If you’d like to help, discussion of Django development, including progress toward the 1.2 release, takes place daily on the django-developers mailing list:

... and in the #django-dev IRC channel on irc.freenode.net. Feel free to join the discussions!

Django’s online documentation also includes pointers on how to contribute to Django:

Contributions on any level – developing code, writing documentation or simply triaging tickets and helping to test proposed bugfixes – are always welcome and appreciated.

And that’s the way it is.

1.0 release

Django 1.0.2 release notes

Welcome to Django 1.0.2!

This is the second “bugfix” release in the Django 1.0 series, improving the stability and performance of the Django 1.0 codebase. As such, Django 1.0.2 contains no new features (and, pursuant to our compatibility policy, maintains backwards compatibility with Django 1.0.0), but does contain a number of fixes and other improvements. Django 1.0.2 is a recommended upgrade for any development or deployment currently using or targeting Django 1.0.

Fixes and improvements in Django 1.0.2

The primary reason behind this release is to remedy an issue in the recently-released Django 1.0.1; the packaging scripts used for Django 1.0.1 omitted some directories from the final release package, including one directory required by django.contrib.gis and part of Django’s unit-test suite.

Django 1.0.2 contains updated packaging scripts, and the release package contains the directories omitted from Django 1.0.1. As such, this release contains all of the fixes and improvements from Django 1.0.1; see the Django 1.0.1 release notes for details.

Additionally, in the period since Django 1.0.1 was released:

  • Updated Hebrew and Danish translations have been added.
  • The default __repr__ method of Django models has been made more robust in the face of bad Unicode data coming from the __unicode__ method; rather than raise an exception in such cases, repr() will now contain the string “[Bad Unicode data]” in place of the invalid Unicode.
  • A bug involving the interaction of Django’s SafeUnicode class and the MySQL adapter has been resolved; SafeUnicode instances (generated, for example, by template rendering) can now be assigned to model attributes and saved to MySQL without requiring an explicit intermediate cast to unicode.
  • A bug affecting filtering on a nullable DateField in SQLite has been resolved.
  • Several updates and improvements have been made to Django’s documentation.

Django 1.0.1 release notes

Welcome to Django 1.0.1!

This is the first “bugfix” release in the Django 1.0 series, improving the stability and performance of the Django 1.0 codebase. As such, Django 1.0.1 contains no new features (and, pursuant to our compatibility policy, maintains backwards compatibility with Django 1.0), but does contain a number of fixes and other improvements. Django 1.0.1 is a recommended upgrade for any development or deployment currently using or targeting Django 1.0.

Fixes and improvements in Django 1.0.1

Django 1.0.1 contains over two hundred fixes to the original Django 1.0 codebase; full details of every fix are available in the Subversion log of the 1.0.X branch, but here are some of the highlights:

  • Several fixes in django.contrib.comments, pertaining to RSS feeds of comments, default ordering of comments and the XHTML and internationalization of the default templates for comments.
  • Multiple fixes for Django’s support of Oracle databases, including pagination support for GIS QuerySets, more efficient slicing of results and improved introspection of existing databases.
  • Several fixes for query support in the Django object-relational mapper, including repeated setting and resetting of ordering and fixes for working with INSERT-only queries.
  • Multiple fixes for inline forms in formsets.
  • Multiple fixes for unique and unique_together model constraints in automatically-generated forms.
  • Fixed support for custom callable upload_to declarations when handling file uploads through automatically-generated forms.
  • Fixed support for sorting an admin change list based on a callable attributes in list_display.
  • A fix to the application of autoescaping for literal strings passed to the join template filter. Previously, literal strings passed to join were automatically escaped, contrary to the documented behavior for autoescaping and literal strings. Literal strings passed to join are no longer automatically escaped, meaning you must now manually escape them; this is an incompatibility if you were relying on this bug, but not if you were relying on escaping behaving as documented.
  • Improved and expanded translation files for many of the languages Django supports by default.
  • And as always, a large number of improvements to Django’s documentation, including both corrections to existing documents and expanded and new documentation.

Django 1.0 リリースノート

revision-up-to:9084 (1.0)

Django 1.0 にようこそ!

3 年もの間、私達が待ち望んで来た瞬間が、ついにやってきました。 Django 1.0 はこれまでの Django の歴史において最も大きなマイルストーンであり、完全主義 者たちが自信を持ってお送りするウェブフレームワークの決定版です。

Django 1.0 は、オープンソースプロジェクトとして、コミュニティによって 3 年 にわたり重ねられてきた開発活動の結晶です。数百もの開発者が Django のコード に貢献し、カタログは 50 もの言語に翻訳されました。そして、今や世界中のあら ゆる分野の開発者が Django を様々な仕事に使っています。

ところで、今日深い話があります。 Django を 2005 年に最初にリリースしたとき、 そのソースを取り出した内部リポジトリのバージョンは 8825 でした。一方、 公開のリポジトリ内で Django 1.0 のリビジョンは 8961 です。Django 1.0 は、 コミュニティの貢献の積み重ねが、プライベートな開発の工数を上回ったまさにそ のときにリリースされたのです。

安定性と互換性の保証

Django 1.0 のリリース から、 API の安定性と将来の互 換性を保証します。簡単にいえば、 Django 1.0 向けに開発したコードは、何も変 更せずに 1.1 で動作し、その後の 1.X リリースでもちょっとした変更しか必要な いのです。

詳細は API の安定性に関するガイド を参照してく ださい。

以前のバージョンと互換性のない変更

Django 1.0 には、 Django 0.96 と互換性のない変更が数多くあります。 0.96 向 けに書かれたアプリケーションを移植したいなら、以下の詳しい移植ガイドを参照 してください:

アプリケーションを Django 0.96 から 1.0 に移行する
revision-up-to:9084 (1.0)

Django 1.0 は、いくつかの点で 0.96 との互換性を失っています。

このガイドは、 0.96 のプロジェクトやアプリケーションを 1.0 に移行する手助け として書かれています。ドキュメントの最初の部分には、 1.0 で動作させるために 必要な変更のうち、よくあるものを説明しています。この部分の説明に従って移行 しても、まだ動作しないようなら、 ややマイナーな変更 を参照して、細かな変更に基づく互換性の問題について 調べてください。

See also

このポーティングガイドでは、コードを手早く移行することに焦点を絞ってい ますが、 1.0 リリースノート では、 1.0 で登場した 新しい機能をより詳しく解説しています。

一般的な変更

この節では、 0.96 から 1.0 への移行の際に大半のユーザが行わねばならない変更 を解説しています。

Unicode を使う

文字列リテラル ('foo') を Unicode リテラル (u'foo') に変更してくだ さい。 Django は全体で一貫して Unicode を使うようになりました。ほとんどの場 所で、通常の文字列はそのまま使えますが、 Unicode リテラルを明示的に使ってお けば、ややこしい問題が発生するのを防げます。

詳しくは Django での Unicode の扱い を参照してください。

モデル

モデルファイルにおける大きな変更は、以下の通りです:

maxlengthmax_length に変更する

maxlength 引数を max_length に変更してください (フォームフィールド との一貫性のための変更です)。

__str____unicode__ に置き換える

モデルの __str____unicode__ メソッドに置き換え、メソッドから Unicode を返す (u'foo') ようにしてください。

prepopulated_from をなくす

モデルフィールドから prepopulated_from 引数をなくしてください。この引数 はもう有効でなく、 ModelAdmin クラスの admin.py に移されました。 admin に関する詳しい変更内容は、後述の admin の変更 を参照し てください。

core の削除

core 引数がモデルフィールドより削除されました。これは、 同様の関数( インラインエディット )が アドミンインターフェースによって、別に動作するようになったため もう必要なくなったからです。インラインエディットについて心配する必要は ありません。 the admin セクションで core へ参照していた全ての 除去されたものたちについて解説しています。

class Admin:admin.py と置き換える

モデルから class Admin 宣言を除去してください。モデル内にそのまま残って いても影響はありませんが、何の効果もありません。アプリケーションを admin に 登録するには、 admin.py ファイルに宣言を移す必要があります。詳しくは admin の変更 を参照してください。

See also

djangosnippets のコントリビュータの一人が、 models.py をスキャンして admin.py を生成するスクリプト を書いていま す。

admin の変更例

models.py ファイルに対する変更を以下に示しましょう:

旧 (0.96 ) models.py:

class Author(models.Model):
    first_name = models.CharField(maxlength=30)
    last_name = models.CharField(maxlength=30)
    slug = models.CharField(maxlength=60, prepopulate_from=('first_name', 'last_name'))

    class Admin:
        list_display = ['first_name', 'last_name']

    def __str__(self):
        return '%s %s' % (self.first_name, self.last_name)

新 (1.0 ) models.py:

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    slug = models.CharField(max_length=60)

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)

新しい (1.0 の) admin.py:

from django.contrib import admin
from models import Author


class AuthorAdmin(admin.ModelAdmin):
    list_display = ['first_name', 'last_name']
    prepopulated_fields = {
        'slug': ('first_name', 'last_name')
    }

admin.site.register(Author, AuthorAdmin)
admin の変更

1.0 で追加された大きな変更の一つに、新しい admin API があります。 Django の 管理インタフェース (django.contrib.admin) は完全にリファクタされました。 admin の定義は完全にモデル定義から脱カップリングされ、admin のフレームワー クは Django の新たなフォーム処理ライブラリを使うよう書き直されました。また、 思い通りに拡張したりカスタマイズしたりできるようになりました。

この変更により、 class Admin 宣言を全て書き直す必要があります。 class Admin から admin.py ファイルの admin.site.register() 呼び 出しへの変更方法は、 モデルの変更 ですでに触れました。 以下では、 Admin 宣言を新たな書式に書き換える上で必要な細かい点について 説明します。

インラインの宣言方法

edit_inline オプションは admin.py に移されました。例を以下に示しま す:

旧 (0.96):

class Parent(models.Model):
    ...

class Child(models.Model):
    parent = models.ForeignKey(Parent, edit_inline=models.STACKED, num_in_admin=3)

新 (1.0):

class ChildInline(admin.StackedInline):
    model = Child
    extra = 3

class ParentAdmin(admin.ModelAdmin):
    model = Parent
    inlines = [ChildInline]

admin.site.register(Parent, ParentAdmin)

詳しくは InlineModelAdmin オブジェクト を参照してください。

fields を簡単にする、または fieldsets を使う

旧来の fields はややこしい書式でしたが、簡単になりました。旧来の記法は まだ使えますが、 fieldsets を使う方がよいでしょう。

旧 (0.96):

class ModelOne(models.Model):
    ...

    class Admin:
        fields = (
            (None, {'fields': ('foo','bar')}),
        )

class ModelTwo(models.Model):
    ...

    class Admin:
        fields = (
            ('group1', {'fields': ('foo','bar'),   'classes': 'collapse'}),
            ('group2', {'fields': ('spam','eggs'), 'classes': 'collapse wide'}),
        )

新 (1.0):

class ModelOneAdmin(admin.ModelAdmin):
    fields = ('foo', 'bar')

class ModelTwoAdmin(admin.ModelAdmin):
    fieldsets = (
        ('group1', {'fields': ('foo','bar'),   'classes': 'collapse'}),
        ('group2', {'fields': ('spam','eggs'), 'classes': 'collapse wide'}),
    )

See also

URLs
ルート urls.py を修正する

admin サイトをルートの urls.py に組み込んでいるのなら、以下のように変更 してください。

旧 (0.96) urls.py:

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^admin/', include('django.contrib.admin.urls')),

    # ... the rest of your URLs here ...
)

新 (1.0) urls.py:

from django.conf.urls.defaults import *

# The next two lines enable the admin and load each admin.py file:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    (r'^admin/(.*)', admin.site.root),

    # ... the rest of your URLs here ...
)
ビュー
newforms の代わりに django.forms を使う

django.newformsdjango.forms に置き換えてください。 Django 1.0 は (0.96 で登場した) newforms モジュールを単に forms と呼びます。 oldforms はなくなりました。

すでに newforms ライブラリを使っていて、 import 文を推奨の書き方で書い ているのなら、 import 文を変更するだけです。 from django import newforms as forms から from django import forms に書き換えてください:

旧:

from django import newforms as forms

新:

from django import forms

古いフォームシステム (以前は django.forms と呼ばれていた django.oldforms)を使っているのなら、フォームを書き直す必要があります。 まずは forms のドキュメント を読むところから始 めてください。

アップロードファイルの処理に新しい API を使う

アップロードファイルを扱うコードを書き換えてください。すなわち、これまでの コードでは request.FILES のエントリを単なる辞書として扱っていましたが、 UploadedFile のインスタンスとして扱ってください。 旧来の辞書としての書式はもう使えません。

従って、以下のような書き方のビュー:

def my_view(request):
    f = request.FILES['file_field_name']
    ...

には、以下の点に注意して変更を施す必要があります:

旧 (0.96) 新 (1.0)
f['content'] f.read()
f['filename'] f.name
f['content-type'] f.content_type
新しい API を使って、ファイルフィールドを手がける

django.db.models.FileField の内部の実装が変わりました。 これが返すビジブルな結果はこれらのモデルフィールドが変えた、 特別な要素に対してアクセスする方法となります。 ( URL, ファイルネーム, イメージサイズ, 等) 次の変更をする必要があります、 モデルの FileFieldmyfile と 呼ばれているとして:

Old (0.96) New (1.0)
myfile.get_content_filename() myfile.content.path
myfile.get_content_url() myfile.content.url
myfile.get_content_size() myfile.content.size
myfile.save_content_file() myfile.content.save()
myfile.get_content_width() myfile.content.width
myfile.get_content_height() myfile.content.height

widthheight アトリビュートは、ただ ImageField を通したフィールドです。 もっと詳しいことは、 model API ドキュメントに載っています。

ObjectPaginator の代わりとして Paginator を使う

0.96 の ObjectPaginator は取り除かれ、代わりに進歩したバージョンの ものに取って代わられました、それが django.core.paginator.Paginator です。

テンプレート
オートエスケープを使う

テンプレートシステムは、デフォルトで変数の出力に自動 HTML エスケープを施す ようになりました。詳しくは HTML の自動エスケープ を参照してくださ い。

個々の変数に対する自動エスケープを無効化するには、 safe フィルタ を使ってください:

エスケープされるよ: {{ data }}
エスケープされないよ: {{ data|safe }}

テンプレート全体で自動エスケープを無効にするには、テンプレート (や、テンプ レートの特定の部分) を autoescape タグで囲います:

{% autoescape off %}
   ... unescaped template content here ...
{% endautoescape %}
よりマイナーな変更

以下の変更は、些細で特殊なものです。これらの変更によって影響を受けるのは、 ごく一部の高度な使い方をしているユーザだけでしょう。とはいえ、この節を一読 して、自分のコードに当てはまる部分がないかチェックする価値はあるでしょう。

シグナル
  • シグナルハンドラには全て **kwargs を追加してください。
  • シグナルハンドラの接続と解除、シグナルの送信は、 django.dispatch.dispatcher のモジュールメソッドではなく、 Signal オブジェクトのメソッドを使ってください。
  • sender オプションの指定から、 Anonymous および Any を外してく ださい。これらのシンボルはもうありません。全てのセンダからシグナルを受け 取りたければ、 sender=None としてください。
  • カスタムシグナルを定義するときは、無名オブジェクトでなく、 django.dispatch.Signal を使ってください。

必要な変更点を手短にまとめた表を以下に示します:

旧 (0.96) 新 (1.0)
def callback(sender) def callback(sender, **kwargs)
sig = object() sig = django.dispatch.Signal()
dispatcher.connect(callback, sig) sig.connect(callback)
dispatcher.send(sig, sender) sig.send(sender)
dispatcher.connect(callback, sig, sender=Any) sig.connect(callback, sender=None)
コメント

Django 0.96 の django.contrib.comments アプリケーションを使っているの なら、 1.0 で登場した新たなコメントアプリケーションに移行してください。詳し くは Django の以前のコメントシステムからの移行 で解説しています。

テンプレートタグ
spaceless タグ

HTML タグ間のスペースを除去する spaceless タグは、以前はスペースを 一つだけ残していましたが、 全て を除去するようになりました。

ローカルフレーバ
U.S. ローカルフレーバ

django.contrib.localflavor.usadjango.contrib.localflavor.us に変更されました。他のローカルフレーバと命名方法を統一するためです。 コードを移植する際には import を書き換えてください。

セッション
新たなセッションキーの取得

SessionBase.get_new_session_key()_get_new_session_key() にリネー ムされました。 get_new_session_object() はもうありません。

フィクスチャ
行レコードのロード時に save() が呼ばれなくなる

以前は、レコード行を読むたびに、自動的にモデルの save() メソッドが呼び 出されていました。この仕様は変更され、呼び出されなくなりました。そのため、 (タイムスタンプなどの) save() 時に自動的に値が入るフィールドがある場合、 フィクスチャ側に値を持たせる必要があります。

設定
例外の改善

以前の EnvironmentErrorImportErrorRuntimeError に分かれました。 ImportError は、 Django が設定モジュールを見付け られなかった場合などに、 RuntimeError はすでに設定をロードした後に設 定を変更しようとした場合などに送出されます。

LOGIN_URL の移動

LOGIN_URL 定数が、 django.contrib.auth から settings モジュール に移動しました。 from django.contrib.auth import LOGIN_URL を使うのでは なく、 settings.LOGIN_URL を参照してください。

APPEND_SLASH の動作が変更されました

0.96 では、 URL がスラッシュで終っておらず、パスの最後の部分にピリオドもな い場合、 APPEND_SLASHTrue だと、 末尾にスラッシュを付加した URLにリダイレクトしていました。 1.0 では、明示的にスラッシュのないパターンをURL パターンでキャッチできるように、 末尾にスラッシュのない URL に対して、 まず URL パターン中に一致するエントリがないか調べ、あればリダイレクトしなく なりました。

ほとんどのユーザはこの仕様変更の影響を受けませんが、以下のような URL パター ンを書いている一部のユーザは影響を受けます:

r'/some_prefix/(.*)$'

以前は、こうしたパターンを書いている場合、まず末尾にスラッシュのある URL に リダイレクトしていました。 URL の末尾に必ずスラッシュが入っているようなパターンを書きたいなら、以下のようにパターンを書き換えてください:

r'/some_prefix/(.*/)$'
モデルに関する細かい変更
get() の例外

マネジャは AssertionError ではなく MultipleObjectsReturned 例 外を返すようになりました。

旧 (0.96):

try:
    Model.objects.get(...)
except AssertionError:
    handle_the_error()

新 (1.0):

try:
    Model.objects.get(...)
except Model.MultipleObjectsReturned:
    handle_the_error()
LazyDate の除去

ヘルパクラス LazyDate はなくなりました。

フィールド値やクエリ引数に呼び出し可能オブジェクトを指定できるようになった ので、 LazyDatedatetime.datetime.now に置き換えられます:

旧 (0.96):

class Article(models.Model):
    title = models.CharField(maxlength=100)
    published = models.DateField(default=LazyDate())

新 (1.0):

import datetime

class Article(models.Model):
    title = models.CharField(maxl_ength=100)
    published = models.DateField(default=datetime.datetime.now)
DecimalField が追加され FloatField が適切に浮動小数を扱うようになる

旧 (0.96):

class MyModel(models.Model):
    field_name = models.FloatField(max_digits=10, decimal_places=3)
    ...

新 (1.0):

class MyModel(models.Model):
    field_name = models.DecimalField(max_digits=10, decimal_places=3)
    ...

これらの変更に対応し忘れると、新たな FloatField に精度桁数に関する引数 がないため、 FloatField__init__ には max_digits という属性 がない、という旨のエラーを受け取ります。

MySQL や PostgreSQL を使っている場合、これ以上の変更は必要ありません。 DecimalField のデータベースカラム型は、旧来の FloatField と同じだか らです。

SQLite を使っている場合、データベースに対して、データを decimal 型でなく float 型として扱うよう教え直す必要があります。そのために、データをリロード してください。データのリロードは、 DecimalField への変更を終えて、 Django をアップデートした後に行ってください。

Warning

データベースを先にバックアップしてください!

SQLite を使っている場合、データベースのバックアップするには、単にデータベー スの保存されているファイル (settings.pyDATABASE_NAME に指定し ているファイル名) をコピーします。

DecimalField を使う全てのアプリケーションについて、 <app> をアプリ ケーションの名前に読み替えて以下の作業を行うとよいでしょう:

$ ./manage.py dumpdata --format=xml <app> > data-dump.xml
$ ./manage.py reset <app>
$ ./manage.py loaddata data-dump.xml

注意:

  1. 作業の最初のステップでは、必ずダンプ形式に XML を指定してください。と いうのも、このステップでは、 XML データダンプによって、 float データが SQLite で扱える decimal に変換されるという仕様を使っているからです。
  2. 二つめのステップでは、アプリケーションのデータが失われてもよいか尋ねら れます。 yes と答えてください。もちろん、三つ目のステップでデータを復 元しますからね。
  3. DecimalField に関する仕様変更前からある Django 付属のアプリケーショ ンは、全て影響を受けません。したがって、標準の Django モデルに対してこ の操作を行う必要はありません。

上のプロセスでうまく行かないようなら、バックアップしておいたデータベースファ イルをデータベースファイルに上書きして、Django を再起動してください。

国際化
django.views.i18n.set_language() には POST リクエストが必要

以前は、 GET リクエストが使われていました。この動作は、サーバの状態 (サイト を表示する際のロケール) を GET リクエストで変更できることになり、 HTTP 仕様 の勧告に違反しています。 1.0 からは、このビューを呼び出すときには、GET では なく POST リクエストを使わねばならなくなりました。そのため、このビューは リンクを使ってアクセスできず、ボタンなどを使ってフォームを提出せねばならな くなりました。

_() は組み込みでなくなりました

以前は、モンキーパッチによって _() (名前がアンダースコア一文字の呼び出 し可能オブジェクト)を組み込み名前空間に入れていましたが、これをやめたため、 _() を魔法のように常に使えなくなりました。

_() の存在を前提としてコードを書いている場合、 ugettextugettext_lazy のどちらか適切な方を明示的に import して、 _ という別 名をつけねばなりません:

from django.utils.translation import ugettext as _
HTTP リクエスト/レスポンスオブジェクト
HttpRequest への辞書的なアクセス

HttpRequest オブジェクトはもはや直接的に辞書式にアクセスすることを サポートしなくなりました、 GETPOST 両方のデータは 直接的に HttpRequest オブジェクトで扱えました(すなわち、 HttpRequest object (すなわち、 if 'some_form_key' in request を使うか、 request['some_form_key'] を読み込むことで、 フォームデータ一つをチェックすることができました。これはもう、 サポートされていません。 もし、組み込みの GETPOST データに アクセスする必要があるなら、 request.REQUEST を代わりに使って ください。

これは強く推奨されています、しかしながら、受け取ることを期待した リクエストの種類が、常に適切なディクショナリとなっているかを、 常に明確にする( request.GETrequest.POST )があります。 組み込みの request.REQUEST ディクショナリは入ってくるデータの オリジンを隠すことができます。

HTTPResponse ヘッダへのアクセス

django.http.HttpResponse.headers_headers にリネームされ、 django.http.HttpResponse` はヘッダの包含チェックを 直接サポートするようになりました。 従って、 if header in response.headers: ではなく if header in response: と書いてください。

一般化リレーション
一般化リレーションはコアパッケージから移動しました

一般化リレーションのクラス、 GenericForeignKey および GenericRelation は、 django.contrib.contenttypes モジュールに移 動しました。

テスト
django.test.Client.login() の変更

login の引数が以下のように変更されました。

旧 (0.96):

from django.test import Client
c = Client()
c.login('/path/to/login','myuser','mypassword')

新 (1.0):

# ... same as above, but then:
c.login(username='myuser', password='mypassword')
管理コマンド
管理コマンドをコードの中から呼び出す

django.core.management は大幅にリファクタされました。

管理コマンドのサービスをコードから呼び出す際に、 call_command を使う必 要があります。例えば、 flushload_data を呼び出す テストコードを以下のように書いていたとしましょう:

from django.core import management
management.flush(verbosity=0, interactive=False)
management.load_data(['test_data'], verbosity=0)

このコードは、例えば以下のように変更してください:

from django.core import management
management.call_command('flush', verbosity=0, interactive=False)
management.call_command('loaddata', 'test_data', verbosity=0)
サブコマンドはオプションの前に置く

django-admin.pymanage.py に引数を指定するとき、サブコマンドはオ プションよりも前に置かねばならなくなりました。従って:

$ django-admin.py --settings=foo.bar runserver

はもう使えず、以下のように変更せねばなりません:

$ django-admin.py runserver --settings=foo.bar
配信フィード
Feed.__init__ の変更

配信フィードフレームワークの Feed クラスの __init__() パラメタは、 第二引数にフィードの URL ではなく HttpRequest オブジェクトを取るように なりました。この変更によって、配信フィードフレームワークは sites フレームワー クがなくても動作するようになりました。 Feed をサブクラス化して、 __init__() をオーバライドするコードや、 Feed.__init__() を直接呼び 出しているコードが影響を受けます。

データ構造
SortedDictFromList の撤廃

django.newforms.forms.SortedDictFromList はなくなりました。その代わり、 タプルのシーケンスを使って django.utils.datastructures.SortedDict をインスタンス化できるようになりました。

コードを変更するには、以下のように書き換えてください:

  1. django.newforms.forms.SortedDictFromList を使っている部分を django.utils.datastructures.SortedDict に書き換えてくださ い。
  2. django.utils.datastructures.SortedDict.copy()SortedDictFromList メソッドとは違って深いコピーを返さないので、 コードを deepcopy に対応して書き換える必要があります。深いコピーを 作成するには、 copy.deepcopy を直接呼び出します。
データベースバックエンドの関数
データベースバックエンドの関数名の変更

データベースバックエンドレベルの関数の名前は、ほとんど すべて 変更され、 場所が変わっているものもあります。この変更はドキュメントで一切説明されてい ませんが、自分のコードでこれらの関数を使っていたのなら、名前を変更する必要 があるでしょう。関数は全て django.db パッケージ下にあります:

旧 (0.96) 新 (1.0)
backend.get_autoinc_sql connection.ops.autoinc_sql
backend.get_date_extract_sql connection.ops.date_extract_sql
backend.get_date_trunc_sql connection.ops.date_trunc_sql
backend.get_datetime_cast_sql connection.ops.datetime_cast_sql
backend.get_deferrable_sql connection.ops.deferrable_sql
backend.get_drop_foreignkey_sql connection.ops.drop_foreignkey_sql
backend.get_fulltext_search_sql connection.ops.fulltext_search_sql
backend.get_last_insert_id connection.ops.last_insert_id
backend.get_limit_offset_sql connection.ops.limit_offset_sql
backend.get_max_name_length connection.ops.max_name_length
backend.get_pk_default_value connection.ops.pk_default_value
backend.get_random_function_sql connection.ops.random_function_sql
backend.get_sql_flush connection.ops.sql_flush
backend.get_sql_sequence_reset connection.ops.sequence_reset_sql
backend.get_start_transaction_sql connection.ops.start_transaction_sql
backend.get_tablespace_sql connection.ops.tablespace_sql
backend.quote_name connection.ops.quote_name
backend.get_query_set_class connection.ops.query_set_class
backend.get_field_cast_sql connection.ops.field_cast_sql
backend.get_drop_sequence connection.ops.drop_sequence_sql
backend.OPERATOR_MAPPING connection.operators
backend.allows_group_by_ordinal connection.features.allows_group_by_ordinal
backend.allows_unique_and_pk connection.features.allows_unique_and_pk
backend.autoindexes_primary_keys connection.features.autoindexes_primary_keys
backend.needs_datetime_string_cast connection.features.needs_datetime_string_cast
backend.needs_upper_for_iops connection.features.needs_upper_for_iops
backend.supports_constraints connection.features.supports_constraints
backend.supports_tablespaces connection.features.supports_tablespaces
backend.uses_case_insensitive_names connection.features.uses_case_insensitive_names
backend.uses_custom_queryset connection.features.uses_custom_queryset

以前のバージョンと互換性のない変更の詳しいリストは http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges にあります。

Django 1.0 の新しい機能

たくさん!

Django 0.96 以降、 4000 ものコミットを行ない、 2000 個のバグを修正しました。 また、編集/追加/削除したコードは 35 万行にも及びます。また、4 万行もの新 たなドキュメントを追加し、既存の機能も格段に改善しました。

実際、新しくなったドキュメントは、 Django の機能の中でもお気に入りの部分の 一つなので、ここから紹介していきましょう。まず、新しいドキュメントのサイト には、下記の URL からアクセスできます:

ドキュメントは大幅な改善と整理の結果、すばらしく生まれ変わりました。専用の 検索機能やインデクスなどもあります。

このドキュメントはまだ 1.0 で登場した全ての機能を網羅しきれていませんが、 ガイドブックの決定版として使えることでしょう。ドキュメントのそこかしこに:

この機能は Django 1.0 で新たに登場しました。

と書かれていて、どの機能を新たに追加したり変更したりしたのか分かるはずです。

それでは、 1.0 で登場したその他の主要な機能を紹介してゆきましょう:

admin アプリケーションのリファクタ

Django の管理インタフェース (django.contrib.admin) を完全にリファクタし ました。admin の定義を完全にモデル定義から脱カップリングし (モデルから class Admin をなくしました!)、Django の新たなフォーム処理ライブラリ (0.96 から登場した django.newforms で、今後は単に django.forms) を 使うよう、 admin のフレームワークを 書き直しました。また、思い通りに拡張し たりカスタマイズしたりできるようになりました。admin アプリケーションのドキュ メントは、 admin インタフェース にあります。

Unicode 処理の改善

Django の内部処理を、一貫して Unicode を使うようリファクタしました。これに より、非西欧圏のコンテンツやデータの扱い劇的に単純化しました。また、サード パーティライブラリや、Unicode を行儀よく扱えないことのあるシステムとの相互 運用を楽にするためのユーティリティも提供しました。

Unicode リファレンス を参照してください。

Django ORM の改善

Django のオブジェクト-リレーショナルマッパ、つまり Django のモデルクラスと データベースを対応づけ、クエリの発行を仲立ちするためのコンポーネントを、徹 底的なリファクタによって劇的に改善しました。ほとんどの Django ユーザにとっ て、この変更による互換性の問題はありません。データベースを操作している公開 の API に細かい変更がありましたが、ほとんどの変更は ORM の内部コードに対し て施されています。このリファクタのもたらす、以前のバージョンと互換性のない 変更や新たな機能は、 Django の wiki ページ に掲載しています。

テンプレート変数の自動エスケープ

クロスサイトスクリプティング (XSS) 脆弱性に対する安全性をより高めるために、 Django のテンプレートシステムが全ての変数出力を自動的に HTML エスケープする よう変更しました。この挙動はもちろん変更でき、変数やテンプレートの一部を 「安全:safe」(エスケープ不要) や「安全でない:unsafe」(エスケープが必要) に マークできます。この機能の詳しい説明は、 autoescape タグのドキュメ ントにあります。

django.contrib.gis (GeoDjango)

1 年にわたる開発を経て、ワールドクラスの GIS (地理情報システム: Geographic Information Systems) のサポートを contrib アプリケーショ ンの形で Django に追加しました。 GIS のドキュメントはまだプロジェクトの外で メンテナンス中で、まもなく Django のメインドキュメントにマージする予定です。 この機能を作り上げ、完成までこぎつけた Justin Bronn, Jeremy Dunck, Brett Hoerner そして Travis Pinney に深く感謝します。

詳しくは http://geodjango.org/ を参照してください。

プラガブルなファイルストレージ機構

Django 組み込みの FileFieldImageField が、プラガブルなファイル ストレージバックエンドを使えるようになりました。ストレージバックエンドによっ て、アップロードファイルを Django に保存する方法を徹底的にカスタマイズでき ます。詳しくは、 ファイルのドキュメント を参照してく ださい。この困難な仕事を達成した Marty Alchin に深く感謝します。

Jython との互換性

Google Summer of Code プロジェクトを通じて多大な貢献をもたらした Leo Soto に感謝します。彼は Django のコードベースをリファクタし、これまで Jython との互換性を妨げていた部分を除去しました。 Jython はJava で書かれた Python 実装で、 Java 仮想マシンで Python コードを実行できます。 Django はまもなく 登場する Jython 2.5 リリースで動作します。

詳しくは Jython 上で Django を動かす を参照してください。

forms と admin への一般化リレーションの組み込み

一般化リレーションのクラスを django.contrib.contenttypes に移し、 admin インタフェースやエンドユーザのフォームでもサポートしました。詳しくは 一般化リレーションのドキュメント を参照してくだ さい。

INSERT/UPDATE の使い分け

Django で save() メソッドを呼び出したとき、SQL レベルで INSERTUPDATE のどちらを使うかの区別は、ほとんどの場合デフォルトの挙動で問題あ りませんが、たまにどちらかを強制的に用いたほうがよい場合があります。そこで、 モデルの save() にパラメタを追加して、実行する SQL を強制できるようにし ました。詳細と、パラメタを使うときの重要な注意点を、データベース API のドキュ メントに記載してあります。

詳しくは INSERT や UPDATE を強制する を参照してください。

CacheMiddleware の分割

Django の CacheMiddleware を 3 つのクラスに分割しました。 CacheMiddleware 自体はまだあり、以前の機能をそのまま残していますが、実 際には二つの別々のミドルウェア (キャッシュにデータを入れるミドルウェアと、 キャッシュからデータを取り出すミドルウェア) からなっていて、一つのミドルウェ アにまとまっていると起きる問題を回避できます。

正しい使い方など、詳細は キャッシュのドキュメント に 記載しています。

django.contrib.comments のリファクタ

Google Summer of Code プロジェクトの一環として、 Thejaswi Puthraya が Django にバンドルされているコメントシステムを大幅にリライト/リファクタし、 フレキシビリティとカスタマイズ性をすばらしく向上させました。 詳細なド キュメント と、以前のコメントアプリケーション を使っていた人のための アップグレードガイド も読めるようになりました。

撤廃した機能の除去

以前のバージョンで撤廃した機能としてマークしていた機能や、 1.0 のリリースに 先だって除去を予定していた機能を Django から取り去りました。除去した機能に は、import パス django.newforms (django.forms で import できます) や form_for_model, form_for_instance といったヘルパ関数 (ModelForm に置き換わりました)、そしてディスパッチャやファイルアップロー ド、ファイルストレージリファクタリングなどで置き換えられた機能な どがあります。

既知の問題

私達は、 Django 1.0 を可能な限り安定させるべくベストを尽くしましたが、残念 ながら、このリリースには既知の問題が二つあります。

to_field 指定を含むマルチテーブルモデル継承での問題

マルチテーブルモデル継承 を使う場合、子の モデルで permanent_linkto_field をカスタマイズすると、データベー スの一貫性に関するエラーを引き起こすという問題があるので注意してください。 以下のようなモデルを定義すると、 うまく動きません

class Parent(models.Model):
    name = models.CharField(max_length=10)
    other_value = models.IntegerField(unique=True)

class Child(Parent):
    father = models.OneToOneField(Parent, primary_key=True, to_field="other_value", parent_link=True)
    value = models.IntegerField()

このバグは、次の Django のリリースで修正する予定です。

特定のデータベースに関する注意点

Django は全てのデータベースバックエンドの可能な限り多くの機能をサポートしよ うと試みています。しかしながら、全てのデータベースシステムがまったく同じ機 能を持っているわけではなく、とりわけ Django のサポートしているデータベース の多くはバージョン毎に大きく変化しています。ですから、 サポートしてい るデータベースに関する注意 を参照しておくとよいでしょう:

Pre-1.0 releases

Django バージョン 0.96 リリースノート

revision-up-to:17812 (1.4)

Django 0.96 の世界へようこそ!

Django 0.96 の主な目標は、 0.95 で採り入れられた機能に対するクリーンアップ と安定化にあります。 0.96 には、 0.95 以前のバージョンと 互換性のない変更 がわずかにありますが、 アップグレードは簡単で、既存のアプリケーションもとくに大きな変更なく動作す るはずです。

とはいえ、 0.96 のリリースには、今後取り込まれる予定の一連の互換性のない変 更に備えるという意味もあります。これらの変更を適用した後には、アプリケーショ ン開発者は自分のコードを多少変更せねばならなくなるでしょう。ですから、次の 公式リリースまでは 0.96 を使い続けるよう勧めます。そうすれば、開発バージョ ンの Django に変更が取り込まれる度に少しづつコードをいじるのではなく、一ス テップでアップグレードできるようになるからです。

互換性のない変更

以下の変更によって、 0.95 から 0.96 に乗り換える際にコードを更新する必要が あります:

MySQLdb バージョンの制約

MySQLdb モジュール (Django が MySQL データベースにアクセスするために使っ ているバックエンド) の古いバージョンのバグを回避するため、 Django の MySQL バックエンドはバージョン 1.2.1p2 またはそれ以降の MySQLdb を要求するよ うになり、それ以前のバージョンを使おうとすると例外を送出するようになりまし た。

現状でこの制約に適合するように MySQLdb のバージョンを上げられない場合、 以前のバージョンと互換性のあるバックエンド mysql_old を使ってください。 このバックエンドを使うには、 DATABASE_ENGINE の設定を、これまで の:

DATABASE_ENGINE = "mysql"

から:

DATABASE_ENGINE = "mysql_old"

に変更してください。

とはいえ、 MySQL ユーザにはできるだけ最新の MySQLdb にアップグレードす るよう強く勧めます。 mysql_old バックエンドは移行を簡単にするだけのため に存在しており、撤廃対象とみなされています。必要なセキュリティフィクスを除 き、ほとんどメンテナンスされることはなく、将来のバージョンで削除される予定 です。

また、 DATABASE_OPTIONS のような設定 (詳細は データベースのドキュメント を参照してください) は、 “mysql” バックエンドでのみ利用でき、 “mysql_old” では使えません。

データベース名の制約に関する変更

Django が外部キー参照を生成するときに使う制約名が少し変更されました。 通常、制約名はカラムに対する参照を直接行えない場合にのみ使われるので、 ユーザの目に触れることはありません。

この変更の影響として、 manage.py reset や同様のコマンドを既存のデータベー スに対して実行すると、新たな制約名の形式で SQL を生成する一方、データベース 本体には以前の形式の制約名が存在するという問題が生じ、このためにデータベー スサーバが実在しない制約に対する変更が行われたというエラーメッセージを送出 する場合があります。

この問題を回避するには 2 通りの方法があります:

  1. manage.py * の出力をファイルにリダイレクトし、生成された SQL を編集して正しい制約名に直してから実行します。
  2. manage.py sqlall の出力から新たな制約名がどうなっているかを調べ て、データベース上の既存の制約名を変更する手がかりにします。
manage.py のオプション名変更

フィクスチャのサポートのために、 manage.py のオプションのうち、いくつか を変更しました:

  • dumpdata および loaddata コマンドが追加されました。これらのコ マンドは、それぞれデータベースに対してデータをダンプしたりロードした りするためのコマンドです。このコマンドは、 Django のサポートする全て のシリアライズ形式を扱えます。
  • sqlinitialdata コマンドは、 sqlcustom に名称変更しました。こ れは、データ関係の操作は loaddata を使うべきであることを強調する 意味もあります (sqlcustom はビューやストアドプロシジャなどのカ スタム SQL 定義に使ってください)。
  • 以前のバージョンの名残であった install コマンドを除去しました。 アプリケーションのインストールには syncdb を使ってください。
バックスラッシュのエスケープに関する変更

Django のデータベース API はクエリパラメタとして渡されたバックスラッシュを エスケープするようになりました。既存のデータベース API まわりのコードにバッ クスラッシュが入っていて、これまでは (エスケープがなくても) ちゃんと動作し ていたのなら、 1 レベル分「エスケープを外し」ておかねばなりません。

例えば、以前は以下のコードがちゃんと動作していたとします:

# Find text containing a single backslash
MyModel.objects.filter(text__contains='\\\\')

このコードは、今後は以下のように書かねばなりません:

# Find text containing a single backslash
MyModel.objects.filter(text__contains='\\')
ENABLE_PSYCO 設定の除去

ENABLE_PSYCO 設定はなくなりました。設定ファイルに ENABLE_PSYCO を加 えても、何も起きません。 Psyco を有効にしたければ、ミドルウェアクラスを自作 してください。

0.96 の新しい機能

Django 0.96 は 1000 以上の新規コミットと、 400 以上のバグフィクスの結果です。 全ての変更を一覧にするのは不可能なので、主要な変更点だけを説明します。

新しいフォームライブラリ

新たなフォーム処理ライブラリ django.newforms が導入されました。このライ ブラリは旧来のフォーム/マニピュレータ/バリデーションフレームワークである django.forms への置き換えにあたります。 0.96 ではどちらの API も使えま すが、今後の 2 バージョンのリリースの中で新たなフォームシステムに完全に移行 し、旧来のシステムは撤廃、除去する予定です。

新たなフォームライブラリへの移行のポイントは 3 つあります:

  • 現在の django.forms の実体は django.oldforms にコピーしました。 これで、互換性のない変更を座して待つことなく、 今すぐ コードの修正 に取り掛かれます。修正は、各アプリケーションのコードを以下のように書 き換えるだけです:

    from django import forms             # 0.95 スタイル
    from django import oldforms as forms # 0.96 スタイル
    
  • 次の Django の公式リリースで、現在の django.newformsdjango.forms に移動します。これは互換性のない変更なので、以前の django.forms を使い続けたい人は、上記に従って import 文を変更する 必要があります。

  • さらに次のリリースで、 django.oldforms を完全に除去します。

newforms ライブラリは現在も改良が続いていますが、すでに一般的な利用に耐 える状態です。Django でのフォーム処理に入門する人は、旧来のフォームを学ぶの はやめて、新たなフォームから学び始めましょう。

django.newforms の詳細は newforms のドキュメント を参照してください。

URLconf の改良

URLconf のコールバックに呼出し可能オブジェクトを使えるようになりました (以 前は呼出し可能オブジェクトの Python パス表記名を表す文字列しか指定できませ んでした)。この改良により、URLconf をより直感的に書けるようになりました。 例えば、以下の URLconf:

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    ('^myview/$', 'mysite.myapp.views.myview')
)

は、以下のように書けるようになりました:

from django.conf.urls.defaults import *
from mysite.myapp.views import myview

urlpatterns = patterns('',
    ('^myview/$', myview)
)

呼出し可能オブジェクトを指定できるようになった利点の一つに、デコレータを使 えるようになったことがあります。 URLconf の中で ビューにデコレータを適用 できるのです。これを使えば、ログインの必要な汎用ビューをとても簡単に書けま す:

from django.conf.urls.defaults import *
from django.contrib.auth.decorators import login_required
from django.views.generic.list_detail import object_list
from mysite.myapp.models import MyModel

info = {
    "queryset" : MyModel.objects.all(),
}

urlpatterns = patterns('',
    ('^myview/$', login_required(object_list), info)
)

どちらの表記方法 (文字列と呼出し可能オブジェクト) も指定方法としては有効で、 当面は混在して利用できます。

テストフレームワーク

ついに Django にテストフレームワークが導入されました。 (テストファーストの 推進者 Kent Beck には悪いですが) これで、「心配を退屈な作業に」変えられます。 テストは doctestunittest を使って作成でき、簡単なテストクライアントを使った ビューのテストもできます。

また、「フィクスチャ」のサポートも追加されました。フィクスチャは Django の サポートする シリアライゼーション形式 で保存さ れた初期データで、テストの開始時に自動的にデータベースにロードされます。フィ クスチャによって、実際のデータを使ったテストが一層簡単になります。

詳しくは テストのドキュメント を参照してください。

admin インタフェースの改良

ユーザの追加や更新のための専用のビューが admin インタフェースに追加されまし た。これはちょっとした、でもとても素晴らしい変更です。というのも、 admin で ハッシュパスワードを扱わなくてよくなったからです。

謝辞

0.95 以後、何人もの人達が進み出て、 Django の開発における主要な役割を果たす ようになりました。ここに彼らの尽力に対して謝意を表します:

  • Russell Keith-Magee と Malcolm Tredinnick は多くのコードに寄与してい ます。 0.96 のリリースは彼らなしでは実現しませんでした。
  • 新たなリリースマネジャ、 James Bennett は、 0.95.1 や 0.96, のリリー スを推進してくれました。(そしておそらく将来のリリースでもお世話にな ることでしょう。)
  • チケットマネジャ Chris Beaven (通称 SmileyChris), Simon Greenhill, Michael Radziej, Gary Wilson に感謝します。彼らは全てのチケットの世話 をして、カタログ化するという偉大な仕事をなしとげました。そのおかげで、 どのチケットに注力すべきかを決める作業が 1000000 倍にも楽になりました。 ほんとうにありがとう。
  • バグ報告、パッチ、そしてチケットへのコメントを提出してくださった皆さ んにも感謝します。0.96 に取り込まれたパッチの作者は 200 名以上にもの ぼるので、全ての人の名前を挙げるのは無理ですが、名前を AUTHORS に掲 載させていただきました。

Django バージョン 0.95 リリースノート

revision-up-to:17812 (1.4)

Django 0.95 リリースへようこそ。

Django 0.95 は、 2006 年 1 月の 0.91 リリース以来の素晴らしい改良の数々でいっ ぱいのリリースです。このリリースに盛り込まれた変更をここですべて挙げるのは 大変なので、簡単にまとめたものを以下に示すことにします。

適合性と API の安定性

このリリースは、 Django を使ったプロダクションレベルのアプリケーションに取 り組みたい開発者への、安定したリファレンスポイントの提供を目的としています。

とはいえ、このリリースは 1.0 ではないので、 1.0 になるまでにはいくつか変更 を採り入れる予定でいます。フレームワークのどの部分が変更されるのか (そして どの部分が変更 されない のか) を知りたければ、配布物の docs/ ディレクトリ にある api-stability.txt (<misc-api-stability) を参照してください。

このドキュメントで「API 変更の対象」と書かれた機能を使う必要がでてくるかも 知れませんが、今の機能に問題がなくて、将来 API が変更されるかも知れないと分 かっているのなら、使っていただいてかまいません。

好運なことに、 Django のコア API のほとんどは 1.0 まで変更しない予定です。 0.95 から 1.0 にかけての変更は、 0.91 から 0.95 にかけての変更ほど大がかり ではないはずです。

変更点と新たな機能

このリリースの主な変更点 (とりわけ現在 0.91 リリースを使っている開発者にとっ て重要な変更点) は、 ‘magic-removal’ 開発ブランチからマージされた内容に基づ く変更です。このブランチは、オープンソースになる前の初期の Django で決めら れた設計によって課されていた、 Django コードの書き方に対するいくつもの制約 を取り払っています。その結果、より自然でかつ Pythonic な、期待通りに動作す るコードを書けるようになり、背後で起きている「黒魔術」を減らせました。

その他に、このリリースのもうひとつのメインテーマとして、劇的なユーザビリティ の向上があります。このリリースではエラーメッセージやドキュメントなどに数え 切れない程の変更が施され、開発者の QOL を向上させています。

0.95 に採り入れられた新たな機能と変更は以下の通りです:

  • データベースからオブジェクトを取り出すのに、より一貫性のある、自然な フィルタインタフェースを使うようになりました。
  • ユーザ定義モデル、関数、および定数が、それらを定義しているモジュール の名前空間で参照できるようになりました。(以前のバージョンでは、全てが django.models.* という名前空間から黒魔術的に提供されていました。)
  • FlatPage, Sites, Redirects といったオプションのアプリケーションをコア システムから脱カップリングして、 django.contrib に移しました。これら のアプリケーションを使いたくない場合、アプリケーションのデータベース テーブルをインストールしなくてすむようになりました。
  • データベースのトランザクション管理をサポートするようになりました。
  • 認証やユーザ識別バックエンドを自作できるようにし、 LDAP のような別の システムをつかってユーザ認証を行えるようになりました。
  • 新たな「マネジャ」API を介して、モデルに簡単に自作のテーブルレベル関 数を追加できるようにしました。
  • データベースなしで Django を使えるようになりました。簡単に言えば、動 的ページを生成させたいだけなら、データベースを稼働させなくてもフレー ムワークを使えるということです。換言すれば、 URLconf とビューだけの構 成で利用できるということです。以前のバージョンでは、実際にデータベー スを使うかどうかに関わらず、設定を行わねばなりませんでした。
  • モデルの save() や delete() をより明示的かつ自然な方法でオーバライド できるようになり、 pre_save() や post_save() メソッドフックを使わなく てもよくなりました。
  • 環境変数を設定しなくても、フレームワークの個々の部分に対する設定を行 えるようになりました。これにより、例えば Django テンプレートシステム だけを他のアプリケーションで使ったりできるようになりました。
  • 国際化 (i18n) サポートの範囲を広げ、フレームワークの各部を一層国際化 させました。Django のコードベースはテンプレートも含めて翻訳され、31 の言語で少なくとも部分的に翻訳されています。新たにアラブ語、中国語、 ハンガリー語、ウェールズ語で Django admin サイトを使えるようになりま した。

0.91 互換のコードを 0.95 コードベースに移植する際に必要な変更は、場合によっ てはかなりの量になります。とはいえ、そのほとんどは合理的な作業であり、一度 だけやれば済むようなものです。変更に必要な作業は Wiki の Removing The Magic のページに列挙してあります。また、移植作業を準備する 際に必要な チェックリスト のページもあります。

問題の報告と手助けの求め方

Django を使った問題解決で手助けが必要になったときは? 配布物に入っているドキュ メントは Django ウェブサイト から オンラインで 入手できます (訳注: 日本語ドキュメント もあります)。特に、何度も寄せられる質問について回答し ている FAQ ドキュメントを一読するようお勧めします。

より個人的な手助けが必要な場合には、 django-users メーリングリストがあり ます。このリストは非常に活発で、 2,000 を超える読者があらゆる Django に関す る問題解決の手助けをしてくれます。とはいえ、よくある多くの質問にはなにがし かの共通性があり、その名かには既に回答されているものもあるので、まずはアー カイブをチェックするよう勧めます。

最後に、 IRC ですぐ応答をもらいたい人のために、 irc.freenode.net には #django というチャネルがあります。このチャネルには世界中の Django ユーザや 開発者が常に集まっています。気さくな人達がいつもいて、手助けをしてくれたり、 話相手になってくれます。

Django を使ってくれてありがとう!

The Django Team July 2006

開発版のリリース

これらのメモは記録用に作成しています。もし、最新の Django リリースに合わせて更新していれば、これを気にする必要は ありません。公式リリースよりも新しいバージョンの Django を動かしているなら、 このページに注意を払っておくとよいでしょう。もちろん、 新たなバージョンが待ち遠しい人にとっても、楽しく読めますよ。

Django 1.1 RC 1 release notes

July 21, 2009

Welcome to the first Django 1.1 release candidate!

This is the third – and likely last – in a series of preview/development releases leading up to the eventual release of Django 1.1, currently scheduled to take place approximately one week after this release candidate. This release is targeted primarily at developers who are interested in trying out new features and testing the Django codebase to help identify and resolve any critical bugs prior to the final 1.1 release.

As such, this release is not yet intended for production use, and any such use is discouraged.

What’s new in Django 1.1 RC 1

The Django codebase has – with one exception – been in feature freeze since the first 1.1 beta release, and so this release candidate contains only one new feature (see below); work leading up to this release candidate has instead been focused on bugfixing, particularly on the new features introduced prior to the 1.1 beta.

For an overview of those features, consult the Django 1.1 beta release notes.

URL namespaces

The 1.1 beta release introduced the ability to use reverse URL resolution with Django’s admin application, which exposed a set of named URLs. Unfortunately, achieving consistent and correct reverse resolution for admin URLs proved extremely difficult, and so one additional feature was added to Django to resolve this issue: URL namespaces.

In short, this feature allows the same group of URLs, from the same application, to be included in a Django URLConf multiple times, with varying (and potentially nested) named prefixes which will be used when performing reverse resolution. For full details, see the documentation on defining URL namespaces.

Due to the changes needed to support this feature, the URL pattern names used when reversing admin URLs have changed since the 1.1 beta release; if you were developing applications which took advantage of this new feature, you will need to update your code to reflect the new names (for most purposes, changing admin_ to admin: in names to be reversed will suffice). For a full list of URL pattern names used by the admin and information on how namespaces are applied to them, consult the documentation on reversing admin URLs.

The Django 1.1 roadmap

As of this release candidate, Django 1.1 is in both feature freeze and “string freeze” – all strings marked for translation in the Django codebase will retain their current form in the final Django 1.1 release. Only critical release-blocking bugs will receive attention between now and the final 1.1 release.

If no such bugs are discovered, Django 1.1 will be released approximately one week after this release candidate, on or about July 28, 2009.

What you can do to help

In order to provide a high-quality 1.1 release, we need your help. Although this release candidate is, again, not intended for production use, you can help the Django team by trying out this release candidate in a safe testing environment and reporting any bugs or issues you encounter. The Django ticket tracker is the central place to search for open issues:

Please open a new ticket only if no existing ticket corresponds to a problem you’re running into.

Additionally, discussion of Django development, including progress toward the 1.1 release, takes place daily on the django-developers mailing list:

... and in the #django-dev IRC channel on irc.freenode.net. If you’re interested in helping out with Django’s development, feel free to join the discussions there.

Django’s online documentation also includes pointers on how to contribute to Django:

Contributions on any level – developing code, writing documentation or simply triaging tickets and helping to test proposed bugfixes – are always welcome and appreciated.

Django 1.1 beta 1 release notes

March 23, 2009

Welcome to Django 1.1 beta 1!

This is the second in a series of preview/development releases leading up to the eventual release of Django 1.1, currently scheduled to take place in April 2009. This release is primarily targeted at developers who are interested in trying out new features and testing the Django codebase to help identify and resolve bugs prior to the final 1.1 release.

As such, this release is not intended for production use, and any such use is discouraged.

What’s new in Django 1.1 beta 1

See also

The 1.1 alpha release notes, which has a list of everything new between Django 1.0 and Django 1.1 alpha.

Model improvements

A number of features have been added to Django’s model layer:

“Unmanaged” models

You can now control whether or not Django creates database tables for a model using the managed model option. This defaults to True, meaning that Django will create the appropriate database tables in syncdb and remove them as part of reset command. That is, Django manages the database table’s lifecycle.

If you set this to False, however, no database table creating or deletion will be automatically performed for this model. This is useful if the model represents an existing table or a database view that has been created by some other means.

For more details, see the documentation for the managed option.

Proxy models

You can now create proxy models: subclasses of existing models that only add Python behavior and aren’t represented by a new table. That is, the new model is a proxy for some underlying model, which stores all the real data.

All the details can be found in the proxy models documentation. This feature is similar on the surface to unmanaged models, so the documentation has an explanation of how proxy models differ from unmanaged models.

Deferred fields

In some complex situations, your models might contain fields which could contain a lot of data (for example, large text fields), or require expensive processing to convert them to Python objects. If you know you don’t need those particular fields, you can now tell Django not to retrieve them from the database.

You’ll do this with the new queryset methods defer() and only().

New admin features

Since 1.1 alpha, a couple of new features have been added to Django’s admin application:

Editable fields on the change list

You can now make fields editable on the admin list views via the new list_editable admin option. These fields will show up as form widgets on the list pages, and can be edited and saved in bulk.

Admin “actions”

You can now define admin actions that can perform some action to a group of models in bulk. Users will be able to select objects on the change list page and then apply these bulk actions to all selected objects.

Django ships with one pre-defined admin action to delete a group of objects in one fell swoop.

Testing improvements

A couple of small but very useful improvements have been made to the testing framework:

  • The test Client now can automatically follow redirects with the follow argument to Client.get() and Client.post(). This makes testing views that issue redirects simpler.
  • It’s now easier to get at the template context in the response returned the test client: you’ll simply access the context as request.context[key]. The old way, which treats request.context as a list of contexts, one for each rendered template, is still available if you need it.
Conditional view processing

Django now has much better support for conditional view processing using the standard ETag and Last-Modified HTTP headers. This means you can now easily short-circuit view processing by testing less-expensive conditions. For many views this can lead to a serious improvement in speed and reduction in bandwidth.

Other improvements

Finally, a grab-bag of other neat features made their way into this beta release, including:

  • The dumpdata management command now accepts individual model names as arguments, allowing you to export the data just from particular models.
  • There’s a new safeseq template filter which works just like safe for lists, marking each item in the list as safe.
  • Cache backends now support incr() and decr() commands to increment and decrement the value of a cache key. On cache backends that support atomic increment/decrement – most notably, the memcached backend – these operations will be atomic, and quite fast.
  • Django now can easily delegate authentication to the web server via a new authentication backend that supports the standard REMOTE_USER environment variable used for this purpose.
  • There’s a new django.shortcuts.redirect() function that makes it easier to issue redirects given an object, a view name, or a URL.
  • The postgresql_psycopg2 backend now supports native PostgreSQL autocommit. This is an advanced, PostgreSQL-specific feature, that can make certain read-heavy applications a good deal faster.

The Django 1.1 roadmap

Before Django 1.1 goes final, at least one other preview/development release will be made available. The current schedule consists of at least the following:

  • Week of April 2, 2009: Django 1.1 release candidate. At this point all strings marked for translation must freeze to allow translations to be submitted in advance of the final release.
  • Week of April 13, 2009: Django 1.1 final.

If deemed necessary, additional beta or release candidate packages will be issued prior to the final 1.1 release.

What you can do to help

In order to provide a high-quality 1.1 release, we need your help. Although this beta release is, again, not intended for production use, you can help the Django team by trying out the beta codebase in a safe test environment and reporting any bugs or issues you encounter. The Django ticket tracker is the central place to search for open issues:

Please open new tickets if no existing ticket corresponds to a problem you’re running into.

Additionally, discussion of Django development, including progress toward the 1.1 release, takes place daily on the django-developers mailing list:

... and in the #django-dev IRC channel on irc.freenode.net. If you’re interested in helping out with Django’s development, feel free to join the discussions there.

Django’s online documentation also includes pointers on how to contribute to Django:

Contributions on any level – developing code, writing documentation or simply triaging tickets and helping to test proposed bugfixes – are always welcome and appreciated.

Development sprints for Django 1.1 will also be taking place at PyCon US 2009, on the dedicated sprint days (March 30 through April 2), and anyone who wants to help out is welcome to join in, either in person at PyCon or virtually in the IRC channel or on the mailing list.

Django 1.1 alpha 1 release notes

February 23, 2009

ようこそ Django 1.1 alpha 1へ!

これが Django 1.1 の2009年4月にする通常のリリースに追いつくまでの開発版です。 このリリースが基本的にターゲットとしているのは、新しい機能を試したり、 1.1 のリリース前にDjangoのコードベースでバグを見つけたり解消することに興味を 抱いている人たちです。

そのため、このリリースは 正式なサポートが含まれていないため、そのような 使い方には向きません

Django 1.1 アルファ 1 で新しくなったこと

ORM の改善

Django のオブジェクトリレーショナルマッパー(ORM)に二つほど大きな機能が 追加されました。

アグリゲートのサポート

SQL のアグリゲート( aggregate )、( COUNT(), MAX(), MIN() など) が Django の ORM で使えるようになりました。直接アグリゲートの結果を 返すか、それとも アグリゲートしたクエリの結果と QuerySet の中のオブジェクトを添えることもできます。

この機能は新しい QuerySet.aggregate()`() で使うか、 QuerySet.annotate()`() メソッドで使えます。詳しくは、 the ORM アグリゲーションのドキュメント を見てください。

クエリの表現

クエリは別のフィールドを参照することも、関係するモデルのフィールドへ 関係性をまたいで参照することも出来ます。この機能は新しい F オブジェクトで実装されています、詳しくは、 F 表記のドキュメント を 見てください。

パフォーマンスの改善

Django の テストフレームワーク を使って書かれた テストは、劇的に早くなりました。(沢山のケースで、 10倍ほど早くなっています)

これは、トランザクションベースドテストの解説のなかで達成されています。 django.test.TestCase を使う時に、テストはトランザクションの中で 走っています、トランザクションはテスト終了時にロールバックされます、 データベースのフラッシュとリポピュレートする代わりにこれを行います。 この結果は莫大なスピードアップをほとんどの種類のユニットテストにもたらします。 TestCaseTransactionTestCase のドキュメントを見てくださ い。詳しい解説とデータベースサポートについての重要な情報が載っています。

その他の進歩

Django 1.0 からの、その他の新しい機能と変更は:

  • CSRF プロテクションミドルウェア は二つのクラスに 分割されました。 CsrfViewMiddleware は入ってくるリクエストをチェック します。 CsrfResponseMiddleware プロセスは返すレスポンスを扱います。 CsrfMiddleware クラス (上記両方機能を果たします)は、 後方互換性のために残しています。しかし、分割したクラスを使うことが推奨 されています。それは、 CSRF プロセスが何時、どこで生じるかをきめ細やかに コントロールすることが出来るからです。
  • reverse() とコードを使う(すなわち、 {% url %} テンプレートタグのことです)と、今は Django の管理サイト の URL と一緒に動きます、管理 URL は include(admin.site.urls) に よって提供されています(アドミンへのリクエストを送るための admin.site.root ビューはまだ動作します、しかしアドミンの URL がこの方法で構成されていると ” reverse 関数で引き戻せません”)
  • Django の URLConf モジュールは、include() 関数はモジュール名に加えて、 URL パターンのシークエンスも受け付けられます(それは、 patterns() で生成 されます)
  • Django フォームのインスタンス( フォームの概要 を見てください。二つのメソッド hidden_fields() と、 visible_fields() が追加されました、これらは非表示のリストが返され、すなわち <input type="hidden"> です、加えてフォームの非表示でないフィールドも 返します。
  • redirect_to 汎用ビュー( 汎用ビューのドキュメント を見てください)は、 追加としてキーワード引数 permanent を受け取れるようになりました。 もし、 permanentTrue ならばビューは HTTP 恒久的な転送 をします(ステータスコードは 301です)。もし、 False ならば、 ビューは HTTP 一時的な転送をします。(ステータスコード は302 です)
  • 新しいデータベースの照合の種類として week_dayDateField と、 DateTimeField に加えられました。この参照のタイプは数字 1(日曜日)から7(土曜日)までを受け取り、フィールドの値がマッチする 週の日付がオブジェクトを返します。 照合種類のフルリスト に詳細があります。
  • Django のテンプレート言語の {% for %} タグはオプションとして、 {% empty %} 句を扱えるようになりました。これは、 {% for %} のループが空っぽになった時に表示されるものです。 組み込みのテンプレートタグのリスト に、これの例が載っています。

Django 1.1 のロードマップ

Django 1.1 の最後のアップデートを迎える前に、幾つか、他の開発版のリリースが 利用できます。最新スケジュールはこのようになっています。

  • 2009年 3月20日 に、 Django 1.1 のベータ1 が “機能が固まり” ます。: 何も新しい機能がこの時点から追加されません、新しい機能は Django 1.2 に延期されます。
  • 2009年 4月2日 には、 Django 1.1 リリースの候補日でっす。この時点で、 全ての翻訳する文字列がマークされ、最終リリースに先立って翻訳がなされる ことを決定します。
  • 2009年4月13日 には、 Django 1.1 の最終版です。

必要ならば、アルファ版もこれに追加されます、ベータやリリース候補日の決定は 1,1 の最終リリースより先に発表します。

Django の助けになるには何ができるか

1.1 が高い質のものとして提供されるために、私たちは助けが必要です。 だけれど、これはアルファ版なので 正式なものとしての使用は意図して いません Django の開発チームを助けるためには、アルファ版を安全な テスト環境で使うことと、バグや発見した問題をレポートすることです。 Django のチケットトラッカーは中央の場所でオープンになっているイシュー を見つけられます。

あなたが Django を使っていて生じた問題が、存在するチケットによって解決 するものでなさそうだったら、新しいチケットをオープンしてください。

加えて、 Django の開発ディスカッションも 1.1 のリリースへ向けたプロセスの 一部で、 Django のデベロッパーメーリングリストにて日々行われています。

... そして、 irc.freenode.net#django-dev IRCチャンネルで Django の開発を助けたいと思ったら、ぜひディスカッションに加わってくだ さい。

Django のオンラインドキュメントも、どうやって Django に貢献すればよいかを 指し示してくれます。

  • Django へどうやって貢献するか

どのレベルで貢献するか、開発版のコードでも、ドキュメントを書くのでもチケット を報告するのでもバグの修正のためにテストをするのでも、いつでも Django は あなたたちを歓迎し、そしてありがたく思っています。

Django 1.1 の開発スプリントは PyCon US 2009 でも行われます、スプリントの 日は(3月30日から4月2日)誰でも加われます。また、 IRC チャンネルかメーリング リストでヴァーチャルに参加することもできます。

Django 1.0 beta 2 リリースノート

revision-up-to:17812 (1.4)

Django 1.0 beta 2 にようこそ!

このリリースは、来るべき Django 1.0 リリースにつながる 4 番目のプレビュー/ 開発者向けリリースです。1.0 のリリースは 9 月初頭を予定しています。このリリー スでは、主に Django のコードベースをテストしたい開発者や、 1.0 の最終リリー スに向けてバグ修正を手伝う開発者をターゲットにしています。

従って、このリリースは実運用向きでは ありません 。くれぐれも実運用の目的 では使わないでください。

Django 1.0 beta 2 で新たに登場した機能

ここ数年、我々は Django の trunk ソースツリーでほぼずっと活発に開発を続け、 0.96 リリース以降、大きな機能をいくつも投入してきました。 Django 1.0 alpha 1 で新たに登場した機能は、 1.0 alpha 1 リリースノート を参照してください。 Django 1.0 alpha 2 で新たに登 場した機能は、 1.0 alpha 2 リリースノート を 参照してください。 Django 1.0 beta 1 で新たに登場した機能は、 1.0 beta 1 リリースノート を参照してください。

このベータリリースでは、以下の主な機能を追加しました:

django.contrib.comments のリファクタ
Google Summer of Code プロジェクトの一環として、 Thejaswi Puthraya が Django にバンドルされているコメントシステムを大幅にリライト/リファ クタし、フレキシビリティとカスタマイズ性をすばらしく向上させました。 詳細なドキュメント と、以前のコメン トアプリケーションを使っていた人のための アップグレードガイド も読めるように なりました。
ドキュメントのリファクタ
Django にバンドルされているオンラインドキュメントを大々的にリファクタし ました。新たなドキュメントでは、 Sphinx を使ってドキュメントをビルド し、トピックごとのインデクスやドキュメント内の相互参照を生成します。 新しいドキュメントは オンライン で参照できるほか、 Sphinx をインストールしていれば、 Django にバンドルされているファイルだけで HTML を自分で生成できます。

新しい機能にに加え、 Django チームは 1.0 リリースに向けてコードベースの整理 に懸命に取り組んでいます。このベータリリースには、 1.0 に到達するための膨大 な数の改善やバグフィクスが入っています。

また、古い機能の撤廃作業の一環として、 Django の古いフォーム処理システムを 除去しました。 django.oldforms はなくなり、 (自動マニピュレータなどの) 様々な API フックも除去されました。フォームは django.forms新 しいフォーム処理システム と完全に入れ替わりました。

Django 1.0 のロードマップ

この beta リリースの主要な目的の一つは、 Django 1.0 に実装する予定の機能 のうち、まだ終っていないものや、最終リリースまでに修正しておかねばならない バグを見極めることです。この beta リリースの時点で、 1.0 に搭載する機能を 最終的に「凍結」します。今後の機能追加リクエストは将来のリリースに持ち越し、 開発活動をバグフィクスと安定性の向上だけに集中します。また、この時点で Django のコードベース内で翻訳対象にマークしている文字列全てをフリーズし、 翻訳作業の貢献者が 1.0 の最終リリースにバンドルする翻訳ファイルをチェック して修正できるようにします。このリリースに続いて、ロンドンとオンラインで 2008 年 8 月 30 日に開発スプリントを実施します。スプリントの目的は、 2008 年 9 月 2 日 予定の 1.0 リリースに向けて、可能な限りバグを潰すこと にあります。また、 Django 1.0 の公式リリースパーティを、 9 月 6,7 にマウン テンビューで開催される DjangoCon で開催する予定です。

リリース作業で手伝えること

高い品質の 1.0 リリースを提供するために、皆さんの手助けが必要です。先にも述 べたように、この beta リリースは実運用向けでは ありません 。安全なテスト 環境で使ってみて、バグや問題を見付けたら Django の開発チームに報告してくだ さい。自分の発見した問題がすでに明らかでないか、 Django のチケットトラッカ を使って探してください:

発見した問題に対応するチケットが見付からなければ、新たなチケットをオープン してください。

また、 1.0 リリースに向けての進捗を含め、 Django の開発に関する議論は、 django-developers メーリングリスト:

と、IRC サーバ irc.freenode.net#django-dev チャネルで常時行って います。 Django の開発を手伝いたいのなら、ぜひ参加して、議論に加わってくだ さい。

Django プロジェクトへの貢献方法は、オンラインドキュメントにも記載しています:

  • Django に貢献する

コードの開発、ドキュメントの作成、そしてチケットのトリアージや、誰かの提出 したバグフィクスのテストなど、どんなレベルの貢献でも歓迎します。

Django 1.0 beta 1 リリースノート

revision-up-to:8961 (1.0)

Django 1.0 beta 1 にようこそ!

このリリースは、来るべき Django 1.0 リリースにつながる 3 番目のプレビュー/ 開発者向けリリースです。1.0 のリリースは 9 月初頭を予定しています。このリリー スでは、主に Django のコードベースをテストしたい開発者や、 1.0 の最終リリー スに向けてバグ修正を手伝う開発者をターゲットにしています。

従って、このリリースは実運用向きでは ありません 。くれぐれも実運用の目的 では使わないでください。

Django 1.0 beta 1 で新たに登場した機能

ここ数年、我々は Django の trunk ソースツリーでほぼずっと活発に開発を続け、 0.96 リリース以降、大きな機能をいくつも投入してきました。 Django 1.0 alpha 1 で新たに登場した機能は、 1.0 alpha 1 リリースノート を参照してください。 Django 1.0 alpha 2 で新たに登 場した機能は、 1.0 alpha 2 リリースノート を 参照してください。

この beta リリースでは主要な新機能は追加していませんが、変更点や改良点がい くつかあります:

forms と admin への一般化リレーションの組み込み
一般化リレーションのクラスを django.contrib.contenttypes に移し、 admin インタフェースやエンドユーザのフォームでもサポートしました。 詳しくは 一般化リレーションのドキュメント を参照してください。
admin のフレキシビリティ向上
1.0 alpha で行った Django の admin インタフェース (django.contrib.admin) のリファクタリングに続いて、2 つのフックを追 加し、admin でモデルインスタンスを操作するときに pre-svave および post-save 処理をカスタマイズできるようにしました。詳しくは admin のドキュメント を参照してください。
INSERT/UPDATE の使い分け
Django で save() メソッドを呼び出したとき、SQL レベルで INSERTUPDATE のどちらを使うかの区別は、ほとんどの場合デフォルトの挙動 で問題ありませんが、たまにどちらかを強制的に用いたほうがよい場合があり ます。そこで、モデルの save() にパラメタを追加して、実行する SQL を 強制できるようにしました。詳細と、パラメタを使うときの重要な注意点を、 データベース API のドキュメントに記載してあります。
CacheMiddleware の分割
Django の CacheMiddleware を 3 つのクラスに分割しました。 CacheMiddleware 自体はまだあり、以前の機能をそのまま残していますが、 実際には二つの別々のミドルウェア (キャッシュにデータを入れるミドルウェ アと、キャッシュからデータを取り出すミドルウェア) からなっていて、一つ のミドルウェアにまとまっていると起きる問題を回避できます。正しい使い方 などの詳細は:doc:キャッシュのドキュメント </topics/cache> に記載してい ます。
撤廃された機能の除去
以前のバージョンで撤廃した機能としてマークしていた機能や、 1.0 のリリー スに先だって除去を予定していた機能を Django から取り去りました。除去し た機能には、import パス django.newforms (django.forms で import できます) や form_for_model, form_for_instance といったヘルパ関 数 (ModelForm に置き換わりました)、そしてディスパッチャやファイルアッ プロード、ファイルストレージリファクタリングなどで置き換えられた機能な どがあります。詳しいリストや、その他互換性のない変更は Django の wiki にあります。

その他にも、 MySQL のコレーションを変更したときの大小文字の区別のようなトリッ キーなケースの解決や、 Windows のパッケージやインストールに関する改善、 Django に一意なセッション識別子を生成させるメソッドの頑健化など、たくさんの 改良やバグフィクスが入っています。

Django 1.0 のロードマップ

この beta リリースの主要な目的の一つは、 Django 1.0 に実装する予定の機能 のうち、まだ終っていないものや、最終リリースまでに修正しておかねばならない バグを見極めることです。このリリースの後、ベータリリースとリリース候補版に 向けて一連のスプリントを実施し、すぐに Django 1.0 をリリースします。タイム ラインは以下のように計画しています:

  • 2008 年 8 月 15 日: スプリント (米国 Texas 州 Austin とオンラインで)
  • 2008 年 8 月 17 日: Sprint (イスラエル Tel Aviv とオンラインで)
  • 2008 年 8 月 21 日: Django 1.0 release candidate 1. この時点で、 Django のコードベース内で翻訳対象にマークしている文字列全てをフリーズし、 翻訳作業の貢献者が 1.0 の最終リリースにバンドルする翻訳ファイルをチェック して修正できるようにします。
  • 2008 年 8 月 22 日: Sprint (米国 Oregon 州 Portland とオンラインで)
  • 2008 年 8 月 22 日: Sprint (米国 Oregon 州 Portland とオンラインで)
  • 2008 年 8 月 26 日: Django 1.0 release candidate 2.
  • 2008 年 8 月 30 日: Sprint (英国 England, London とオンラインで)
  • 2008 年 9 月 2 日: Django 1.0 final リリース。 9 月 6,7 にマウンテン ビューで開催される DjangoCon で、 Django 1.0 リリースパーティ。

もちろん、予定のタイムラインなので、状況によって変更する可能性もあります。 最新情報は Django プロジェクトの wiki に掲載します:

リリース作業で手伝えること

高い品質の 1.0 リリースを提供するために、皆さんの手助けが必要です。先にも述 べたように、この beta リリースは実運用向けでは ありません 。安全なテスト 環境で使ってみて、バグや問題を見付けたら Django の開発チームに報告してくだ さい。自分の発見した問題がすでに明らかでないか、 Django のチケットトラッカ を使って探してください:

発見した問題に対応するチケットが見付からなければ、新たなチケットをオープン してください。

また、 1.0 リリースに向けての進捗を含め、 Django の開発に関する議論は、 django-developers メーリングリスト:

と、IRC サーバ irc.freenode.net#django-dev チャネルで常時行って います。 Django の開発を手伝いたいのなら、ぜひ参加して、議論に加わってくだ さい。

Django プロジェクトへの貢献方法は、オンラインドキュメントにも記載しています:

  • Django に貢献する

コードの開発、ドキュメントの作成、そしてチケットのトリアージや、誰かの提出 したバグフィクスのテストなど、どんなレベルの貢献でも歓迎します。

Django 1.0 alpha 2 リリースノート

revision-up-to:17812 (1.4)

Django 1.0 alpha 2 にようこそ!

このリリースは、来るべき Django 1.0 リリースにつながる 2 番目のプレビュー/ 開発者向けリリースです。1.0 のリリースは 9 月初頭を予定しています。このリリー スでは、主に Django のコードベースをテストしたい開発者や、 1.0 の最終リリー スに向けてバグ修正を手伝う開発者をターゲットにしています。

従って、このリリースは実運用向きでは ありません 。くれぐれも実運用の目的 では使わないようにしてください。

Django 1.0 alpha 2 で新たに登場した機能

ここ数年、我々は Django の trunk ソースツリーでほぼずっと活発に開発を続け、 0.96 リリース以降、大きな機能をいくつも投入してきました。 Django 1.0 alpha 1 で新たに登場した機能は、 1.0 alpha 1 リリースノート を参照してください。 1.0 alpha 1 以降に追加された機能を以下に示します:

django.contrib.gis (GeoDjango)
1 年にわたる開発を経て、ワールドクラスの GIS (地理情報システム: Geographic Information Systems) のサポートを contrib アプリケー ションの形で Django に追加しました。 GIS のドキュメント はまだメンテナンス中で、 1.0 の最終リリースまでに Django のメインドキュメントにマージする予定で す。この機能を作り上げ、完成までこぎつけた Justin Bronn, Jeremy Dunck, Brett Hoerner そして Travis Pinney に深く感謝します。
プラガブルなファイルストレージ機構
Django 組み込みの FileFieldImageField は、プラガブルなファ イルストレージバックエンドを使えるようになりました。ストレージバックエ ンドによって、アップロードファイルを Django に保存する方法を徹底的にカ スタマイズできます。詳しくは、 ファイルのドキュメント を参照してください。この困難な仕事を達成した Marty Alchin に深く感謝します。
Jython との互換性
Google Summer of Code プロジェクトを通じて多大な貢献をもたらした Leo Soto に感謝します。彼は Django のコードベースをリファクタし、これま で Jython との互換性を妨げていた部分を除去しました。 Jython はJava で書かれた Python 実装で、 Java 仮想マシンで Python コードを実行できま す。 Django はまもなく登場する Jython 2.5 リリースで動作します。

他にも、このリリースでたくさんの機能追加や改良を行いました。その中でも、2 つのパフォーマンス改善があります。一つは、 Django の国際化システム で翻訳対象にマークした文字列のメモリ消費を低減したこと、もう 一つは、リクエスト/レスポンスの処理中や、オブジェクト-リレーショナルマッパ を扱うときに頻繁に呼び出される Django の内部ディスパッチャを劇的に高速化し たことです。

Django 1.0 のロードマップ

この alpha リリースの主要な目的の一つは、 Django 1.0 に実装する予定の機能 のうち、まだ終っていないものや、最終リリースまでに修正しておかねばならない バグを見極めることです。このリリースの後、ベータリリースとリリース候補版に 向けて一連のスプリントを実施し、すぐに Django 1.0 をリリースします。タイム ラインは以下のように計画しています:

  • 2008 年 8 月 14 日: Django 1.0 beta リリース この時点で、1.0 に向けて の機能フリーズを行います。以後はバグフィクスと安定化に専念します。
  • 2008 年 8 月 15 日: スプリント (米国 Texas 州 Austin とオンラインで)
  • 2008 年 8 月 17 日: Sprint (イスラエル Tel Aviv とオンラインで)
  • 2008 年 8 月 21 日: Django 1.0 release candidate 1. この時点で、 Django のコードベース内で翻訳対象にマークしている文字列全てをフリーズし、 翻訳作業の貢献者が 1.0 の最終リリースにバンドルする翻訳ファイルをチェック して修正できるようにします。
  • 2008 年 8 月 22 日: Sprint (米国 Oregon 州 Portland とオンラインで)
  • 2008 年 8 月 26 日: Django 1.0 release candidate 2.
  • 2008 年 8 月 30 日: Sprint (英国 England, London とオンラインで)
  • 2008 年 9 月 2 日: Django 1.0 final リリース。 9 月 6,7 にマウンテン ビューで開催される DjangoCon で、 Django 1.0 リリースパーティ。

もちろん、予定のタイムラインなので、状況によって変更する可能性もあります。 最新情報は Django プロジェクトの wiki に掲載します:

リリース作業で手伝えること

高い品質の 1.0 リリースを提供するために、皆さんの手助けが必要です。先にも述 べたように、この alpha リリースは実運用向けでは ありません 。安全なテスト 環境で使ってみて、バグや問題を見付けたら Django の開発チームに報告してくだ さい。自分の発見した問題がすでに明らかでないか、 Django のチケットトラッカ を使って探してください:

発見した問題に対応するチケットが見付からなければ、新たなチケットをオープン してください。

また、 1.0 リリースに向けての進捗を含め、 Django の開発に関する議論は、 django-developers メーリングリスト:

と、IRC サーバ irc.freenode.net#django-dev チャネルで常時行って います。 Django の開発を手伝いたいのなら、ぜひ参加して、議論に加わってくだ さい。

Django プロジェクトへの貢献方法は、オンラインドキュメントにも記載しています:

  • Django に貢献する

コードの開発、ドキュメントの作成、そしてチケットのトリアージや、誰かの提出 したバグフィクスのテストなど、どんなレベルの貢献でも歓迎します。

Django 1.0 alpha リリースノート

revision-up-to:17812 (1.4)

Django 1.0 alpha にようこそ!

このリリースは、来るべき Django 1.0 リリースにつながる最初のプレビュー/開 発者向けリリースです。1.0 のリリースは 9 月初頭を予定しています。このリリー スでは、主に Django のコードベースをテストしたい開発者や、 1.0 の最終リリー スに向けてバグ修正を手伝う開発者をターゲットにしています。

従って、このリリースは実運用向きでは ありません 。くれぐれも実運用の目的 では使わないようにしてください。

Django 1.0 alpha で新たに登場した機能

ここ数年、我々は Django の trunk ソースツリーでほぼずっと活発に開発を続け、 0.96 リリース以降、大きな機能をいくつも投入してきました。その中でも重要なも のを以下に示します:

admin アプリケーションのリファクタ (newforms-admin)

Django の管理インタフェース (django.contrib.admin) を完全にリファク タしました。admin の定義を完全にモデル定義から脱カップリングし (モデル から class Admin をなくしました!)、Django の新たなフォーム処理ライ ブラリ (0.96 から登場した django.newforms で、今後は単に django.forms) を使うよう、 admin のフレームワークを 書き直しました。 また、思い通りに拡張したりカスタマイズしたりできるようになりました。 admin アプリケーションのドキュメントは、以下の Django 標準ドキュメント:

admin インタフェース

にあります。

Unicode 処理の改善

Django の内部処理を、一貫して Unicode を使うようリファクタしました。 これにより、非西欧圏のコンテンツやデータの扱い劇的に単純化しました。 また、サードパーティライブラリや、Unicode を行儀よく扱えないことのある システムとの相互運用を楽にするためのユーティリティも提供しました。 詳細は、 Django の Unicode 処理ドキュメント:

Unicode リファレンス

にあります。

Django ORM の改善

Django のオブジェクト-リレーショナルマッパ、つまり Django のモデルクラ スとデータベースを対応づけ、クエリの発行を仲立ちするためのコンポーネン トを、徹底的なリファクタによって劇的に改善しました。ほとんどの Django ユーザにとって、この変更による互換性の問題はありません。データベースを 操作している公開の API に細かい変更がありましたが、ほとんどの変更は ORM の内部コードに対して施されています。このリファクタのもたらす、以前のバー ジョンと互換性のない変更や新たな機能は、 Django の wiki ページ:

に掲載しています。

テンプレート変数の自動エスケープ
クロスサイトスクリプティング (XSS) 脆弱性に対する安全性をより高めるため に、 Django のテンプレートシステムが全ての変数出力を自動的に HTML エス ケープするよう変更しました。この挙動はもちろん変更でき、変数やテンプレー トの一部を「安全:safe」(エスケープ不要) や「安全でない:unsafe」(エスケー プが必要) にマークできます。この機能の詳しい説明は、 autoescape タグのドキュメントにあります。

他にも、新しい機能やバグフィクス、以前のバージョンからある機能に対する改善 がいくつもあります。 例えば newforms ライブラリには大々的な改良を行いま したが、その中で、様々なフォーム処理の実装を補ったり土台になったりする便利 なアドオンをいくつも django.contrib に追加しました。また、ファイルのアッ プロードハンドラをリファクタし、より細かなアップロードプロセス制御を可能に すると同時に、巨大なファイルのストリーミングに対応しました。

こうした改善や機能追加の一方で、各機能の刷新と、1.0 リリースに向けた API の 確定に伴って、以前のバージョンと互換性のない変更をフレームワークに対してい くつも行っています。こうした変更に対する詳しいガイドは最終的な Django 1.0 リリースに含めて読めるようにします。また、アップグレードを始めたり、テスト したりしたい人のために、以前のバージョンと互換性のない変更の全容を Django の wiki ページにまとめています:

Django 1.0 のロードマップ

この alpha リリースの主要な目的の一つは、 Django 1.0 に実装する予定の機能 のうち、まだ終っていないものや、最終リリースまでに修正しておかねばならない バグを見極めることです。このリリースの後、ベータリリースとリリース候補版に 向けて一連のスプリントを実施し、すぐに Django 1.0 をリリースします。タイム ラインは以下のように計画しています:

  • 2008 年 8 月 1 日: スプリント (Washington, DC とオンラインで)
  • 2008 年 8 月 5 日: Django 1.0 beta 1 リリース。同時に、 1.0 に向けての機 能フリーズを行います。 1.0 に搭載する機能は、この時点で trunk 内での作業 を終えなければなりません。
  • 2008 年 8 月 8 日: スプリント (Lawrence, KS とオンラインで)
  • 2008 年 8 月 12 日: Django 1.0 beta 2 リリース。
  • 2008 年 8 月 15 日: スプリント (Austin, TX とオンラインで)
  • 2008 年 8 月 19 日: Django 1.0 release candidate 1.
  • 2008 年 8 月 22 日: スプリント (Portland, OR とオンラインで)
  • 2008 年 8 月 26 日: Django 1.0 release candidate 2.
  • 2008 年 9 月 2 日: Django 1.0 final リリース。 9 月 6,7 にマウンテンビュー で開催される DjangoCon で、 Django 1.0 リリースパーティ。

もちろん、予定のタイムラインなので、状況によって変更する可能性もあります。 最新情報は Django プロジェクトの wiki に掲載します:

リリース作業で手伝えること

高い品質の 1.0 リリースを提供するために、皆さんの手助けが必要です。先にも述 べたように、この alpha リリースは実運用向けでは ありません 。安全なテスト 環境で使ってみて、バグや問題を見付けたら Django の開発チームに報告してくだ さい。自分の発見した問題がすでに明らかでないか、 Django のチケットトラッカ を使って探してください:

発見した問題に対応するチケットが見付からなければ、新たなチケットをオープン してください。

また、 1.0 リリースに向けての進捗を含め、 Django の開発に関する議論は、 django-developers メーリングリスト:

と、IRC サーバ irc.freenode.net#django-dev チャネルで常時行って います。 Django の開発を手伝いたいのなら、ぜひ参加して、議論に加わってくだ さい。

Django プロジェクトへの貢献方法は、オンラインドキュメントにも記載しています:

  • Django に貢献する

コードの開発、ドキュメントの作成、そしてチケットのトリアージや、誰かの提出 したバグフィクスのテストなど、どんなレベルの貢献でも歓迎します。

Django の内部

revision-up-to:11321 (1.1)

ここにあるのは、 Django 自体をハックする人達のためのドキュメントです。 Django の改善を手伝ったり、 Django が舞台裏でやっていることを学んだりしたけ れば、ここにあるドキュメントを読みましょう。

Warning

Django ドキュメントの他のセクションでは、書かれている内容に一定の保証が あります。すなわち、ある API がひとたび公式のドキュメントとして公開され たら、その API は「安定」であるとみなされ、十分妥当な理由がない限り変更 されません。しかし、ここで扱っている API は「内部向け」であり、必要であ れば変更する余地を残しています。

Django プロジェクトに協力するために

revision-up-to:11321 (1.1) unfinished

Django を 使う のを楽しいと思ってもらえたなら、 使い続ける 前にすこし待っ てください。私達は多大な情熱をかけて、ユーザがコミュニティのメンバに貢献で きるよう手助けしています。Django の開発を手伝うにはいくつもの方法があります:

  • Django について blog を書きましょう。私達は知っている限りの全ての Django 関係の blog を コミュニティのページ で配信しています。この ページに登録したい blog があるなら jacob@jacobian.org に連絡してくだ さい。
  • バグ報告や機能に関する要望を チケットトラッカ に提出しましょう。 私達が望んでいるバグ報告の提出方法の詳細は バグの報告 を読んで下さい。
  • 新たな機能を追加したり従来の機能を修正するパッチを提出しましょう。 パッチの提出方法は パッチの提出 を参照してください。
  • django-developers メーリングリストに参加して、 Django をよりよくす るためのアイデアを皆で共有しましょう。どんな提案でも歓迎します。ただ し私達は後ろだてになるコードがないスケールの大きな話には懐疑的です。
  • 他のユーザが提出したパッチのトリアージ (選別) を行います。トリアージ の手順については、後述の チケットのトリアージ を 参照してください。

Django 開発コミュニティに参加するのに必要な知識はこれだけです。このドキュメ ントの残りの部分では、開発コミュニティがどのようになっていて、どうやってバ グを処理しているかについて詳しく説明し、メーリングリストやその他こまごまと した注意点について記述しています。

バグの報告

上手に書かれたバグ報告は 信じられないくらい 役立ちます。とはいえ、バグ追 跡システムでの作業はかなりのオーバヘッドを要するので、チケットトラッカをで きるだけ有意義に使うよう協力してもらえると助かります。特に:

  • 必ず FAQ を読んで、自分の抱えている問題が既知 のものでないか探して下さい。
  • 必ず トラッカを検索 して、自分の抱えている問題がファイルされて いないか探して下さい。
  • 必ず 最初に django-users で質問して、自分の考えていることが バグだということを確認してください。
  • 必ず 完結した、再現可能な、的確なバグ報告を書いて下さい。完全なコー ド断片やテストセットなど、可能な限り多くの情報を含めて下さい。問題に 対する詳細かつ明瞭な説明と、問題を再現するための手順を含めてください。 小さなテストケースでバグを再現できれば最良のバグ報告になります。
  • サポート質問にチケットシステムを 絶対に使わないで下さい。 質問は django-users リストや #django IRC チャネルでお願いします。
  • スケールの大きな機能の提案にチケットシステムを 絶対に使わないで下さい。 Django のコアに関わる大きな変更は、 取り掛かる前に必ず django-developers リストで議論します。
  • “wontfix” にマークされた問題を 絶対に開き直さないで下さい。 “wontfix” マークは決定事項であり、この問題についてはこれ以上修正でき ないか、修正する予定はないのです。納得できなければ、 django-developers で質問してください。
  • 長い議論をチケットシステムで 絶対に行わないで下さい。 チケットシ ステムでは議論のポイントがすぐに失われてしまうからです。チケットの内 容について議論になりそうなときは django-developers に場所を移して 下さい。
  • バグ報告をチケットに登録したこと だけ を django-developers にポス ト しない でください。チケットを登録すると、別のメーリングリスト (django-updates) にメールが送信されます。開発者やトリアージ担当者 はこのメーリングリストを監視しているので、登録したことがすぐ分かるか らです。

セキュリティ問題の報告

セキュリティ問題の報告は security@djangoproject.com にお願いします。このメー リングリスト経験豊かで信頼できる Django 開発者だけが購読でき、アーカイブは 非公開になっています。

Django に脆弱性が発見された場合、私達は以下のように行動します:

  • 報告者に対して、報告を受けとったことと、脆弱性がまもなく修正されるこ とを知らせます。修正までのおおまかなタイムラインを示し、報告者に対し て、アナウンスを行うまでにどのくらいの間この問題を秘密にしておけるか 問い合わせます。
  • 現在のバージョンと、二つ前までのリリースに対するパッチを含む修正版の 開発に必要な期間、他の全ての開発を停止します。
  • 脆弱性と修正版をアナウンスするする日取りを決めます。 パッチを適用する 側と脆弱性を不正利用する側の間の「軍拡競争」を抑えるため、私達はセキュ リティ問題を即座にアナウンスしません。
  • 影響を受けるバージョンの Django を使っているユーザのうち、私達が把握 している人全員に事前に通知します。この通知は個人宛の電子メールで行わ れます。メールには脆弱性に関するドキュメントと該当パッチへのリンク、 そしてこの脆弱性を公式の公開日まで秘密にしておくよう要請する文が入っ ています。
  • あらかじめ決めておいた日取りに基づいて、脆弱性と修正版を公開し、アナ ウンスします。通常は新たなバージョンの Django リリースを意味しますが、 場合によっては現在のリリースに対する単なるパッチになります。

パッチの提出

Django のコードに対するパッチはつねに大歓迎です。実際、パッチつきのバグ報告 は、パッチのないものよりも はるかに 素早く修正されます。

チケットをクレーム(審査請求)する

世界中に何百人ものコントリビュータを擁するようなオープンソースプロジェクト では、コミュニケーションを効率的に進めることで、同じ作業が何度も繰り返され るのを防ぎ、コントリビュータができるだけ効果的に振る舞えるような配慮が重要 です。そのため、コントリビュータがチケットをクレームし、他の開発者たちに、 何らかのバグ報告や機能提案がなされていることを知らせるという方針をとります。

Django プロジェクトに何らかの貢献をしたいと考えていて、 (コード作成能力や、 Django の内部に関する知識、時間的な余裕から) 必要な修正を行えるのなら、以下 のステップに従ってチケットをクレームしてください:

  • チケットシステム上に アカウントを作成 します。
  • 自分の提起したい内容がまだ チケットトラッカ 上になければ、 新たに作成します。
  • 自分の提起したい内容がすでにチケットトラッカ上にあるのなら、そのチケッ トの “Assigned to” セクションを調べて、誰かによってクレーム済みでない か確認してください。 “nobody” になっていれば、そのチケットはクレーム できます。すでに誰かのアカウント名が入っているのなら、他のチケットを 探してクレームするか、その問題に関わっている開発者に連絡をとって、チ ケット解決に手を貸してください。
  • まだログインしていなければ、自分のアカウントでログインしてください。 ログインするには、チケットページの右上にある “Login” をクリックします。
  • チケットをクレームするには、チケットページの下にある、”Accept ticket” の隣のラジオボタンをクリックしてから、 “Submit changes” をクリックします。
チケットをクレームしたら

チケットをクレームした人は、そのチケットが時代おくれにならないよう作業せね ばなりません。チケットに時間を割けないのなら、クレームを解除するか、そもそ もクレームしないようにしてください!

チケットのトリアージ担当者たちは、クレーム済みのチケットを何度も調べて、各々 のチケットに進捗があるかどうか調べます。クレーム状態にあるチケットが進捗し ないまま 1 週間以上過ぎた場合、チケットが独占されつづけないよう、クレームを 解除してほしい旨問い合わせる場合があります。

チケットをクレームしてから、コードを書くまでにしばらく (数日から数週間) かかる場合、何らかのコメントをポストして、その旨を通知してください。更新が なく、進捗レポートの要求に対する返事もない場合、チケットを無効にする場合も あります。まずは連絡第一です!

どのチケットをクレームすべきか

もちろん、わざわざチケットをクレームするまでもない場合もあります。ドキュメ ントのタイプミスや、ほんの数分あれば修正できるような小さなバグの場合には、 チケットのクレームまでする必要はありません。単にパッチを投稿して、そのまま にしておいてください。

パッチ形式
  • Django の コーディングスタイル に従っているか確認してくださ い。

  • svn diff コマンドの返す書式のパッチを提出してください。ただし、コー ドよりも英語で変更点を説明した方がはるかに分かりやすい場合は例外です。 例えばインデントはよくある例です。というのも、コードの違いがインデン トでしかない場合、パッチを読むのはとても大変だからです。

    git diff 形式のパッチでもかまいません。

  • パッチを作るときには、 常に trunk ディレクトリの最上位の階層、 すなわち、 django, docs, tests, AUTHORS などがある場 所で svn diff を実行してください。こうしてパッチを作ったほうが 他の人が適用しやすいからです。

  • チケットトラッカ で、 “attach file” ボタンを使ってチケットにパッチ を添付してください。一行のパッチでないかぎり、チケットの説明やコメン トの中にパッチを 入れないで 下さい。

  • パッチファイルの名前には .diff 拡張子をつけて下さい。そうすること で、チケットトラッカは構文のハイライト強調を正しく行うので助かります。

  • チケットの詳細情報欄にある「パッチ付き」(“Has patch”) ボックスにチェッ クを入れてください。チケットがパッチつきであることが分かりやすくなり、 チケットシステムがそのチケットを パッチつきのチケットのリスト に追 加してくれます。

  • 問題を解決したり機能を追加するためのコードはパッチの重要な部分ですが、 それだけではいけません。よいパッチというものには必ず回帰テストが付属 していて、問題が解決されたことを検証できる (そして将来同様の問題が再 発しないようにできる) ものです。

  • パッチ中のコードが新たな機能や既存の機能に対する変更をもたらす場合、 パッチにはドキュメントも含めてください。

要注意パッチ

「要注意 (non-trivial)」パッチとは、単なるバグフィクスに留まらず、Django に 新たな機能をもたらし、何らかの設計上の判断を迫るようなパッチです。

要注意パッチを提出する場合には、その問題について django-developers で議 論済みであるという証明を含めてください。自分のパッチが要注意パッチかどうか 判断しかねる場合には問い合わせてください。

チケットのトリアージ

残念ながら、 チケットトラッカ に届くバグ報告全てが、上に述べた チケットの要件 を満たしているわけではありません。 パッチの添付されたチケットもたくさんありますが、それら全てが よいパッチ の要件を満たしているわけでもありません。

こうした状況の打開を手助けする一つの方法に、他のユーザが報告したバグのトリ アージ (選別) 作業があります。この作業には献身的なボランティア 2 名が常時携 わっていますが、手助けをしてくれる人は常に歓迎です。

トリアージ作業のワークフローの大半は、チケットの「トリアージ段階 (triage stage)」というフィールドに関わる作業です。このステージとは、あるチケットが ライフサイクルのどの段階にあるかを示す指標です。ステージフラグやその他のフ ラグによって、誰のどんなチケットが処理待ちになっているかがわかります。

百聞は一見にしかずですから、例を挙げて説明しましょう:

Django のチケットワークフロー図

チケット処理の流れには、まず、 2 種類の公認の役割があります:

  • コア開発者: コミット権限を持ち、コードに関する重大な決定や、大部分の コード作成を行う人です。
  • トリアージ担当者: Django コミュニティでの長期にわたる実績を持った信 頼のおけるメンバです。その実績に基づいて、コア開発者はチケット単位の より小規模な決定権を委譲しています。

次に、トリアージ作業には以下の 5 つのステージがあります:

  1. チケットは「未レビュー(unreviewed)」の状態からスタートします。まだだ れもチケットを調べていない状態です。
  2. 「設計判断待ち(design decision needed)」は、「このコンセプトには設計 上の判断が必要」であり、チケットのコメント欄か、 django-developers 上で議論すべきであることを示しています。 設計判断待ちのステップは、原則として機能追加リクエストのチケットにし かありません。ただし、意見や解釈によってはバグと見なされ 得る よう な問題に対して使われる場合もあります。明らかなバグ (クラッシュする、 クエリ結果がおかしい、標準からかけ離れた動作) の場合、このステップは 飛ばして「承認」に進みます。
  3. チケットの内容に従った修正が受け入れられた場合、「承認 (accepted)」 ステージに移行します。このステージは全ての作業が終わった状態です。
  4. チケットは “Someday/Maybe” 状態に移行させられる場合があります。これ は、該当チケットに述べられている内容に対して、素晴らしいパッチが提供 された時点でフレームワークに追加しようと考えていることを示します。こ の状態に移行したチケットの優先度は高くありません。
  5. チケットにパッチが関連づけられている場合 (下記参照)、トリアージ作業 者はパッチをレビューします。パッチの内容が完璧なら、「チェックイン可 (ready for checkin)」にマークされ、コア開発者にパッチをレビューし てチェックすべきであることを知らせます。

ワークフローにはもう 1 つ、一連のフラグがあります。フラグは各チケットを 「チェックイン可」にするために必要な条件のうち、何が満たされていて何が必要 かを示します:

「パッチあり (has patch)」
チケットに パッチ が 添付されていることを示します。 このフラグのついたパッチはトリアージ担当者によってレビューされ、条 件を満たした「よいパッチ」であるかどうか調べられます。
「ドキュメント不足 (needs documentation)」
パッチつきのチケットに対して、ドキュメントが必要であることを示しま す。コードベースに修正をチェックインする条件として、完全なドキュメ ントが必要です。
「テスト不足 (needs tests)」
パッチに単位テストが必要であることを示します。上ど同様、条件として 有効なパッチが必要です。
「パッチに改良の余地あり (patch needs improvement)」
チケットにパッチが 付属している が、チェックインするには修正の余 地があることを示します。パッチが古くてきれいに当てられなくなってし まっている場合や、コードがコーディング基準に従っていないことを示し ます。

チケットは色々な形で解決されます:

「修正済み (fixed)」
パッチが Django に取り込まれ、問題が解決されると、コア開発者はチケッ トを fixed にマークします。
「無効 (invalid)」
チケットの内容が不正確であると判断された場合に使われます。無効扱い は、チケットの報告している問題が何らかのユーザの手違いに起因してい る、 Django に関係ない問題である、あるいは、バグ報告でも機能リクエ ストでもない (例えば、初心者の中にはチケットにサポート質問を書く人 がいます) と判断されたことを示しています。
「修正の予定なし (wontfix)」
修正要求を Django に取り込むのは不適切であると判断した場合、コア開 発者はチケットを wondfix にマークします。 wontfix へのマークは、 通常は django-developer メーリングリストでの議論の末に選択され ることなので、気になる議論があったらぜひ参加してください。
「他のチケットと重複 (duplicate)」
他のチケットで同じ問題がカバーされている場合にはチケットを duplicate にマークします。重複したチケットをクローズして問題解決の ための議論を 1 箇所にまとめ、話を進めやすくするためです。
「再現不能 (worksforme)」
チケットに十分な情報がなく、問題を再現できない場合に使われます。

あるチケットが明らかに誤ってクローズされた – クローズされたチケットで提起 されている問題が依然として生じている場合や、別の問題が生じた場合、あるいは トリアージ作業でミスが起きている – 場合には、そのチケットを再度開いて (reopen)、その理由を記載してください。また、コア開発者が “wontfix” にマーク したチケットを reopen しないでください。

一般コミュニティメンバによるトリアージ

コア開発者やトリアージ担当者がチケットのトリアージ作業で重要な決定を行う一 方で、一般コミュニティのメンバもまた、トリアージ作業に参加できます。 具体的には、以下のようなトリアージ補助があります:

  • 「レビュー待ち」状態のチケットを、「無効」、「再現不能」、「重複」と いった理由でクローズできます。
  • 「レビュー待ち」状態のチケットを、設計判断が必要な場合には「設計判断 待ち」に、明らかなバグの場合には「承認」に昇格させられます。
  • 「テスト不足」「ドキュメント不足」のチケットを修正したり、「パッチあ り」フラグが正しくセットされていないチケットを修正できます。
  • 古いチケットに何も変化がないまま長時間経過している場合、その問題が解 決されているにもかかわらずチケットがクローズされず放置されていないか 調べられます。
  • チケットをクレームしたにもかかわらず、最近動きのないチケットオーナに 連絡して、返事が 1 週間以上ない場合にはチケットのクレームを失効させら れます。
  • チケットの傾向と本質的な問題を分析できます。 Django の特定の部分に対 するバグ報告が集中している場合、コードのリファクタを検討する必要があ ることを示しています。何らかの傾向が見られるのなら、(問題のチケットを 引きあいに出して) django-developers に問題提起してください。

とはいえ、一般コミュニティのメンバがチケットデータベースを操作する際には、 以下の点に気をつけてください:

  • チケットを「修正の予定なし」で閉じては なりません 。チケットの生 死を最終的に決めるのはコア開発者で、それも通常はコミュニティと相談し た後だからです。
  • つづりの間違い修正やドキュメントのリンク修正といった 些細な 変更で ない限り、チケットを「チェックイン可」に昇格させては なりません
  • コア開発者が下した決定を差し戻しては なりません 。議論に納得でき ないのなら、 django-developers にメッセージをポストしてください。
  • 慎重に振る舞ってください。チケットの状態を変更すべきか迷うような場合 には、変更してはなりません。そんな場合には、チケットに自分のコメント を残すか、 django-developers にメッセージをポストしてください。

翻訳の提出と維持

admin サイトやバリデータのエラーメッセージなど、Django は様々な部分で国際化 されており、ユーザの言語設定に従って様々なテキストを表示します。この機能を 実現するために、Django は共通の国際化メカニズムを使っています。国際化メカニ ズムはどのアプリケーションからも利用できます。利用法は i18n のドキュメント で解説しています。

翻訳カタログは世界中の Django ユーザによる貢献でできています。間違った翻訳 や、まだ翻訳存在しない言語に新たな翻訳を追加したい場合は以下のようにします:

  • Django i18n メーリングリスト に参加して自己紹介してください。

  • i18n のドキュメント に従って翻訳を作成してくださ い。カタログの生成には django-admin.py makemessages ツールを使い ます。 Django 全体のカタログを生成する場合、 Django のソースツリーの トップレベルにある django ディレクトリでコマンドを実行してくださ い。

    このツールは、 Django のソースツリー全体を走査して、翻訳対象としてマー クされた文字列を取り出します。メッセージカタログファイルは conf/locale ディレクトリ以下に生成(または更新)されます。 (例えば、 pt-BR ロケールであれば、ファイルは conf/locale/pt-br/LC_MESSAGES/django.po に書き出されます。)

  • django-admin.py compilemessages -l <lang> を実行して、警告がでな いのを確認してください。

  • 上の二つのステップを、 djangojs ドメインに対しても実行してくださ い。 (django-admin.py のコマンドラインに -d djangojs オプショ ンを付加して実行します)

  • 最新の Subversion trunk に対して、 .po ファイルの差分を作成してください。

  • Django のチケットシステムで新しいチケットを作成し、 Component フィー ルドを Translations に設定して、パッチを添付して提出してください。

コードの書き方

コードを書いて Django に取り込みたいなら、以下のコーディング標準に従って下 さい:

  • 特に指定のない限り PEP 8 に従って下さい。

    pep8.py のようなツールを使えば、コーディング標準に従っているかどう かをチェックできます。とはいえ、 PEP 8 はガイドにすぎません。まずは、 周辺のコードのスタイルを尊重してください。

  • インデントにはスペース 4 つを使います。

  • 変数名、関数名、メソッド名には camelCase ではなくアンダースコアを使っ て下さい (たとえば poll.getUniqueVoters ではなく poll.get_unique_voters())。

  • クラス名 (やクラスを返すファクトリ関数) には InitialCaps を使って ください。

  • 国際化の必要な全ての文字列をマークしておいてください。詳しくは i18n ドキュメント を参照してください。

  • docstring 内では、下記のような “action word” を使ってください:

    def foo():
        """
        Calculates something and returns the result.
        """
        pass
    

    以下のような書き方をしてはなりません:

    def foo():
        """
        Calculate something and return the result.
        """
        pass
    
  • コード中に自分の名前を埋め込まないでください。Django プロジェクトでは、 コードの開発者や貢献者の名前がコード中に散逸しないようにするため、 AUTHORS ファイルにまとめて記載するというポリシを採用しています。 ほんのちょっとした変更でないかぎり、ご自分のパッチに AUTHORS への 変更を加えて頂いてもかまいません。

テンプレートの書き方
  • Django テンプレートコード内では、波括弧とタグコンテンツの間に 1 個 (1 個だけ) スペースをいれて下さい。

    [正しい]:

    {{ foo }}
    

    [誤り]:

    {{foo}}
    
ビューの書き方
  • Django のビューを書くときには、最初のパラメタは必ず request とい う名前にしてください。

    [正しい]:

    def my_view(request, foo):
        # ...
    

    [誤り]:

    def my_view(req, foo):
        # ...
    
モデルの書き方
  • フィールド名は全て小文字で、キャメルケース (camelCase のような書き方) はせず、アンダースコアを使います。

    以下のような書き方をします:

    class Person(models.Model):
        first_name = models.CharField(max_length=20)
        last_name = models.CharField(max_length=40)
    

    以下のような書き方をしてはなりません:

    class Person(models.Model):
        FirstName = models.CharField(max_length=20)
        Last_Name = models.CharField(max_length=40)
    
  • class Meta はフィールドの定義を書いた に書きます。また、フィー ルド定義とクラス定義の間には一行空行を入れます。

    以下のように書きます:

    class Person(models.Model):
        first_name = models.CharField(max_length=20)
        last_name = models.CharField(max_length=40)
    
        class Meta:
            verbose_name_plural = 'people'
    

    以下のような書き方をしてはなりません:

    class Person(models.Model):
        first_name = models.CharField(max_length=20)
        last_name = models.CharField(max_length=40)
        class Meta:
            verbose_name_plural = 'people'
    

    以下のような書き方もよくありません:

    class Person(models.Model):
        class Meta:
            verbose_name_plural = 'people'
    
        first_name = models.CharField(max_length=20)
        last_name = models.CharField(max_length=40)
    
  • モデルの内部クラスや標準メソッドの順番は以下のようにします (ただし、 どれも必須ではないので省略してもかまいません):

    • 全てのデータベースフィールド
    • カスタムマネジャのアトリビュート
    • class Meta
    • def __unicode__()
    • def __str__()
    • def save()
    • def get_absolute_url()
    • カスタムのメソッド定義
  • choices をモデルフィールドに定義する場合、選択肢は、各選択項目の タプルからなるタプルで定義します。定義はモデルモジュールの冒頭か、各 モデルクラスのすぐ上に置き、全て大文字の変数名を付けます。例えば以下 のようにします:

    GENDER_CHOICES = (
        ('M', 'Male'),
        ('F', 'Female'),
    )
    

ドキュメントの書き方

私達は、ドキュメントの一貫性と読みやすさをとても重視しています (なんといっ ても、 Django はジャーナリズムの中で生まれましたからね!)

新たな機能のドキュメントを書くには

私達は、ドキュメントをコードと同じように扱います。すなわち、可能な限り改善 を重ねたいと思っているのです。この節では、ドキュメントの書き手に、有意義で エラーの少ないドキュメントの変更方法を説明します。

ドキュメントの変更には、二つの形式があります:

  • 一般的な改善 – タイプミス、誤った内容の修正、明確な文章への修正や、 例題の追加です。
  • 新たな機能説明 – 前回のリリース以降に追加された機能のドキュメントで す。

私達はドキュメントを以下のポリシに従って作成しています:

新たな機能に関するドキュメントを追加する場合、必ず該当機能が開発版の Django でのみ使用可能な旨を明記せねばなりません。ドキュメントの読み手は、 開発版ではなく、最新のリリースを使っていると想定してください。

新しい機能を説明するときには、ドキュメントの先頭に ”.. versionadded:: X.Y” を付加します。オプションで一行コメントを入れることもできます。 ”.. versionadded:: X.Y” の後には必ず空行を入れてください。

一般的な改善や API の変更は、 ”.. versionchanged:: X.Y” ディレクティブで強 調します(フォーマットは versionadded と同じです)。

Django のドキュメントシステム のページには、 詳しい情報が書かれています。ドキュメントを書き始めるまえに、必ず一読してく ださい。

ReST ファイル作成のガイドライン

私達は、 ReST ドキュメントを作成するときに、以下のガイドラインに従っていま す:

  • 章や節の題名では、最初の文字と適切な名前のみ大文字で書きます。
  • ドキュメントは幅 80 文字以内で折り返します。ただし、コード例を示す際に 複数行に分けると著しく読みにくくなる場合や、その他妥当な理由がある場合 は例外です。
よく使う用語

ドキュメント中でよく使われる用語の書き方を以下に示します:

  • Django – フレームワークそのものを指す場合には、頭文字を大文字にし ます。 Python コード中や djangoproject.com のロゴでは小文字です。
  • e-mail – ハイフンを入れます。
  • MySQL
  • PostgreSQL
  • Python – 言語そのものを指す場合には頭文字を大文字にします。
  • realize, customize, initialize, etc. – “-ise” ではなく、ア メリカ語表記の “-ize” です。
  • SQLite
  • subclass – 動詞、名詞を問わず、ハイフンを入れず一つの単語で表しま す。
  • Web, World Wide Web, the Web – ワールドワイドウェブを指す 場合には、常に Web の W は大文字です。
    • Web site – Web を大文字にして、二つの単語を繋げません。
Django 固有の用語
  • model – 頭文字は小文字です。
  • template – 頭文字は小文字です。
  • URLconf – “URL” は大文字、 “conf” は小文字です。
  • view – 頭文字は小文字です。

コードのコミット

Django の Subversion リポジトリにコードをコミットする場合には以下のガイドラ インに従って下さい:

  • 中規模から大規模な変更 (「中規模から大規模」の判断は各自に任せます) の際には、変更前に django-developers メーリングリストに相談を持ち 込んで下さい。

    django-developers に持ち込んだ話題に対して返事がなかった場合、自分 のアイデアが素晴らしく、すぐにでも実装すべきだと皆が思ったため誰も何 も言わないのだと勘違いしないでください。 Django の開発指揮者はメーリ ングリストの議論にすぐに割ける時間を持ち合わせていないので、返事には 数日待たねばならない場合もあるのです。

  • 詳しいコミットメッセージを過去形で書いて下さい。現在形を使ってはなり ません。

    • 良い: “Fixed Unicode bug in RSS API.”
    • 悪い: “Fixes Unicode bug in RSS API.”
    • 悪い: “Fixing Unicode bug in RSS API.”
  • ブランチにコミットする場合、コミットメッセージの先頭にブランチ名を付 けて下さい。例えば “magic-removal: Added support for mind reading.” のようにします。

  • 意味のある変更のまとまりであるかぎり、できるだけ細かい変更に分けてコ ミットしてください。つまり、たまに大きなコミットをするのではなく、小 さなコミットを頻繁に行うようにしてください。例えば、機能 X を実装して いて、その機能の実現にライブラリ Y の修正が必要なら、まず Y の修正を コミットして、次に X を別にコミットしてください。これだけで、 Django のコア開発者全員が変更を追うための 大きな 助けになります。

  • バグフィクスと機能の改善とを分離してください。

    バグフィクスは現在のバグフィクスブランチ (1.0.X ブランチなど) と、 現在の trunk の両方に施す必要があるからです。

  • コミットによって Django チケットトラッカ の何らかのチケットをクロー ズする場合、コミットメッセージの先頭に “Fixed #abc” というメッセージ を入れて下さい。 “abc” はコミットによって修正されるチケットの番号です。 例えば “Fixed # 123 – Added support for foo” のようにします。私達は Subversion と Trac を結びつけているので、この形式のメッセージを使って commit した場合、関連するチケットを自動的にクローズし、完全なコミット メッセージをコメントとしてチケットに追加します。

    コミットによってブランチのチケットをクローズする場合、ブランチ名を先 にもってきます。例えば “magic-removal: Fixed #123 – Added whizbang feature.” のようにします。

    ちなみに、この機能は Trac の post-commit フック で実現しています。

  • コミットメッセージで Django チケットトラッカ の何らかのチケットを 参照し、かつチケットを 閉じない 場合、 “Refs #abc” というフレーズを 入れて下さい。 “abc” はコミットで参照しているチケットの番号です。私達 は Subversion と Trac を結びつけているので、この形式のメッセージを使っ て commit した場合、関連するチケットに完全なコミットメッセージをコメ ントとして追加します。

単体テストの作成

Django には独自のテストスイートが付属しています。テストは tarball 内の test ディレクトリ下にあります。ポリシとして、常に全てのテストがパスする ようにしています。

テストでは以下の項目をカバーしています:

  • モデル API とデータベース API (tests/modeltests/)。
  • その他、Django のコア内にあるテスト (tests/regressiontests)
  • contrib アプリケーション (django/contrib/<contribapp>/tests, 下記 参照)

テストスイートに対する協力は何でも歓迎します!

Django のテストは全て、 Django に付属のアプリケーションテストインフラを使っ ています。テストの書き方の詳細は Django アプリケーションのテスト を参照してください。

ユニットテストの実行

テストを実行するには、 tests/ ディレクトリ下に移って以下のように入力し ます:

./runtests.py --settings=path.to.django.settings

そう、テストには設定モジュールが必要です。とはいえ、必要なのは データベース接続に関する情報 DATABASE_ENGINE だけです。

sqlite3 バックエンドを使っているなら、設定はこれだけで十分です。一時デー タベースはテスト実行時にメモリ上に生成されます。

sqlite3 以外のバックエンドを使っている場合は、以下のような設定が必要で す:

  • DATABASE_USER を、対象データベースに存在するユーザ名に設定 する必要があります。
  • DATABASE_NAME を、実際に存在して、かつユーザが接続可能なデー タベースの名前に設定せねばなりません。ただし、ユニットテストはこのデー タベースを操作しません。テストランナは、 DATABASE_NAME の前に test_ を付けた新たなデータベースを作成し、テスト終了後にこ のデータベースを削除します。従って、データベースユーザには、 CREATE DATABASE を実行する権限がなければなりません。

また、データベースのデフォルト文字セットを UTF-8 にしているか確認してくださ い。データベースサーバのデフォルト文字セットが UTF-8 に設定されていないのな ら、 TEST_DATABASE_CHARSET に文字セットを指定する必要があります。

テストを全て実行したければ、以下の依存モジュール全てをインストールしておく 必要があります:

memcached キャッシュバックエンドをテストしたければ、 CACHE_BACKEND 設定に memcached インスタンスを定義しておかねばな りません。

上記の依存モジュールはなくても構いません。インストールされていなければ、 関連するテストは飛ばして実行されます。

ユニットテストの一部(サブセット)を実行したい場合は、 runtest.py コマ ンドラインの後にテストモジュールの名前を追加してください。モジュール名は、 tests/modeltests および tests/regressiontests 以下のディレクトリ名 を参照してください。

例えば、 Django が PYTHONPATH 上になく、 settings.pytests/ ディレクトリにある場合で、汎用リレーション (generic relation) と国際化 (internationalization) だけをテストしたければ、以下のようにタイプします:

PYTHONPATH=..
./runtests.py --settings=settings generic_relations i18n
contrib アプリケーション

django/contrib 以下のアプリケーションのテストは、 django/contrib/ 以下のそれぞれのディレクトリ下にある test.py に収められています。 (テストを複数のモジュールに分割したければ、 tests ディレクトリを使って ください。)

アプリケーションのテストを見つけさせるには、アプリケーション内に models.py を入れていなければなりません (ファイルは空でもかまいません)。 URL をマップする必要があるのなら、 tests/urls.py を入れてください。

特定の contrib アプリケーション (例えば markup) だけをテストするには、 上で述べたのと同じ方法を使います:

./runtests.py --settings=settings markup

機能追加の要望を出す

私達は常に Django を改良しようと努めています。その中で、皆さんから寄せられ る要望は一つの鍵になっています。効果的に要望を出すコツをいくつか紹介してお きます:

  • チケットトラッカではなく、 django-developers に要望を出して下さい。 メーリングリストの方が多くの人の目に触れやすいからです。
  • 不足している機能と、それをどのように実装すればよいと思っているかを、 すっきりと、かつ詳細に説明してください。可能ならサンプルコード (実際 に動かなくても構いません) をつけてください。
  • なぜ その機能を取り入れたいのかを説明してください。自明な場合もあり ますが、 Django は実際の開発者が実際の仕事に使うために設計されている ので、ある機能がどのようにユーザの役に立つのかを説明する必要がありま す。

ほとんどのオープンソースプロジェクトと同じく、コードは大きな説明力を持って います。追加したい機能のコードを書く意志があるか、(さらに望ましいのは) すで に書き上げているのなら、ずっと受け入れられやすくなるでしょう。大がかりな機 能で、複数の開発者が必要になりそうなら、いつでも喜んで実験用ブランチをリポ ジトリに作成します。詳しくは次節を参照してください。

ブランチの管理ポリシ

一般的に、Django の trunk は安定に保たれています。誰がいつ trunk から取り出 したDjango でも、実運用のサイトを走らせられるはずです。さらに、私たちは、 trunk への変更は可能なかぎりアトミックに行われるべきで、より細かい単位の変 更がベターだと考えています。従って、大掛かりな変更、すなわち一つのパッチに 収まらないくらい大きな変更を伴う合や、多くの人が関わる必要のある変更の場合 には、専用のブランチを作成します。

つまり、一つのパッチで済まないような大きな機能や、大掛かりなリファクタリ ングは機能ブランチ (feature branch) で行わねばならないのです。私たちの開発 プロセスです、機能ブランチのありかたに、二つの選択肢をもたせています:

  1. GitMercurial, Bazaar といった分散リビジョンコントロールシステ

    ムを使った機能ブランチ。

    If you’re familiar with one of these tools, this is probably your best option since it doesn’t require any support or buy-in from the Django core developers.

    However, do keep in mind that Django will continue to use Subversion for the foreseeable future, and this will naturally limit the recognition of your branch. Further, if your branch becomes eligible for merging to trunk you’ll need to find a core developer familiar with your DVCS of choice who’ll actually perform the merge.

    If you do decided to start a distributed branch of Django and choose to make it public, please add the branch to the Django branches wiki page.

  2. Feature branches using SVN have a higher bar. If you want a branch in SVN itself, you’ll need a “mentor” among the core committers. This person is responsible for actually creating the branch, monitoring your process (see below), and ultimately merging the branch into trunk.

    If you want a feature branch in SVN, you’ll need to ask in django-developers for a mentor.

Branch rules

We’ve got a few rules for branches born out of experience with what makes a successful Django branch.

DVCS branches are obviously not under central control, so we have no way of enforcing these rules. However, if you’re using a DVCS, following these rules will give you the best chance of having a successful branch (read: merged back to trunk).

Developers with branches in SVN, however, must follow these rules. The branch mentor will keep on eye on the branch and will delete it if these rules are broken.

  • Only branch entire copies of the Django tree, even if work is only happening on part of that tree. This makes it painless to switch to a branch.

  • Merge changes from trunk no less than once a week, and preferably every couple-three days.

    In our experience, doing regular trunk merges is often the difference between a successful branch and one that fizzles and dies.

    If you’re working on an SVN branch, you should be using svnmerge.py to track merges from trunk.

  • Keep tests passing and documentation up-to-date. As with patches, we’ll only merge a branch that comes with tests and documentation.

Once the branch is stable and ready to be merged into the trunk, alert django-developers.

あるブランチがマージされると、そのブランチは「死んだ」ものとみなされます。 死んだブランチには書き込めなくなり、古いブランチは定期的に「刈り取られ」 ます。 SVN への世話焼きを最小限にするため、ブランチから trunk へのマージは 一度しか行いません。

ブランチを使う

ブランチをテストするには、二つの作業が必要です:

  • 該当するブランチのコードを Subversion から取得します。
  • Python の site-package ディレクトリが、該当ブランチの django を含むように設定します。
Subversion からコードを取り出す

ブランチコードの最新版を入手するには Subversion を使います:

svn co http://code.djangoproject.com/svn/django/branches/<branch>/

<branch> はブランチの名前です。ブランチの名前については ブランチ名一覧 を参照してください。

既存の Django を Subversion からソースコードをチェックアウトして使っている 場合には、ディレクトリ全体を特定のバージョンに自動的に変換できます。 django ディレクトリの下で以下のコマンドを実行してください:

svn switch http://code.djangoproject.com/svn/django/branches/<branch>/

svn co ではなく svn switch を使う利点は、 switch コマンドを使っ た場合、ローカルコピー上で既に変更済みの内容についてはファイルを変更しない 点にあります。 switch はローカルコピー上の変更を “スイッチ先の” コード にマージします。 svn switch には欠点もあります。それは、ローカルコピー 上でコードに変更を加えた場合、スイッチ先のコードにも同じ部分に変更があると 衝突するという問題です。

(svn switch を使う場合には、次の節で述べるような、Pythonのモジュール検 索パスを変更する操作は必要ありません。)

Python に別のバージョンの Django を使わせる

ブランチのコードを取り出したら、ブランチの site-packages ディレクトリ の構成を変更して、ブランチ版の django ディレクトリを使えるようにする必 要があります。 (site-packages ディレクトリは /usr/lib/python2.4/site-packages/usr/local/lib/python2.4/site-packages, C:\Python\site-packages などにあります。)

元の django ディレクトリを django.OLD のような別の名前に変えて、 trunk などから取り出したバージョンのコードをコピーし、名前を django に 変更するのが簡単です。

別の方法として、 django と言う名前のシンボリックリンクを作成して、特定 のブランチの django パッケージの場所を指すという方法もあります。元に戻 したい場合には、シンボリックリンクが元のコードを指すように変更しなおすだけ です。

第三の方法は、 パスファイル (<something>.pth) を使うというものです。この方法は、 (シンボリックリン クを使えない Windows を含む) 全てのシステムで利用できます。まず、 site-packages ディレクトリに、 django という名前のファイルやディレ クトリ、シンボリックリンクがない状態にしてください。次に、 django.pth という名前のテキストファイルを作成して、 site-packages ディレクトリの直 下に保存します。このファイルには、使いたい Django の置かれているパスを一行 で記述します。コメントを追加しても構いません。複数のブランチを指定できるよ うにしたパスファイルの例を以下似示します。特定のブランチ (例えば ‘trunk’) を使いたい場合、その行のコメントを解除して、他の行を全てコメント化します:

# トランク (trunk): svn リポジトリの
#   http://code.djangoproject.com/svn/django/trunk/
# からチェックアウトしたもの
#
/path/to/trunk

# ブランチ (branch): ブランチ名 <branch> を svn リポジトリの
#   http://code.djangoproject.com/svn/django/branches/<branch>/
# からチェックアウトしたもの
#
#/path/to/<branch>

# Windows の場合は以下のような形式にします:
# C:/path/to/<branch>

Django 0.95 やそれ以前のバージョンをインストールしていて、インストールに python setup.py install を使った場合、 django ではなく Django-0.95-py2.4.egg といった名前のディレクトリになっているでしょう。 この場合、 setuptools.pth を編集して、該当する Django の .egg の書かれた行を削除してから、 django のブランチを site-packages にコ ピーします。

仕様に関する決定

ある仕様の要望が出て議論が始まると、そのうち仕様を取り入れるべきか棄却すべ きかという決定をせねばなりません。

私達は、可能な場合はいつでもまずおおまかな合意を形成しようと試みます。その 後、たいていは django-developers において、その機能について正式でない投 票を行います。投票では、 Apache や Python で使われている形式を採用しており、 投票は +1, +0, -0, or -1 のいずれかを用いて行います。これらの票の大雑把な解 釈は以下の通りです:

  • +1: “これはいい。強く同意します (I love the idea and I’m strongly committed to it.)”
  • +0: “いいんじゃないかな (Sounds OK to me.)”
  • -0: “あまりわくわくしないが、反対もしない (I’m not thrilled, but I won’t stand in the way.)”
  • -1: “強く反対。このアイデアは実現してほしくない (I strongly disagree and would be very unhappy to see the idea turn into reality.)”

django-developers での投票は正式なものではありませんが、その結果は真摯に受 け止められます。適切な投票期間を経て、明らかな合意を形成できた場合には、投 票の決定に従うでしょう。

とはいえ、つねに合意を形成できるわけではありません。その場合、完全コミッタ 全員の中で十分に議論を重ねた後、最終判断を慈悲深き終身独裁者 (Benevolent Dictators for Life) である Adrian と Jacob に委ねます。

コミット権限

Django プロジェクトには二種類のコミッタがいます:

完全コミッタ (full committers)

長期間にわたって Django のコードベースに貢献してきており、メーリングリ ストにおいても礼儀正しく親切で、 Django の開発に十分な時間を割けること が分かっている人達です。

完全な commit 権限者の敷居は極めて高いものです。全ての完全コミッタによ る全会一致でのみ受け入れることとし、その決定は覆りません。

部分コミッタ (partial committers)

「個別領域のエキスパート」です。管轄下にあるサブシステムのコードに直接 チェックインする権限を持ち、サブシステムの懸案事項に対する正式な投票権 を持ちます。このタイプの権限は、 Django の大きなサブフレームワーク に貢献し、継続してメンテナンスを続けたい人に与えられるものです。

完全コミッタと同様、部分コミッタの受け入れも全ての完全コミッタ (と同じ 領域の部分コミッタ) による全会一致でのみ受け入れることとします。とはい え、敷居はやや低く、個別領域で十分な専門性を示しているということで十分 です。

コミット権限を得たければ、現在コミッタを勤めているだれかに個人的にコンタク トしてください。コミット権限を公の場でリクエストするのはフレームの元であり、 一切無視します。

Django ドキュメントの仕組み

revision-up-to:11321 (1.1)

... と、ドキュメント作業への貢献方法

Django のドキュメントは Sphinx ドキュメンテーションシステムを使っています。 Sphinx は docutils に基づいて作られています。 docutils は、簡単な書式の プレーンテキストを、 HTML や PDF その他の様々な出力形式で簡単に扱えるように することを念頭に置いて作られています。

ドキュメントを実際に手元でビルドするには、現状では Sphinx をインストールす る必要があります。インストールは easy_install Sphinx でできます。

さて、 html のビルドは簡単です。単に docs ディレクトリで make html を実行するだけです。

ドキュメント作業に貢献したいなら、まず ReStructuredText Primer を読みま しょう。その後 Sphinx 固有のマークアップ の説明を読んで、メタデータやイ ンデクス、相互参照の方法を学ぶとよいでしょう。

ドキュメントを書いたり編集したりする上で覚えておかねばならないのは、よりセ マンティックなマークアップを使う方がよい、ということです。従って:

Add ``django.contrib.auth`` to your ``INSTALLED_APPS``...

とするよりも:

Add :mod:`django.contrib.auth` to your :setting:`INSTALLED_APPS`...

と書いた方が便利なのです。なぜなら、後者のマークアップの場合、 Sphinx が適 切なリンクを生成するため、ドキュメントの読み手にとって非常に助かるからです。 制限はありません。可能な限り便利なマークアップを使ってください。

Django 固有のマークアップ

Sphinx の組み込みマークアップ の他に、Django ドキュメントではいくつか追 加で表記単位 (description unit) を定義しています:

  • 設定:

    .. setting:: INSTALLED_APPS
    

    リンクするには、 :setting:`INSTALLED_APPS` としてください。

  • テンプレートタグ:

    .. templatetag:: regroup
    

    タグの説明にリンクするには :ttag:`regroup` としてください。

  • テンプレートフィルタ:

    .. templatefilter:: linebreaksbr
    

    リンクするには :tfilter:`linebreaksbr` としてください。

  • フィールド照合 (Foo.objects.filter(bar__exact=whatever) など):

    .. fieldlookup:: exact
    

    リンクするには :lookup:`exact` としてください。

  • django-admin コマンド:

    .. django-admin:: syncdb
    

    リンクするには :djadmin:`syncdb` としてください。

  • django-admin コマンドラインオプション:

    .. django-admin-option:: --traceback
    

    リンクするには :djadminopt:`--traceback` としてください。

マークアップ方法を理解するために、以下の手順に従って確認してみましょう:

  • まず、 ref/settings.txt ドキュメントを見てみましょう。このドキュ メントは以下のような内容から始まっています:

    .. _ref-settings:
    
    settings に設定できる値
    ==========================
    
    ...
    
  • topics/settings.txt ドキュメントを見ると、 ref/settings への リンクがどのように書かれているか分かります:

    利用可能な設定
    ==============
    
    利用可能な設定は :ref:`setting リファレンス <ref-settings>` を参照
    してください。
    
  • 設定項目をどのように表記しているかを見てみましょう:

    .. setting:: ADMIN_FOR
    
    ADMIN_FOR
    ---------
    
    デフォルト値: ``()`` (空のタプル)
    
    admin 用サイトの設定モジュールで設定します。このサイトの admin を他
    のサイトの admin にする場合、設定モジュールを (``'foo.bar.baz'`` の
    形式のタプルで) 指定します。
    
    admin サイトはこの変数を使って、モデルやビュー、テンプレートタグの
    ドキュメントに対するイントロスペクションを自動的に行います。
    

    この .. settings:: の部分で、 ADMIN_FOR の「正しい」ターゲッ トとしてを定義しています。これで、 ADMIN_FOR について説明するとき に、 :setting:`ADMIN_FOR` を使って参照できます。

このようにして、お互いの参照を解決します。

TODO

ドキュメントの整備はほぼ終っていますが、まだ、ほぼ以降に挙げる順番にやらね ばならないことが残っています。

  • 「開発版で追加/変更された機能」の部分を、全て Sphinx の .. versionadded:: および .. versionchanged:: ディレクティブに 置き換えます。

  • おかしなリンクをチェックして修正します。 make linkcheck を実行し て、 300 個以上出るエラーや警告メッセージを全て修正します。

    特に、相対リンクを全て調べる必要があります。これらは正しい参照に変更 せねばなりません。

  • ほとんどの index.txt ドキュメントに、肝心の説明文が とても わず かしかないか、まったくありません。それぞれに、各階層下に収められてい るコンテンツのよい説明文が必要です。

  • 用語集がいい加減すぎます。もっと内容を濃くする必要があります。

  • メタデータターゲットをもっと増やします。まだ:

    ``File.close()``
    ~~~~~~~~~~~~~~~~
    

    のような部分がたくさんあり、以下のように書き直さねばなりません:

    .. method:: File.close()
    

    つまり、タイトルではなくメタデータを使わねばなりません。

  • リンクを追加します。現状のインラインコードリテラルは、ほぼ全て相互参 照に変更できます。

    _ext 以下にある literals_to_xrefs.py ファイルを参照してくださ い。このシェルスクリプトを使えば、作業が楽になります。

    おそらく終わりのない、地道な作業になるでしょう。

  • 適切な info フィールドリスト を追加する必要があります。

  • 色づけ表示の必要なリテラルブロックに .. code-block:: <lang> を付 加する必要があります。

ヒント

読みやすいドキュメントにするためのヒントをいくつか紹介しましょう:

  • 可能なかぎり、リンクを使いましょう。例えば、 ``ADMIN_FOR``:setting:`ADMIN_FOR` にしましょう。

  • ディレクティブの中には、プレフィクススタイルのもの (.. setting:: など)あります。プレフィクススタイルのディレクティブは、記述対象のブロッ クの に置かねばなりません。その他 (.. class:: など) は独自の マークアップを生成します。その他のディレクティブは、記述対象のセクショ ンの中に置かねばなりません。こうしたディレクティブは「記述単位 (description unit)」と呼びます。

    どのディレクティブがどちらのタイプは、 _ext/djangodocs.py を 参照してください。このファイルの中で、それぞれのロールを登録していま す。

  • クラスや関数、モジュールなどを参照するときは、完全指定の名前 (:class:`django.contrib.contenttypes.models.ContentType`)を使うと よいでしょう。

    完全指定の名前を使っただけでは、出力はさほどきれいにならないでしょう。 というのも、オブジェクトの全てのパスが表示されてしまうからです。 ターゲットの先頭にチルダ (~) を付けると、パスの「最後の部分」だけ が表示されます。従って、 :class:`~django.contrib.contenttypes.models.ContentType` とすると、 単に “ContentType” と書かれたリンクを生成します。

Django のコミッタ

revision-up-to:11321 (1.1)

当初の開発者たち

Django プロジェクトは、米国ローレンス州カンザスにある Lawrence Journal-World 社の Web 開発部門、 World Online で生まれました。

Adrian Holovaty

Adrian はジャーナリズムのバックグラウンドを持った Web 開発者です。ジャー ナリズムの世界では、「計算機ジャーナリズム」のパイオニアとして、テクノ ロジーの世界では「Django を作った男」として知られています。

Adrian は 2 年半の間 World Online のリードプログラマを勤め、その間に Django を開発して World Online サイトを実装しました。現在彼は「地域に根 ざしたフィードサイト」である EveryBlock のリーダー兼創立者です。

シカゴ在住です。

Simon Willison

Simon はイングランドから来た有名な Web 開発者です。彼は World Online で 1 年間のインターンシップを過ごし、その間に Adrian とともに Djang をスクラッチから開発しました。彼はまれに見る情熱家の英国人で、 Web 開発の王道について確固たる信念を持っており、多くの読者を擁する Web 開発についての blog を運営しています。

イングランドのブライトン在住です。

Jacob Kaplan-Moss

Jacob は Django や関連のオープンソーステクノロジに関するサポートサービ スを行う Revolution Systems のパートナーです。 Jacob の仕事時間の大 半は Django に関する仕事に割り当てられています。Jacob はかつて Django の開発された WorldOnline に勤務しており、当時はメディア企業向けの商用パ ブリッシングプラットフォームである Ellington のリードデベロッパでした。

ローレンス州カンザス在住です。

Wilson Miner

Django をかっこよく見せているのは Wilson のデザインの力です。今あなたが 見ている Django サイトも、 Django の管理サイトのインタフェースも Wilson がデザインしたものです。 Wilson は EveryBlock のデザイナとして 働いています。

サンフランシスコ在住です。

現在の開発者

現在、 Django の開発は世界中のボランティアのチームによって進められています。

BDFLs

Adrian と Jacob は、共に Django の 慈悲深き終身独裁者 です。「大局的な合意と実際に動くコード」 のポリシがうまく働かないときには、彼らが最終判断を下します。

コア開発者たち

ここに挙げる人達は、長い間にわたりプロジェクトに貢献し、メーリングリストで も堅実に有益な助言を重ねてきました。また、多くの時間を Django に費そうとい う確固たる意志を持っています。その結果、彼らには待望のコミット権限が与えら れ、 Django の全ての部分をハックする自由を有するに至りました。

Malcolm Tredinnick

Malcolm はもともと数学者になりたかったのですが、どういうわけかソフトウェ ア開発者になりました。彼は多くのオープンソースソフトウェアプロジェクト に貢献しており、 GNOME ファウンデーションのボードメンバの一人でもありま す。すごいチェスの指し手です。

謎の男として忙しく世界を駆け回っていないときは、オーストラリアのシドニー に住んでいます。

Russell Keith-Magee

Russell は学部で物理学を学び、 PhD でニューラルネットワークを研究しまし た。彼の最初の仕事は、シミュレーションフレームワークを開発する防衛関係 の企業の立ち上げでした。その後、 Django を扱ううちに、より Web 開発に深 くかかわるようになりました。

Russell は主要な Django の機能のいくつかに手を貸してくれました。 2 つの 内部的なリファクタリング、テストシステムの構築などです。

Russell は世界でもっとも隔絶された首都 – オーストラリアのパースに住ん でいます。

Joseph Kocherhans

Joseph は現在 EveryBlock の開発者です。以前、 Lawrence Journal-World で働いていたときに、 Marketplace サイトのバックエンドの大半を構築しまし た。時々彼は数日森に籠って新しいコンピュータ言語を学んだり、 Charango を演奏して隣人を悩ませたりしています。

Joseph の最初の Django への貢献は、認証システムをプラガブルな認証機構を サポートするよういくつも改良したことでした。その後、新しいフォームシス テムの開発や admin への組み込み、その他細々とした改良に取り組んでいます。

シカゴ在住です。

Luke Plant

Luke は大学で物理学と物性科学を学び、そこで出会った Michael Meeks の影響で、 Linux とオープンソースに触れ、プログラミングの楽しさを再発見 しました。その後、彼はいくつものオープンソースプロジェクトに参加し、プ ロの開発者として活動しました。

Luke はデータベースレベルの改善や、 CSRF ミドルウェア、ユニットテストな ど、様々な素晴らしい改善に貢献しています。

Luke は現在英国 Bradford の教会で働きながら、パートタイムでフリーランス の開発の仕事をしています。

Brian Rosner

Brian は現在、 Django の電子決済システムを開発している Web 開発者です。 彼は自分の自由時間を Django プロジェクトに費すほか、プログラミング言語 やシステムアーキテクチャの習得に費しています。 Brian は毎週放送される podcast, This Week in Django の副司会者でもあります。

Brian は、 Django の “newforms-admin” ブランチを Django 1.0 に間に合わ せて完了させる上で非常に大きな働きを見せました。彼は今やフルコミッタで あり、 admin と forms システムの改良に取り組んでいます。

デンバー在住です。

Gary Wilson

Gary は 2006 年ごろから、 テキサス大学 (UT) の Web アプリケーション を開発するかたわら Django にパッチを提供していました。当時から、電子メー ル機能やフォーム機能に貢献しており、その他にも数々の機能とコードベース 全体にわたるクリーンアップを手伝っています。

テキサス州オースティン在住です。

Justin Bronn

Justin Bronn は計算機科学者であり、知的財産や地理空間情報の利用に関する 法律 (spatial law) を専門とする弁護士でもあります。

2007 年から、 Justin はいわゆる GeoDjango ブランチで django.contrib.gis の開発を始めました。その後、 GeoDjango は Django 1.0 でマージされました。 GeoDjango の開発のかたわら、 Justin は ORM や 管理サイト、 Oracle のサポートなど、 Django の内部に関する深い知識を得 ています。

テキサス州ヒューストン在住です。

Karen Tracey

Karen のバックグラウンドは分散オペレーティングシステム (大学院) から情 報通信関連のソフトウェア技術 (企業)、そしてクロスワードパズルの作成 (フ リーランス) にわたります。2006 年、自分のクロスワードパズルデータベース にフロントエンドをつけようとしたのが、こ彼女が Django に関わったきっか けでした。その後、彼女はコミュニティに寄せられる質問への回答や、デバッ グにずっと関わっています。コーディングパズルを解くのは、クロスワードパ ズルと同じくらい楽しいから、という理由で。

ニューカレドニア州エーペックス在住です。

専門家たち
James Bennett

James は Django のリリースマネジャです。彼はドキュメントの作成で貢献 しています。

James は、プログラマ達がよい賃金をもらう程に口論ばかりするようになると いう事実を発見して、哲学にもとづいた Web 開発者への道を選びました。 彼はカンザス州ローレンス在住で、 Ellington を開発している Journal-World に勤務しています。 ブログを書きDjango の本 を著し、 ポートワインと車語りを楽しんでいます。

Ian Kelly
Ian は Django の Oracle サポートに携わっています。
Matt Boersma
Matto も Django の Oracle サポートに携わっています。
Jeremy Dunck

Jeremy はテキサス州ダラスの 個人向けローカルサイトである Pegasus News のリードデベロッパです。 Greasemonkey と Django の初期からのコントリビュー タであり、テクノロジーをコミュニケーションや知識へのアクセス手段ととら えています。

Jeremy は GeoDjango の開発を立ち上げ、 Django 1.0 のシグナル受信速度の 劇的な向上に携わっています。

テキサス州ダラス在住です。

名誉開発者たち

Georg “Hugo” Bauer
Georg は Django の国際化システムを作り上げ、 i18n に関する貢献をまとめ あげ、さまざまな素晴らしい工夫と機能追加、バグフィクスを行いました。
Robert Wittams
Robert は Django の admin アプリケーションの はじめて のリファクタ を担当し、より簡単に再利用できるようにして、さまざまな素晴らしい工夫を と機能追加、バグフィクスを行いました。

Django のリリースプロセス

revision-up-to:11321 (1.1) unfinished

公式リリース

Django のリリース番号は以下のように付与されています:

  • バージョンは A.B または A.B.C という形式でつけられます。
  • A はメジャーバージョン番号で、増えるのは Django に重大な変更が加 えられ、変更が必ずしも以前のバージョンと互換でない場合だけです。従っ て、 Django 6.0 で動いたコードは Django 7.0 では動かなくなるかもしれ ません。
  • B はマイナーバージョン番号で、比較的大きいながらも後方互換性を保っ た変更の際に増えます。 Django 6.4 向けに書かれたコードは Django 6.5 でも動作するでしょう。
  • C はマイクロバージョンで、バグやセキュリティ修正の度に増えます。 マイクロバージョンは以前のマイクロバージョンと 100% 後方互換性を保ち ます。
  • 場合によってはリリース候補 (release candidate) を作成します。リリース 候補のバージョン番号は A.BrcN の形式で、 A.BN 番目の リリース候補であることを表します。

以上のバージョン番号スキームの例外として、1.0 以前の Django のコード があります。 1.0 リリース以前のコードでは、後方互換性を全く保証していません。

Subversion 上では、 Django の各リリースは tags/releases_ でタグづけされて います。trunk 由来ではないバグフィクスリリースやセキュリティ修正リリースを 出す必要画ある場合、該当リリースは branches/releases にコピーされ、 バグフィクスリリースになります。

Major releases

Major releases (1.0, 2.0, etc.) will happen very infrequently (think “years”, not “months”), and will probably represent major, sweeping changes to Django.

Minor releases

Minor release (1.1, 1.2, etc.) will happen roughly every six months – see release process, below for details.

These releases will contain new features, improvements to existing features, and such. マイナーリリースでは、新しい機能や既存の機能の改善などが行われます。また、 マイナーリリースでは、以前のリリースの特定の機能を撤廃することがあります。 バージョン A.B の機能が撤廃された場合、撤廃された機能は A.B+1 では 動作します。 A.B+2 では PendingDeprecationWarning 警告を送出します が動作します。 A.B+3 では完全に機能を削除します。

So, for example, if we decided to remove a function that existed in Django 1.0:

  • Django 1.1 will contain a backwards-compatible replica of the function which will raise a PendingDeprecationWarning. This warning is silent by default; you need to explicitly turn on display of these warnings.
  • Django 1.2 will contain the backwards-compatible replica, but the warning will be promoted to a full-fledged DeprecationWarning. This warning is loud by default, and will likely be quite annoying.
  • Django 1.3 will remove the feature outright.
Micro releases

Micro releases (1.0.1, 1.0.2, 1.1.1, etc.) will be issued at least once half-way between minor releases, and probably more often as needed.

These releases will always be 100% compatible with the associated minor release – the answer to “should I upgrade to the latest micro release?” will always be “yes.”

Each minor release of Django will have a “release maintainer” appointed. This person will be responsible for making sure that bug fixes are applied to both trunk and the maintained micro-release branch. This person will also work with the release manager to decide when to release the micro releases.

Supported versions

At any moment in time, Django’s developer team will support a set of releases to varying levels:

  • The current development trunk will get new features and bug fixes requiring major refactoring.
  • All bug fixes applied to the trunk will also be applied to the last minor release, to be released as the next micro release.
  • Security fixes will be applied to the current trunk and the previous two minor releases.

As a concrete example, consider a moment in time halfway between the release of Django 1.3 and 1.4. At this point in time:

  • Features will be added to development trunk, to be released as Django 1.4.
  • Bug fixes will be applied to a 1.3.X branch, and released as 1.3.1, 1.3.2, etc.
  • Security releases will be applied to trunk, a 1.3.X branch and a 1.2.X branch. Security fixes will trigger the release of 1.3.1, 1.2.1, etc.

Release process

Django uses a time-based release schedule, with minor (i.e. 1.1, 1.2, etc.) releases every six months, or more, depending on features.

After each previous release (and after a suitable cooling-off period of a week or two), the core development team will examine the landscape and announce a timeline for the next release. Most releases will be scheduled in the 6-9 month range, but if we have bigger features to development we might schedule a longer period to allow for more ambitious work.

Release cycle

Each release cycle will be split into three periods, each lasting roughly one-third of the cycle:

Phase one: feature proposal

The first phase of the release process will be devoted to figuring out what features to include in the next version. This should include a good deal of preliminary work on those features – working code trumps grand design.

At the end of part one, the core developers will propose a feature list for the upcoming release. This will be broken into:

  • “Must-have”: critical features that will delay the release if not finished
  • “Maybe” features: that will be pushed to the next release if not finished
  • “Not going to happen”: features explicitly deferred to a later release.

Anything that hasn’t got at least some work done by the end of the first third isn’t eligible for the next release; a design alone isn’t sufficient.

Phase two: development

The second third of the release schedule is the “heads-down” working period. Using the roadmap produced at the end of phase one, we’ll all work very hard to get everything on it done.

Longer release schedules will likely spend more than a third of the time in this phase.

At the end of phase two, any unfinished “maybe” features will be postponed until the next release. Though it shouldn’t happen, any “must-have” features will extend phase two, and thus postpone the final release.

Phase two will culminate with an alpha release.

Phase three: bugfixes

The last third of a release is spent fixing bugs – no new features will be accepted during this time. We’ll release a beta release about halfway through, and an rc complete with string freeze two weeks before the end of the schedule.

Bug-fix releases

After a minor release (i.e 1.1), the previous release will go into bug-fix mode.

A branch will be created of the form branches/releases/1.0.X to track bug-fixes to the previous release. When possible, bugs fixed on trunk must also be fixed on the bug-fix branch; this means that commits need to cleanly separate bug fixes from feature additions. The developer who commits a fix to trunk will be responsible for also applying the fix to the current bug-fix branch. Each bug-fix branch will have a maintainer who will work with the committers to keep them honest on backporting bug fixes.

How this all fits together

Let’s look at a hypothetical example for how this all first together. Imagine, if you will, a point about halfway between 1.1 and 1.2. At this point, development will be happening in a bunch of places:

  • On trunk, development towards 1.2 proceeds with small additions, bugs fixes, etc. being checked in daily.
  • On the branch “branches/releases/1.1.X”, bug fixes found in the 1.1 release are checked in as needed. At some point, this branch will be released as “1.1.1”, “1.1.2”, etc.
  • On the branch “branches/releases/1.0.X”, security fixes are made if needed and released as “1.0.2”, “1.0.3”, etc.
  • On feature branches, development of major features is done. These branches will be merged into trunk before the end of phase two.

Django Deprecation Timeline

revision-up-to:11321 (1.1) unfinished

This document outlines when various pieces of Django will be removed, following their deprecation, as per the Django deprecation policy

  • 1.3
    • AdminSite.root(). This release will remove the old method for hooking up admin URLs. This has been deprecated since the 1.1 release.
  • 2.0
    • django.views.defaults.shortcut(). This function has been moved to django.contrib.contenttypes.views.shortcut() as part of the goal of removing all django.contrib references from the core Django codebase. The old shortcut will be removed in the 2.0 release.

索引、モジュール一覧、用語集

撤廃されたもの・古いドキュメント

現バージョン Django では、以下のドキュメントは撤廃または他のドキュメントと 置き換わっています。

撤廃された機能のドキュメント

revision-up-to:11321 (1.1)

このセクションのカバーしている機能は、現在の Django ではすでに撤廃されたか、 別の機能にとって代わられています。ここに残しているのは、古いバージョンの Django を使っているユーザや、撤廃された API を使っているユーザのためです。 新しくコードを書くときには、このセクションにある API を使わないでください。

Django 管理インタフェースのカスタマイズ

revision-up-to:

11321 (1.1)

Warning

このドキュメントが書かれた後に admin の設計は変更されました。そのため、 ここに書かれている内容はもはやあてはまりません。 Django の admin をカ スタマイズするための API は別途開発されているので、このドキュメントは もはやメンテナンスされていません。

Django が動的に生成する admin インタフェースは、コードを書かずに使える完全 な機能を備えた admin を提供しています。 admin は動的管理サイト構築の単なる 足掛かりではなく、実運用の環境でそのまま使えるだけの機能を備えています。 admin ページの根底にある形式は Django で構築されていますが、 admin のスタイ ルシートや画像を編集すればルック & フィールをカスタマイズできます。

このドキュメントでは、 Django の admin の CSS で使われている主要なスタイル とクラスについてざっと紹介します。

モジュール

admin 上ではコンテンツをグループ化する基本の構成要素として .module クラ スを使っています。 .moduledivfieldset に適用されます。 .module はコンテンツのグループをボックス内にラップし。その中身に一定の スタイルを適用します。例えば、 div.module 内の h2 タグは、グループ 全体のヘッダになるよう、 div の上に配置されます。

Example use of module class on admin homepage
カラムタイプ

Note

管理ページは (ダッシュボード部分を除いて) 全て可変幅 (fluid-width) になっ ており、以前の Django にあった固定幅のクラスは全て除去されています。

admin ページのベーステンプレートには、ページのカラム構造を決めるブロックが あります。このブロックにはページのコンテンツ領域 (div#content) のクラス を定義し、コンテンツ領域の幅がわかるようにします。指定できるカラムタイプは 3 種類あります。

colM
全てのページのデフォルトのカラムの設定です。 “M” は “main” を表します。 全てのコンテンツは一つのメインカラム (div#content-main) に入るもの と仮定しています。
colMS
一つのメインカラムと、その右側にサイドバーを持つようなページのカラム設 定です。 “S” は “sidebar” を表します。メインのコンテンツは div#content-main に入り、サイドバーのコンテンツは div#content-related に入るものと仮定しています。メインの admin ペー ジで使われています。
colSM
上と同じですが、サイドバーは左側に出ます。ソース中でどちらのカラムが先 にでてくるかは関係ありません。

例えば、以下のようなコードをテンプレートに張り付ければ、右側のサイドバーを 2 カラムのページにできるでしょう:

{% block coltype %}colMS{% endblock %}
テキストのスタイル
フォントサイズ

スタイルシートには、ほとんどの HTML 要素 (ヘッダ、リストなど) に対して コンテキストに応じてベースフォントサイズを指定しています。テキストを 特定のサイズに強制する 3 つのクラスがあります。

small
11px
tiny
10px
mini
9px (控え目に使ってください)
フォントスタイルと字揃え

テキストのスタイルもいくつかあります。

.quiet
フォント色をライトグレーにします。説明文の傍注意などに便利です。協調の 度合を変えるには .small.tiny と組み合わせて下さい。
.help
フォーム要素の機能を説明するインラインヘルプテキストのブロック用に作ら れたクラスです。テキストを小さいグレーで表示し、 .form-row 要素 (後述の「フォームのスタイル」参照) 内の p エレメントで使うと、フォー ムフィールドと並ぶようにオフセットを決めます。ヘルプテキストには small quiet ではなくこのクラスを使ってください。他のエレメントで も使えますが、できるだけ p に使うようにしてください。
.align-left
テキストを左揃えにします。インラインエレメントの入ったブロックエレメン トでしか使えません。
.align-right
こんなの気にしませんよね?
.nowrap
テキストとインラインオブジェクトがラップされないようにします。 テーブルヘッダなどを一行に収めたい場合に便利です。
float 指定とクリア
float-left
左よせの float です。
float-right
右よせの float です。
clear
float 指定を全てクリアします。
オブジェクトツール

フォームやチェンジリストのページには、オブジェクトに直接適用される操作への リンクがあります。これらのリンクはチェンジリストの上にある「ツールバー」行 の右側に表示されます。 ツールは object-tools クラスの ul でラップ されています。ツールには二つのカスタムのタイプがあり、ツール内で a タグ に指定して使うようになっています。 .addlink.viewsitelink です。

チェンジリストページではこのようになります:

<ul class="object-tools">
  <li><a href="/stories/add/" class="addlink">Add redirect</a></li>
</ul>
Object tools on a changelist page

フォームページでは以下のようになっています:

<ul class="object-tools">
 <li><a href="/history/303/152383/">History</a></li>
 <li><a href="/r/303/152383/" class="viewsitelink">View on site</a></li>
</ul>
Object tools on a form page
フォームのスタイル
フィールドセット

admin のフォームは fieldset エレメントでグループごとに分けられています。 各フィールドセットには .module クラスがなくてはなりません。また、 各フィールドセットの先頭には h2 タグによるヘッダがなくてはなりません (ただし、フォームの最初のグループや、フィールドグループに論理的なラベル を必要としない場合は除きます)。

また、各フィールドセットに .module 以外の追加のクラスを指定して、フィー ルドグループ全体が適当なフォーマットになるようにしてもかまいません。

.aligned
ラベルと input エレメントを同じ行に横並びに配置します。
.wide
.aligned と組み合わせて、ラベルの使えるスペースを広くします。
フォーム行

(fieldset 内の) フォームの各行は form-row クラスの div で囲わね ばなりません。行内に収めるフィールドが必須のフィールドの場合、 div.form-row には required クラスを追加せねばなりません。

Example use of form-row class
ラベル

チェックボックスとラジオボタンを除き、フォームのラベルは常にフィールドの前 にきます。チェックボックスやラジオボックスの場合には input タグが先にき ます。 label タグ以降の説明文やヘルプテキストは、 .help クラスの p タグに入ります。