データのエクスポートとインポート

□未翻訳

□翻訳中

■翻訳完了(細田謙二)

■レビュー(Omi Chiba)

データのエクスポートとインポート

CSV(一度に1つのテーブル)

CSV (one table at a time)

DALのRowsオブジェクトが文字列に変換されるとき、自動的にCSV形式にシリアライズされます:

When a DALRows object is converted to a string it is automatically serialized in CSV:

1.

2.

3.

4.

5.

6.

>>> rows = db(db.person.id==db.dog.owner).select()

>>> print rows

person.id,person.name,dog.id,dog.name,dog.owner

1,Alex,1,Skipper,1

1,Alex,2,Snoopy,1

2,Bob,3,Puppy,2

単一のテーブルをCSV形式にシリアライズして、"test.csv"ファイルに保存することができます:

You can serialize a single table in CSV and store it in a file "test.csv":

1.

>>> open('test.csv', 'w').write(str(db(db.person.id).select()))

そして、次のようにして簡単にそれを読み取ることができます:

and you can easily read it back with:

1.

>>> db.person.import_from_csv_file(open('test.csv', 'r'))

インポートするときに、web2pyはCSVのヘッダにあるフィールド名を探します。この例では、"person.name"と"person.id"という2つのカラムを見つけます。"person"という接頭辞と、"id"というフィールドは無視されます。そして、すべてのレコードは追加され、新しいIDが割り当てられます。これら両方の操作はappadminのWeb・インターフェースを介して行うことができます。

When importing, web2py looks for the field names in the CSV header. In this example, it finds two columns: "person.id" and "person.name". It ignores the "person." prefix, and it ignores the "id" fields. Then all records are appended and assigned new ids. Both of these operations can be performed via the appadmin web interface.

CSV(すべてのテーブルを一度に)

CSV (all tables at once)

web2pyでは、次の2つのコマンドでデータベース全体をバックアップ/復元することができます:

In web2py, you can backup/restore an entire database with two commands:

エクスポートするには:

To export:

1.

>>> db.export_to_csv_file(open('somefile.csv', 'wb'))

インポートするには:

To import:

1.

>>> db.import_from_csv_file(open('somefile.csv', 'rb'))

このメカニズムは、インポートしたデータベースがエクスポートするデータベースと異なるタイプのものでも使用することができます。データは"somefile.csv"にCSVファイルとして保存されます。このファイルでは、各テーブルは、テーブル名を示す一つの行と、フィールド名を持つもう1つの行から始まります。

This mechanism can be used even if the importing database is of a different type than the exporting database. The data is stored in "somefile.csv" as a CSV file where each table starts with one line that indicates the tablename, and another line with the fieldnames:

1.

2.

TABLE tablename

field1, field2, field3, ...

2つのテーブルは\r\n\r\nで区切られます。ファイルは次の行で終わります

Two tables are separated \r\n\r\n. The file ends with the line

1.

END

このファイルには、アップロードしたファイルは、それらがデータベースに保存されていない限り含まれません。どのような場合でも、"uploads"フォルダを個別に圧縮することは十分簡単です。

The file does not include uploaded files if these are not stored in the database. In any case it is easy enough to zip the "uploads" folder separately.

インポートするとき、新規のレコードは、データベースが空でない場合、データベースに追加されます。一般に、新しくインポートしたレコードは元の(保存した)レコードと同じレコードidを持つことはありません。しかし、web2pyは参照は復元するので、idの値が変化しても参照が機能しなくなることはありません。

When importing, the new records will be appended to the database if it is not empty. In general the new imported records will not have the same record id as the original (saved) records but web2py will restore references so they are not broken, even if the id values may change.

もしテーブルに"uuid"と呼ばれるフィールドが含まれる場合、そのフィールドは重複を識別するために使用されます。またもしインポートしたレコードが既存のレコードと同じ"uuid"を持つ場合、前のレコードは更新されます。

If a table contains a field called "uuid", this field will be used to identify duplicates. Also, if an imported record has the same "uuid" as an existing record, the previous record will be updated.

CSVとリモート・データベースの同期

CSV and Remote Database Synchronization

次のモデルを考えてください:

Consider the following model:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

db = DAL('sqlite:memory:')

db.define_table('person',

Field('name'),

format='%(name)s')

db.define_table('dog',

Field('owner', db.person),

Field('name'),

format='%(name)s')

if not db(db.person.id>0).count():

id = db.person.insert(name="Massimo")

db.dog.insert(owner=id, name="Snoopy")

各レコードは、IDによって識別され、そのIDによって参照されます。別々にインストールしたweb2pyによって利用されるデータベースの2つのコピーを持っているなら、IDは各データベースにおいてのみユニークで、データベース全体ではユニークではありません。これは、異なるデータベースからレコードをマージするときに問題になります。

Each record is identified by an ID and referenced by that ID. If you have two copies of the database used by distinct web2py installations, the ID is unique only within each database and not across the databases. This is a problem when merging records from different databases.

データベース全体でレコードを一意に識別できるようにするには、レコードを次のようにする必要があります:

In order to make a record uniquely identifiable across databases, they must:

  • 一意のID(UUID)を持たせる

  • have a unique id (UUID),

  • event_timeを持たせる(複数のコピーにてどちらがより最近のものかを判別するために)

  • have an event_time (to figure out which one is more recent if multiple copies),

  • idの代わりにUUIDで参照する

  • reference the UUID instead of the id.

これはweb2pyを変更することなく実現できます。以下にどのようにするかを示します:

This can be achieved without modifying web2py. Here is what to do:

1. 上記のモデルを次のように変更します:

Change the above model into:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

18.

19.

