| revision-up-to: | 13211 (1.1) unfinished |
|---|
このドキュメントでは、モデル API の詳細を解説します。このドキュメントは、 モデル や データベースクエリ <topics-db-queries> といったガイドを前提にしているので、このドキュメントを 読む前に、予め読んで理解しておくとよいでしょう。
このリファレンスでは、 データベースクエリガイド の Weblog のモデル例 を使います。
モデルの新たなインスタンスは、通常の Python のクラスと同じ方法で生成します:
キーワード引数に指定できる名前は、モデルで定義したフィールドの名前です。 モデルのインスタンスを生成しても、 save() を呼び出すまでデータベースは 操作されません。
オブジェクトをデータベースに書き戻すには、 save() を使います:
もちろん、 データベースへの保存には、以下に説明するような細かい注意点があり ます。
save() メソッドのシグネチャが変更されました (force_insert と force_update が追加されました) メソッドをオーバライドするときには、正し いシグネチャを使ってください。
モデルに 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 のドキュメントを参照してください。)
主キーを自前で定義しているか、 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 は以下の段階を踏んでオブジェクトを保存します:
``pre_save`` シグナルの発行 django.db.models.signals.pre_save シグナル の発行によって、何らかのオブジェクトを保存しようとしていることを通知 します。このシグナルを待ち受けている関数でカスタムの処理を実行できま す。
データの前処理 オブジェクトの各フィールドについて、保存時に自動 的に実行する必要があるデータ修飾処理がないか調べ、あれば実行します。
ほとんどのフィールドは前処理を 伴いません 。フィールドのデータは そのまま保存されます。前処理が行われるのは、特殊な挙動を示すフィー ルドだけです。例えば、 auto_now=True に設定された DateField の場合、前処理の段階で、フィールドの内容が現在の日付になるようデータ を置き換えます (現時点では、「特殊な」挙動を示すフィールドのリストを 全て列挙したドキュメントはありません)。
データベース保存用のデータ準備処理 各フィールドについて、フィー ルドの現在の値を元にデータベースに保存できる型のデータを生成します。
ほとんどのフィールドはデータ準備処理を 伴いません 。整数や文字列は Python オブジェクトとして「いつでもデータベースへの書き込みに使える」 形式になっています。ただ、より複雑なデータ型の場合、なにがしかの修飾 が必要なことがあります。
例えば、 DateField は、データの保存に Python の datetime 型 を使います。データベースは datetime オブジェクトを保存しないので、 データベースに保存するには、フィールドの値を ISO 準拠の日付文字列に 変換せねばなりません。
データベースへの保存 前処理と準備処理を経たデータが SQL 文に組み 込まれ、データベースに挿入されます。
``post_save`` シグナルの発行 ` django.db.models.signals.pre_save シグナルと同じく、オブジェ クトが成功理に保存されたことを通知するために django.db.models.signals.post_save シグナルが発行されます。
Django データベースオブジェクトがオブジェクトの作成と変更に同じ save() メソッドを使っていることにお気づきかもしれませんね。 Django は INSERT と UPDATE SQL 文のどちらを使うべきかの判断を抽象化しています。具体的 に言うと、 save() を呼び出したときに、Django は以下のアルゴリズムに従い ます:
新たなオブジェクトを保存する際、まだ使われていない値を主キーに指定できる保 証がないかぎり、主キーの値を明示的に指定しないよう注意してください。詳しく は上記の 自動主キーの値を明示的に指定する の節や、後述の INSERT や UPDATE を強制する を参照してください。
ごく稀に、 save() メソッドに INSERT だけを実行させ、 UPDATE に フォールバックさせたくない、あるいはその逆、すなわち UPDATE が可能なら 実行するが、新たなレコードの INSERT はさせたくないような場合があります。 そんなときには、 force_insert=True や force_update=True パラメタを save() メソッドに渡してください。 INSERT と UPDATE は同時に行え ないので、両方のパラメタを同時に渡すとエラーを引き起こします。
このパラメタが必要なケースは本当にごく稀な場合だけです。たいていは、 Django は正しい SQL で保存を行いますし、パラメタをオーバライドすると、追跡の困難な エラーにつながる恐れがあります。特殊な用途でだけ、このパラメタを使ってくだ さい。
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 can be optimized slightly by expressing the update relative to the original field value, rather than as an explicit assignment of a new value. Django provides F() expressions as a way of performing this kind of relative update. Using F() expressions, the previous example would be 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.
モデルには、特殊な使われ方をするメソッドがあります:
__str__() は、オブジェクトに対して str() を呼び出した際に返す内容を 定義するための Python の特殊メソッドです。 Django はそこかしこで str(obj) (または unicode(obj) -- 下記参照) を使っています。ほとんど は、 Django の admin サイトでオブジェクトをレンダリングして表示したときの値 として、またオブジェクトを表示するときにテンプレートに挿入される値として使 われています。従って、オブジェクトの __str__ は、人間可読なわかりやすい 文字列を返さねばなりません。必須ではありませんが、強く推奨します (ただし、 そこかしこに __str__ メソッドを突っ込んでしまう前に __unicode__ の 説明を良く読んでくださいね)。
例を示します:
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))
__unicode__() メソッドは、オブジェクトに対して unicode() を呼び出し た際に呼び出されます。Django のデータベースバックエンドはモデルの属性値とし て Unicode 文字列を返すので、通常はモデルの __unicode__() メソッドを定 義するとよいでしょう。前節の例を __unicode__() を使って書き直すと、以下 のように簡単になります:
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 任せ にするよう勧めます。
オブジェクトの URL を演算する方法を Django に教えるには get_absolute_url メソッドを定義してください。例えば:
def get_absolute_url(self):
return "/people/%i/" % self.id
Django はこのメソッドを admin インタフェースで使います。オブジェクトが get_absolute_url() を定義していた場合、オブジェクトの詳細ページには「サ イト上で表示 (View on site)」というリンクが表示されます。このリンクは、オブ ジェクトの get_absolute_url() に基づいて、オブジェクトを公開しているビュー に直接飛べるようになっています。
また、その他にも、例えば 配信フィードフレームワーク などで、 get_absolute_url() を使うことでユーザの利便性を高めています。
テンプレートでオブジェクトの URL を表示する場合、ハードコードするのでは なく get_absolute_url() を使うようにするとよいでしょう。例えば、以下の テンプレート:
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
は良い例ではなく、以下のようにするとよいでしょう:
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
ノート
get_absolute_url() の返す文字列は ASCII 文字だけで構成しなければな りません (RFC 2396 の URI 仕様でそのように要求されています)。また、 必要に応じて URL エンコードせねばなりません。 get_absolute_url() を 使うコードやテンプレートが、 get_absolute_url() の返す文字列を、追 加の処理を施さなくても直接利用できるようにせねばならないのです。 URI に Unicode 文字列を沢山使っているのなら、 django.utils.encoding.iri_to_uri() も使うことになるでしょう。
上に述べた get_absolute_url() には、いささか DRY 則の侵犯である、すなわ ちURLconf とモデルの両方で URL が定義されているという問題があります。
permalink デコレータを使うと、 URLconf からモデルを脱カップリングできま す:
このデコレータには、ビュー関数、引数のリスト、そして (オプションとして) 名前つきパラメタの入った辞書を指定します。これらの情報から、 Django は 指定したパラメタで URLconf を置き換えて完全な URL パスを計算します。例えば、 以下のような URLconf が定義されていたとしましょう:
(r'^people/(\d+)/$', 'people.views.details'),
また、モデルの get_absolute_url メソッドは以下のように定義できます:
from django.db import models
@models.permalink
def get_absolute_url(self):
return ('people.views.details', [str(self.id)])
また、以下のような URLconf のエントリがあったとします:
(r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', archive_view)
permalink() は以下のように使えます:
@models.permalink
def get_absolute_url(self):
return ('archive_view', (), {
'year': self.created.year,
'month': self.created.month,
'day': self.created.day})
この例では、第 2 引数に空の配列 (空のタプル) を指定していますが、これは引数 リストを渡さず、キーワード引数だけを渡したいからです。
permalink を使えば、 URL に関する情報を繰り返すことなく、モデルの絶対 URL と表示に使ったビューを結びつけられます。以前と同様、 get_absolute_url はテンプレート中でも使えます。
汎用ビューを使う場合や、複数のモデルに対して同じビューを再利用する場合、ビュー 関数そのものを指定すると、(複数のパターンが同じビューを指してしまうため) URLディスパッチャが混乱をきたします。
この問題を解決するために、 Django には 名前つき URL パターン があります。 名前つき URL パターンを使えば、 URL パターンに固有の名前をつけておき、ビュー 関数の代わりに参照できます。名前つき URL パターンを定義するには、タプル表記 の URL パターンを url 関数に置き換えます:
from django.conf.urls.defaults import *
url(r'^people/(\d+)/$',
'django.views.generic.list_detail.object_detail',
name='people_view'),
この名前を使って、URL からビューの名前を以下のようにして逆解決します:
from django.db.models import permalink
def get_absolute_url(self):
return ('people_view', [str(self.id)])
get_absolute_url = permalink(get_absolute_url)
名前つき URL パターンの詳細は URL ディスパッチャのドキュメント を参照してください。
save(), delete() に加えて、モデルオブジェクトは以下のいずれか、あるい は全てのメソッドを持つことがあります:
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'
null=True であるような DateField および DateTimeField フィール ドについて、オブジェクトは get_next_by_FOO() および get_previous_by_FOO() メソッドを持ちます。 FOO はフィールド名です。 このメソッドは該当の日付フィールドに応じて前のオブジェクトや次のオブジェク トを返します。適切なオブジェクトがなければ DoesNotExist を送出します。
これらのメソッドはいずれもオプションのキーワード引数をとります。引数は 前述の「 Field lookups 」で解説した形式にします。
同じ日付値を持つオブジェクトがある場合、このメソッドは ID を使ったチェック にフォールバックします。これにより、レコードがスキップしたり重複したりしな いことが保証されています。
Aug 19, 2010