仮想フィールド

□未翻訳

□翻訳中

■翻訳完了(細田謙二)

■レビュー(Omi Chiba)

仮想フィールド

仮想フィールドもまた、(前節のように)計算されたフィールドですが、それらは異なります。なぜなら、データベースには保存されず、また、データベースからレコードが取り出されるたびに計算されるという点で仮想であるからです。追加の保存先なしに単純にユーザーコードを用いることができますが、それを用いて検索することはできません。

Virtual fields are also computed fields (as in the previous subsection) but they differ from those because they are virtual in the sense that they are not stored in the db and they are computed each time records are extracted from the database. They can be used to simplify the user's code without using additional storage but they cannot be used for searching.

1つ以上の仮想フィールドを定義するためには、コンテナクラスを定義し、インスタンス化し、テーブルまたは選択に対してリンクさせる必要があります。たとえば、次のようなテーブルを考えてください:

In order to define one or more virtual fields, you have to define a container class, instantiate it and link it to a table or to a select. For example, consider the following table:

1.

2.

3.

>>> db.define_table('item',

Field('unit_price','double'),

Field('quantity','integer'),

このとき、total_priceという仮想フィールドを次のように定義できます:

One can define a total_price virtual field as

1.

2.

3.

4.

>>> class MyVirtualFields(object):

def total_price(self):

return self.item.unit_price*self.item.quantity

>>> db.item.virtualfields.append(MyVirtualFields())

単一の引数(self)をとるこのクラスの各メソッドが、新規の仮想フィールドになることに注意してください。フィールドの値はself.item.unit_priceのように完全パスで参照されます。テーブルは、このクラスのインスタンスをテーブルのvirtualfields属性に追加することによって、この仮想フィールドにリンクされます。

Notice that each method of the class that takes a single argument (self) is a new virtual field.self refers to each one row of the select. Field values are referred by full path as inself.item.unit_price. The table is linked to the virtual fields by appending an instance of the class to the table's virtualfields attribute.

仮想フィールドもまた、次のように再帰的なフィールドにアクセスできます:

Virtual fields can also access recursive fields as in

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

>>> db.define_table('item',

Field('unit_price','double'))

>>> db.define_table('order_item',

Field('item',db.item),

Field('quantity','integer'))

>>> class MyVirtualFields(object):

def total_price(self):

return self.order_item.item.unit_price \

* self.order_item.quantity

>>> db.order_item.virtualfields.append(MyVirtualFields())

再帰的なフィールドはself.order_item.item.unit_priceにアクセスしていますが、ここで、selfはループで回されているレコードであることに注意してください。

Notice the recursive field access self.order_item.item.unit_price where self is the looping record.

これらは、結合(JOIN)の結果に対しても作用することができます:

They can also act on the result of a JOIN

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

>>> db.define_table('item',

Field('unit_price','double'))

>>> db.define_table('order_item',

Field('item',db.item),

Field('quantity','integer'))

>>> rows = db(db.order_item.item==db.item.id).select()

>>> class MyVirtualFields(object):

def total_price(self):

return self.item.unit_price \

* self.order_item.quantity

>>> rows.setvirtualfields(order_item=MyVirtualFields())

>>> for row in rows: print row.order_item.total_price

この場合、どのように構文が異なっているかに注意してください。仮想フィールドは、join選択に属しているself.item.unit_priceとself.order_item.quantityの両方にアクセスしています。仮想フィールドは行オブジェクトのsetvirtualfieldsメソッドを用いてテーブルの行に付け加えられます。このメソッドは任意の数の名前付き引数をとります。そして次のように、複数のクラスで定義された複数の仮想フィールドを設定し、それらを複数のテーブルに付け加えることができます:

Notice how in this case the syntax is different. The virtual field accesses bothself.item.unit_price and self.order_item.quantity which belong to the join select. The virtual field is attached to the rows of the table using the setvirtualfields method of the rows object. This method takes an arbitrary number of named arguments and can be used to set multiple virtual fields, defined in multiple classes, and attach them to multiple tables:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

>>> class MyVirtualFields1(object):

def discounted_unit_price(self):

return self.item.unit_price*0.90

>>> class MyVirtualFields2(object):

def total_price(self):

return self.item.unit_price \

* self.order_item.quantity

def discounted_total_price(self):

return self.item.discounted_unit_price \

* self.order_item.quantity

>>> rows.setvirtualfields(

item=MyVirtualFields1(),

order_item=MyVirtualFields2())

>>> for row in rows:

print row.order_item.discounted_total_price

仮想フィールドは遅延(lazy)することが可能です。そのためにやることは、次のように、関数を返すようにして、その関数を呼び出すことです:

Virtual fields can be lazy; all they need to do is return a function and access it by calling the function:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

>>> db.define_table('item',

Field('unit_price','double'),

Field('quantity','integer'),

>>> class MyVirtualFields(object):

def lazy_total_price(self):

def lazy(self=self):

return self.item.unit_price \

* self.item.quantity

return lazy

>>> db.item.virtualfields.append(MyVirtualFields())

>>> for item in db(db.item.id>0).select():

print item.lazy_total_price()

または、ラムダ関数を用いてより短くします:

or shorter using a lambda function:

1.

2.

3.

4.

>>> class MyVirtualFields(object):

def lazy_total_price(self):

return lambda self=self: self.item.unit_price \

* self.item.quantity