Djangoにおけるdumpdataとloaddata

  • 8月 10, 2007 08:10

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そのもので書いてるのと変わらないのではないかと疑問も感じます。