Djangoにおけるdumpdataとloaddata
Djangoは複数のアプリを入れておけるプロジェクトをまず作るのですが、そのときにコマンドラインユーティリティ(manage.py)が作られます。manage.pyでモデルをDBに反映させたり、テストサーバーを起動させたりするのですが、その中にデータをjson,xml,yaml(PyYamlが別途必要)形式で標準出力に出力できるdumpdataとloaddataというものがあります。 例えば
python manage.py dumpdata app_name --format=yaml > app.yaml
などとやるとアプリケーションapp_nameのデータをapp.yamlというファイルで保存できます。 (アプリ名を省略するとプロジェクト全てのデータを取る)
jsonの場合はインデントを指定することもできます
python manage.py dumpdata app_name --format=json --indent=2 > app.json
アプリのデータを一度リセットして
python manage.py reset app_name
再度読み込ませるにはloaddata
python manage.py loaddata app.yaml
また、
myproject(プロジェクト)/app_name(アプリ)/fixtures/initial_data.yaml
のようにアプリ直下にfixturesというフォルダを作ってinitial_dataという名前でデータを置いておくとsyncdbの時に自動でデータの読み込みがされます。
ところがなぜか失敗したので原因を調べていたら、ForeignKeyを使ったモデル間の連携があるアプリの場合dumpdataで出力するデータの順番が考慮されていないことがわかりました。
class Bbsthread(models.Model):
name = models.CharField(maxlength=200, blank=False)
class Entry(models.Model):
bbsthread = models.ForeignKey(Bbsthread)
body = models.TextField(blank=False)
created = models.DateTimeField(blank=True)
というモデルのデータをyamlでdumpdataしたときに
- fields: {bbsthread: 1, body: dfafd, created: !!timestamp '2007-08-10 11:28:59.468000'}
model: bbs.entry
pk: '1'
- fields: {bbsthread: 1, body: fafa, created: !!timestamp '2007-08-10 11:29:00.890000'}
model: bbs.entry
pk: '2'
- fields: {bbsthread: 2, body: fafd, created: !!timestamp '2007-08-10 11:29:06.265000'}
model: bbs.entry
pk: '3'
- fields: {name: d}
model: bbs.bbsthread
pk: '1'
- fields: {name: dfafa}
model: bbs.bbsthread
pk: '2'
と出力されたのですが、bbsthreadのpk1のデータはまだ作られていなにのにも関わらず、bbs.entryを読み込んだために 「bbsthread のpk=1のデータは存在しない」とエラーになってしまったようです。
後ろ6行のmodel: bbs.bbsthreadの部分をbbs.entryの前に手動で移動したら上手くいきました。
jsonはマルチバイトが文字化けしますが、MiCHiLuさんの 文字化けしない JSON serializer - MiCHiLU.com をやればOKです。
yamlはPyYamlが必要ですが easy_installで簡単にインストールできます。
日本語は
- fields: {bbsthread: 1, body: !!python/str "\u307B\u3052\u307B\u3052yaml\u3067\u306A\
\u304A\u3057\u305F", created: !!timestamp '2007-08-10 12:05:53.906000'}
model: bbs.entry
pk: '8'
こんな表示になってしまいますが
- fields: {bbsthread: 1, body: !!python/str "YAMLで変更", created: !!timestamp '2007-08-10 12:05:53.906000'}
model: bbs.entry
pk: '8'
このように、yaml内で変更して反映させることもできます(文字コードはUTF-8限定)。
PyYAMLはなかなかすばらしいのですが、「!!python/str」でよければPythonそのもので書いてるのと変わらないのではないかと疑問も感じます。