revision-up-to: | 11321 (1.1) |
---|
モデルリファレンス ドキュメントでは、
CharField
や
DateField
といった、 Django の標準のフィールドク
ラスの使用法について説明しています。ほとんどの用途には、これらの標準フィー
ルドクラスだけで十分でしょう。とはいえ、現行の Django が自分の要求をうまく
満たしていない場合や、 Django が提供しているものと全く異なるフィールドを使
いたい場合もあるでしょう。
Django の組み込みフィールド型は、データベースのカラムとして利用できる全ての
データ型をサポートしているわけではなく、 VARCHAR
や INTEGER
のよう
な一般的な型しかサポートしていません。幾何多角形 (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 のモデルフィールドは、そのフィールドに関係のないオプショ
ンも引数に指定できます。例えば、
editable
と
auto_now
の両方を
DateField
に指定してもよく、
DateField
は
(auto_now
を指定すると
editable=False
なので) editable
パ
ラメタを無視します。この場合、エラーは送出されません。
このような挙動にしておくと、不要なオプションをいちいちチェックしなくて よいので、フィールドクラスの定義が簡単になります。サブクラスでは、単に 全てのオプションを親クラスに渡しておけばよく、それ以上何もしなくてよい のです。選べるオプションを厳しく制限してもよいですし、簡単にしたければ、 何でも指定できるようにしておけばよいのです。
__init__()
メソッドは、以下のパラメタを (並び
順通りに) 取ります:
verbose_name
name
primary_key
max_length
unique
blank
null
db_index
core
rel
: (ForeignKey
のような) リレーションに関するフィールドで使います。高度な用途でしか必要ありま せん。default
editable
serialize
:False
の場合、モデルイ ンスタンスを シリアライザ に渡しても、 フィールドをシリアライズしません。デフォルトの値はTrue
です。prepopulate_from
unique_for_date
unique_for_month
unique_for_year
validator_list
choices
help_text
db_column
db_tablespace
: 現状は Oracle バックエ ンドだけで使っています。インデクス生成に使います。通常、このオプショ ンは無視できます。
上のリストで解説のないオプションは、通常の Django のフィールドと同じ意味を 持っています。詳しくは モデルのドキュメント を参 照してください。
SubfieldBase
メタクラス¶はじめに でも説明したように、フィールド型のサブクラスが必要な理由は主に 二つあります。一つはカスタムのデータベースカラム型を利用したい場合、もう一 つは複雑な Python のデータ型を扱いたい場合です。もちろん、二つを合わせて実 現するのも可能です。カスタムのデータベースカラム型を扱っているだけで、かつ Python からモデルフィールドを扱うときのデータ型が、データベースバックエンド から取り出したデータの型と一致している場合には、この節を気にする必要はあり ません。
Hand
クラスのようにカスタムの Python 型を扱うフィールドを作成したい場合、
Django がモデルのインスタンスを生成して、フィールドのアトリビュート値をデー
タベースに保存する時に、フィールドの値を適切な Python オブジェクトに変換す
る必要があります。この処理のからくりはやや複雑ですが、 Field
クラスを定
義するときに書かねばならないコードはいたって単純で、特殊なメタクラスを使っ
てサブクラスを作成するだけです:
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 生成コードはこの
フィールドの処理をスキップします。もちろん、その場合には、何らかの方法で正
しいテーブルに正しいカラムを生成する必要があります。
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()
は自動的に呼び出されません。
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_now
や
auto_now_add
で生成された場合、このメソッド
を使って正しい値をセットします。
このメソッドをオーバライドする場合、最後にアトリビュートの値を返さねばなり ません。また、フィールドの値を変更した場合、モデル上の対応する値も更新して、 モデルインスタンスを参照しているコードが正しい値を読み出せるようにせねばな りません。
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 が呼び出されます。
また、カスタムのフィールド型でサポートする照合タイプを制限したい場合にも、 このメソッドを定義する必要があるでしょう。
range
や in
を使った照合を行う場合、 get_db_prep_lookup は
引数として (適切な型の) オブジェクトのリストを受け取り、データベースに渡せ
るなにがしか適切な型のオブジェクトからなるリストに変換せねばなりません。
大抵の場合は get_db_prep_save を使い回したり、別のメソッドに共通の
処理を括り出しておけます。
例えば、以下のコードでは get_db_prep_lookup を実装して、照合タイプを
exact
と in
に制限しています:
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 型とデータベース、そしてシリア ライゼーション形式との間で複雑な変換を行う場合には、トリッキーな処理になり がちです。よりスムーズにフィールドを定義するためのアドバイスを、以下に示し ます:
- 既存のフィールド型定義 (
django/db/models/fields/__init__.py
にあります) を見て、インスピレーションを得ましょう。全く何もない状態 からスクラッチでフィールドを定義するのではなく、自分の実現したいこと に近い処理を行っているフィールド型を探して、それをちょっとだけ拡張す るようにしましょう。- フィールドとしてラップしたいクラスに、
__str__()
や__unicode__()
メソッドを定義しましょう。フィールドの処理におけ るデフォルトの動作として、ラップしているクラスのインスタンスに対してforce_unicode()
を呼び出すような処理が たくさんあります。 (このドキュメントの例では、value
はHand
のインスタンスであり、HandField
のインスタンスではないので)__unicode__()
メソッドを定義しておき、 Python オブジェクトが自 動的に文字列形式に変換されるようにしておけば、作業を大幅に減らせます。
FileField
のサブクラスを定義する¶上に挙げたメソッドに加えて、ファイルを扱うフィールドを定義するときには、い
くつか必要な条件があります。データベースストレージの操作やデータの取得など、
フィールド定義に必要なメカニズムのほとんどは FileField
で定義しています
が、特定のタイプのファイルをサポートするための処理はサブクラスに委ねていま
す。
Django はファイルのコンテンツや操作をプロキシする File
クラスを提供して
います。このクラスはサブクラス化でき、ファイルのアクセス方法やメソッドをカ
スタマイズできます。 File
クラスは django.db.models.fields.files
で
定義されており、デフォルトの動作は ファイルクラスのドキュメント で解説しています。
File
のサブクラスを作ったら、 FileField
サブクラスの attr_class
に指定して、 FileField
サブクラスに指定のファイルクラスを使うよう指示し
てください。
上に挙げた説明に加えて、カスタムフィールドのコードの効率や可読性を挙げるた めのガイドラインをいくつか示しておきます。
- Django の
ImageField
(django/db/models/fields/files.py
) は、FileField
をサブクラス化して特定のファイルタイプをサポートしてい る素晴らしい例題です。このクラスでは、上に述べたテクニックを余すとこ ろ無く使っています。- 可能な限り、ファイルの属性をキャッシュしましょう。ファイルは遠隔のス トレージシステム上にあるので、ファイルデータの取得には時間もお金もか かります。しかも、常に必要なわけではありません。一度ファイルを取得し て、コンテンツに関するデータを収集したら、データ可能な限りキャッシュ して、以後のアクセスでファイルを再取得する回数を減らしましょう。
Oct 26, 2017