db.define_table('person',

Field('uuid', length=64, default=uuid.uuid4()),

Field('modified_on', 'datetime', default=now),

Field('name'),

format='%(name)s')

db.define_table('dog',

Field('uuid', length=64, default=uuid.uuid4()),

Field('modified_on', 'datetime', default=now),

Field('owner', length=64),

Field('name'),

format='%(name)s')

db.dog.owner.requires = IS_IN_DB(db,'person.uuid','%(name)s')

if not db(db.person.id).count():

id = uuid.uuid4()

db.person.insert(name="Massimo", uuid=id)

db.dog.insert(owner=id, name="Snoopy")

2. データベースをエクスポートするコントローラのアクションを作成します:

Create a controller action to export the database:

1.

2.

3.

4.

5.

def export():

s = StringIO.StringIO()

db.export_to_csv_file(s)

response.headers['Content-Type'] = 'text/csv'

return s.getvalue()

3. 他のデータベースの保存したコピーをインポートし、レコードを同期するコントローラのアクションを作成します:

Create a controller action to import a saved copy of the other database and sync records:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

def import_and_sync():

form = FORM(INPUT(_type='file', _name='data'), INPUT(_type='submit'))

if form.accepts(request.vars):

db.import_from_csv_file(form.vars.data.file,unique=False)

# for every table

for table in db.tables:

# for every uuid, delete all but the latest

items = db(db[table].id>0).select(db[table].id,

db[table].uuid,

orderby=db[table].modified_on,

groupby=db[table].uuid)

for item in items:

db((db[table].uuid==item.uuid)&\

(db[table].id!=item.id)).delete()

return dict(form=form)

4. uuidによる検索を高速化するためにインデックスを手動で作成します。

Create an index manually to make the search by uuid faster.

ただし、ステップ2と3はすべてのデータベースモデルで機能します。これらはこの例に固有のものではないからです。

Notice that steps 2 and 3 work for every database model; they are not specific for this example.

別の方法として、XML-RPCを用いてファイルをエクスポート/インポートすることができます。

Alternatively, you can use XML-RPC to export/import the file.

レコードがアップロードしたファイルを参照する場合、uploadsフォルダの中身もまたエクスポート/インポートする必要があります。ただし、そこにあるファイルはUUIDですでにラベル付けされているので、名前の衝突と参照を心配する必要はありません。

If the records reference uploaded files, you also need to export/import the content of the uploads folder. Notice that files therein are already labeled by UUIDs so you do not need to worry about naming conflicts and references.

HTML/XMLの(一度に1つのテーブル)

HTML/XML (one table at a time)

DALのRowsオブジェクトはまた、(ヘルパのように)自身をXML/HTMLへとシリアライズするxmlメソッドを持ちます:

DALRows objects also have an xml method (like helpers) that serializes it to XML/HTML:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

18.

19.

20.

21.

22.

23.

>>> rows = db(db.person.id > 0).select()

>>> print rows.xml()

<table>

<thead>

<tr>

<th>person.id</th>

<th>person.name</th>

<th>dog.id</th>

<th>dog.name</th>

<th>dog.owner</th>

</tr>

</thead>

<tbody>

<tr class="even">

<td>1</td>

<td>Alex</td>

<td>1</td>

<td>Skipper</td>

<td>1</td>

</tr>

...

</tbody>

</table>

DALのRowsを、カスタムタグを持った他のXMLフォーマットへとシリアライズしたい場合は、普遍的なタグヘルパや*表記を使用して簡単に行うことができます:

If you need to serialize the DALRows in any other XML format with custom tags, you can easily do that using the universal TAG helper and the * notation:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

>>> rows = db(db.person.id > 0).select()

>>> print TAG.result(*[TAG.row(*[TAG.field(r[f], _name=f) \

for f in db.person.fields]) for r in rows])

<result>

<row>

<field name="id">1</field>

<field name="name">Alex</field>

</row>

...

</result>

データ表現

Data Representation

export_to_csv_file関数はキーワード引数representを受け入れます。Trueの場合、データのエクスポート中に、生のデータの代わりに、カラムのrepresent関数を用います。

The export_to_csv_file function accepts a keyword argument named represent. WhenTrue it will use the columns represent function while exporting the data instead of the raw data.

この関数はまた、エクスポートしたいカラムの名前のリストを保持するキーワード引数colnamesを受け入れます。デフォルトではすべてのカラムになります。

The function also accepts a keyword argument named colnames that should contain a list of column names one wish to export. It defaults to all columns.

export_to_csv_fileとimport_from_csv_fileの両方とも、CSVの構文解析機に保存/読み込み先のファイルのフォーマットを知らせる次のようなキーワード引数を受け入れます:

Both export_to_csv_file and import_from_csv_file accept keyword arguments that tell the csv parser the format to save/load the files:

  • delimiter: 値を区切る区切り文字(デフォルトは',')

  • delimiter to separate values (default ',')

  • quotechar: 文字列の値を引用するために使用する文字(デフォルトはダブルクォート)

  • character to use to quote string values (default to double quotes)

  • quoting: 引用体系(デフォルトはcsv.QUOTE_MINIMAL)

  • quote system (default csv.QUOTE_MINIMAL)

ここではいくつか使用例を示します:

Here is some example usage:

1.

2.

3.

4.

5.

6.

>>> import csv

>>> db.export_to_csv_file(open('/tmp/test.txt', 'w'),

delimiter='|',

quotechar='"',

quoting=csv.QOUTE_NONNUMERIC)

quoting=csv.QUOTE_NONNUMERIC)

これは次のようなものにレンダリングされます

Which would render something similar to

1.

"hello"|35|"this is the text description"|"2009-03-03"

より詳細な情報は公式のPythonドキュメントを参照してください。

For more information consult the official Python documentation 64