# Django 5.2.8 ドキュメント

# Django オブジェクトのシリアライズ

Django のシリアライズフレームワークは、Django のモデルを他のフォーマットに「翻訳」する仕組みを提供します。通常、このような他のフォーマットはテキストベースや Django データをネットワーク越しに送信するために使われるフォーマットになりますが、シリアライザーはどんなフォーマットも (テキストベースと非テキストベースのいずれも) 処理可能です。

参考

あるデータをテーブルからシリアライズされた形式として取得したい場合、`dumpdata` 管理コマンドが使用できます。

## データのシリアライズ

最も高いレベルでは、次のようにデータをシリアライズできます。

    from django.core import serializers

    data = serializers.serialize("json", SomeModel.objects.all())

`serialize` 関数の引数は、データをシリアライズするフォーマット (シリアライズフォーマット) とシリアライズする `QuerySet` です。(実際、第2引数は Django モデルのインスタンスを yield するどんなイテレータでも渡せますが、ほとんど場合は QuerySet になります。)

django.core.serializers.get_serializer(format)

シリアライザーオブジェクトを次のように直接使用することもできます。

    JSONSerializer = serializers.get_serializer("json")
    json_serializer = JSONSerializer()
    json_serializer.serialize(queryset)
    data = json_serializer.getvalue()

これは次のようにデータをファイルライクなオブジェクト (`HttpResponse` を含む) に直接シリアライズしたい場合に便利です。

    with open("file.json", "w") as out:
        json_serializer.serialize(SomeModel.objects.all(), stream=out)

注釈

`get_serializer()` を未知の フォーマット で呼び出すと、`django.core.serializers.SerializerDoesNotExist` 例外が発生します。

### フィールドのサブセット

フィールドのサブセットのみをシリアライズしたい場合は、次のようにシリアライザーに `fields` 引数を指定できます。

    from django.core import serializers

    data = serializers.serialize("json", SomeModel.objects.all(), fields=["name", "size"])

この例では、各モデルの `name` と `size` 属性だけがシリアライズされます。主キーは常に出力結果内の `pk` 要素としてシリアライズされ、`fields` 部分には決して現れません。

注釈

モデルによってはフィールドのサブセットだけをシリアライズしたモデルをデシリアライズすることは不可能かもしれません。もしシリアライズしたオブジェクトがモデルで必須のすべてのフィールドを指定しなかった場合、デシリアライザーはデシリアライズされたインスタンスを保存できないでしょう。

### 継承されたモデル

抽象ベースクラス を使用して定義したモデルの場合、そのモデルをシリアライズするために特別なことは何もする必要がありません。シリアライズしたいオブジェクト (または複数のオブジェクト) 上でシリアライザーを呼べば、出力はシリアライズされたオブジェクトの完全な表現になります。

しかし、マルチテーブル継承 を利用したモデルの場合、そのモデルのすべてのベースクラスもシリアライズする必要があります。なぜなら、モデル上でローカルに定義されたフィールドだけがシリアライズされるためです。たとえば、次のようなモデルを考えてみてください。

    class Place(models.Model):
        name = models.CharField(max_length=50)

    class Restaurant(Place):
        serves_hot_dogs = models.BooleanField(default=False)

もし次のように Reastaurant モデルだけをシリアライズした場合、

    data = serializers.serialize("json", Restaurant.objects.all())

シリアライズされた出力のフィールドには、`serves_hot_dogs` 属性だけが含まれます。ベースクラスの `name` 属性は無視されます。

`Restaurant` インスタンスを完全にシリアライズするためには、`Place` モデルも同様にシリアライズする必要があります。

    all_objects = [*Restaurant.objects.all(), *Place.objects.all()]
    data = serializers.serialize("json", all_objects)

## データのデシリアライズ

データのデシリアライズも、シリアライズと非常によく似ています。

    for obj in serializers.deserialize("json", data):
        do_something_with(obj)

見ての通り、`deserialize` 関数は、`serialize` と同じ形式の引数であるデータの文字列またはストリームを取り、イテレータを返します。

しかし、ここで処理は少し複雑になります。`deserialize` イテレータによって返されるオブジェクトは、通常の Django オブジェクト ではありません。代わりに、作成された (ただし、保存されていない) オブジェクトと関連するリレーションデータをラップした、特別な `DeserializedObject` インスタンスです。

`DeserializedObject.save()` を呼ぶと、オブジェクトはデータベースに保存されます。

注釈

もしシリアライズされたデータ内に `pk` 属性が存在しないか、null だった場合、新しいインスタンスがデータベースに保存されます。

これにより、もしシリアライズされた表現内のデータが現在データベース内にあるデータと一致しなかったとしても、デシリアライズ処理は非破壊的な操作であることが保証されます。通常、`DeserializedObject` インスタンスを用いた操作は、次のようになります。

    for deserialized_object in serializers.deserialize("json", data):
        if object_should_be_saved(deserialized_object):
            deserialized_object.save()

言い換えれば、通常の使用では、デシリアライズされたオブジェクトが保存する前に保存するのに「適している」ことを確認します。もしデータソースを信頼しているなら、代わりにオブジェクトを直接保存してそのまま先に進めます。

Django オブジェクト自体は、`deserialized_object.object` として検査できます。シリアライズされたデータ内のフィールドがモデル上に存在しない場合は、`ignorenonexistent` 引数に `True` が渡されていない限り、`DeserializationError` が発生します。

    serializers.deserialize("json", data, ignorenonexistent=True)

## シリアライズフォーマット

Django は多数のシリアライズフォーマットをサポートしてします。一部のフォーマットはサードパーティの Python モジュールが必要です。

識別子 | 情報
--- | ---
`xml` | シンプルな XML 方言のシリアライズ・デシリアライズを行います。
`json` | JSON のシリアライズ・デシリアライズを行います。
`jsonl` | JSONL のシリアライズ・デシリアライズを行います。
`yaml` | YAML (YAML Ain't a Markup Language) のシリアライズ・デシリアライズを行います。このシリアライザーは PyYAML がインストールされている場合のみ利用できます。

### XML

基本的なXMLのシリアライズフォーマットは以下のようなものです:

    <?xml version="1.0" encoding="utf-8"?>
    <django-objects version="1.0">
        <object pk="123" model="sessions.session">
            <field type="DateTimeField" name="expire_date">2013-01-16T08:16:59.844560+00:00</field>
            <!-- ... -->
        </object>
    </django-objects>

シリアライズまたはデシリアライズされたオブジェクトのコレクション全体は、複数の `<object>` 要素を含む `<djangoobjects>` タグで表現されます。このようなオブジェクトはそれぞれ2つの属性を持ちます。"pk" と "model" です。後者はアプリの名前 ("sessions") とモデルの小文字の名前 ("session") をドットで区切って表します。

オブジェクトの各フィールドは "type "と "name "のフィールドを持つ `<field>` 要素としてシリアライズされます。要素のテキストコンテンツは格納されるべき値を表します。

外部キーとその他のリレーション先フィールドは、少し違う扱いになります:

    <object pk="27" model="auth.permission">
        <!-- ... -->
        <field to="contenttypes.contenttype" name="content_type" rel="ManyToOneRel">9</field>
        <!-- ... -->
    </object>

この例では、PK 27の `auth.Permission` オブジェクトが、PK 9の `contenttypes.ContentType` インスタンスに対する外部キーを持つように指定しています。

多対多のリレーションはそれらを結びつけるモデルに対してエクスポートされます。例えば、`auth.User` モデルは `auth.Permission` モデルに対してこのようなリレーションを持っています:

    <object pk="1" model="auth.user">
        <!-- ... -->
        <field to="auth.permission" name="user_permissions" rel="ManyToManyRel">
            <object pk="46"></object>
            <object pk="47"></object>
        </field>
    </object>

この例では、与えられたユーザーをPK46と47を持つパーミッションモデルにリンクしています。

制御文字

シリアライズされるコンテンツにXML 1.0標準では認められていない制御文字が含まれている場合、 `ValueError` 例外が発生してシリアライズは失敗します。詳しくはW3Cの HTML, XHTML, XML and Control Codes の説明を参照してください。

### JSON

以前と同じ例のデータを使うと、データは JSON として次のようにシリアライズされます。

    [
        {
            "pk": "4b678b301dfd8a4e0dad910de3ae245b",
            "model": "sessions.session",
            "fields": {
                "expire_date": "2013-01-16T08:16:59.844Z",
                # ...
            },
        }
    ]

このフォーマットは、XML よりも少しシンプルです。コレクション全体は array として表現され、オブジェクトは3つのプロパティ "pk"、"model"、"fields" を持つ JSON オブジェクトとして表現されています。"fields" もオブジェクトであり、各フィールド名と値がそれぞれプロパティとプロパティ値として含まれています。

外部キーは、プロパティ値としてリンクされたオブジェクトの PK を持ちます。ManyToMany リレーションは、それを定義したモデルに対してシリアライズされ、PK のリストとして表現されます。

すべての Django 出力が未修正のまま `json` に渡せるとは限らないことに注意してください。たとえば、シリアライズするオブジェクトにカスタム型がある場合、そのためのカスタム `json` エンコーダを書く必要があります。以下のようなものが機能します。

    from django.core.serializers.json import DjangoJSONEncoder

    class LazyEncoder(DjangoJSONEncoder):
        def default(self, obj):
            if isinstance(obj, YourCustomType):
                return str(obj)
            return super().default(obj)

そして、`cls=LazyEncoder` を `serializers.serialize()` 関数に渡します。

    from django.core.serializers import serialize

    serialize("json", SomeModel.objects.all(), cls=LazyEncoder)

GeoDjango は カスタマイズされた GeoJSON シリアライザー を提供していることにも注意してください。

#### `DjangoJSONEncoder`

class django.core.serializers.json.DjangoJSONEncoder

JSON シリアライザーは `DjangoJSONEncoder` をエンコーディングに使用します。`JSONEncoder` のサブクラスであり、以下の追加の型を処理します。

`datetime`

  ECMA-262 で定義されている `YYYY-MM-DDTHH:mm:ss.sssZ` または `YYYY-MM-DDTHH:mm:ss.sss+HH:MM` という形式の文字列。

`date`

  `YYYY-MM-DD` という形式の文字列は、ECMA-262 で定義されています。

`time`

  `HH:MM:ss.sss` という形式の文字列は、ECMA-262 で定義されています。

`timedelta`

  期間を表現する文字列は ISO-8601 で定義されています。たとえば、`timedelta(days=1, hours=2, seconds=3.4)` は `'P1DT02H00M03.400000S'` と表現されます。

`Decimal`, `Promise` (`django.utils.functional.lazy()` objects), `UUID`

  オブジェクトの文字列表現です。

### JSONL

JSONL は JSON Lines の略です。このフォーマットでは、オブジェクトは改行で区切られ、各行には有効なJSONオブジェクトが含まれます。JSONLでシリアライズされたデータは次のようになります:

    {"pk": "4b678b301dfd8a4e0dad910de3ae245b", "model": "sessions.session", "fields": {...}}
    {"pk": "88bea72c02274f3c9bf1cb2bb8cee4fc", "model": "sessions.session", "fields": {...}}
    {"pk": "9cf0e26691b64147a67e2a9f06ad7a53", "model": "sessions.session", "fields": {...}}

JSONLは、データを一度にメモリに読み込むのではなく、一行ずつ処理できるため、大規模なデータベースにデータを入力するのに便利です。

### YAML

YAML シリアライズは JSON にとてもよく似ています。オブジェクトリストは "pk"、"model"、"fields" を持つマッピングのシーケンスとしてシリアライズされます。各フィールドもマッピングで、キーがフィールド名、値が値になります。

    - model: sessions.session
      pk: 4b678b301dfd8a4e0dad910de3ae245b
      fields:
        expire_date: 2013-01-16 08:16:59.844560+00:00

参照フィールドは、同様に PK または PK のシーケンスとして表現されます。

### カスタムのシリアライズ形式

デフォルトの形式に加えて、カスタムのシリアライズ形式を作成することもできます。

たとえば、CSV のシリアライザとデシリアライザを考えてみましょう。まず、`Serializer` クラスと `Deserializer` クラスを定義します。これらは既存のシリアライズ形式のクラスをオーバーライドすることができます：

`path/to/custom_csv_serializer.py`

     import csv

     from django.apps import apps
     from django.core import serializers
     from django.core.serializers.base import DeserializationError

     class Serializer(serializers.python.Serializer):
         def get_dump_object(self, obj):
             dumped_object = super().get_dump_object(obj)
             row = [dumped_object["model"], str(dumped_object["pk"])]
             row += [str(value) for value in dumped_object["fields"].values()]
             return ",".join(row), dumped_object["model"]

         def end_object(self, obj):
             dumped_object_str, model = self.get_dump_object(obj)
             if self.first:
                 fields = [field.name for field in apps.get_model(model)._meta.fields]
                 header = ",".join(fields)
                 self.stream.write(f"model,{header}\n")
             self.stream.write(f"{dumped_object_str}\n")

         def getvalue(self):
             return super(serializers.python.Serializer, self).getvalue()

     class Deserializer(serializers.python.Deserializer):
         def __init__(self, stream_or_string, **options):
             if isinstance(stream_or_string, bytes):
                 stream_or_string = stream_or_string.decode()
             if isinstance(stream_or_string, str):
                 stream_or_string = stream_or_string.splitlines()
             try:
                 objects = csv.DictReader(stream_or_string)
             except Exception as exc:
                 raise DeserializationError() from exc
             super().__init__(objects, **options)

         def _handle_object(self, obj):
             try:
                 model_fields = apps.get_model(obj["model"])._meta.fields
                 obj["fields"] = {
                     field.name: obj[field.name]
                     for field in model_fields
                     if field.name in obj
                 }
                 yield from super()._handle_object(obj)
             except (GeneratorExit, DeserializationError):
                 raise
             except Exception as exc:
                 raise DeserializationError(f"Error deserializing object: {exc}") from exc

次に、シリアライザ定義を含むモジュールを `SERIALIZATION_MODULES` 設定に追加します：

    SERIALIZATION_MODULES = {
        "csv": "path.to.custom_csv_serializer",
        "json": "django.core.serializers.json",
    }

Changed in Django 5.2:

提供されている各シリアライズ形式に対して、 `Deserializer` クラスの定義が追加されました。

## ナチュラルキー

デフォルトの外部キーと多対多リレーションのシリアライズ戦略は、オブジェクトのプライマリーキーの値をリレーション内にシリアライズするというものです。この戦略はほとんどのオブジェクトに対してうまく機能しますが、いくつかの状況で困難を引き起こします。

`ContentType` を参照する外部キーを持つオブジェクトのリストの場合を考えてみてください。もしcontent type を参照するオブジェクトをシリアライズしようとした場合、最初に content type を参照する手段が必要になります。`ContentType` オブジェクトは Django がデータベースの同期処理の間に自動的に作成するため、与えられた content type のプライマリーキーは簡単には予測できず、`migrate` が実行される方法とタイミングに依存することになってしまいます。同じことは、特に `Permission`、`Group`、`User` を含む、オブジェクトを自動生成するすべてのモデルにも当てはまります。

警告

自動生成されたオブジェクトは、決してフィクスチャや他のシリアライズされたデータに含めるべきではありません。偶然、フィクスチャ内のプライマリーキーがデータベース内のものと一致して、フィクスチャの読み込みに効果がないかもしれません。より起こりえる状況はプライマリーキーが一致しなかった場合で、フィクスチャのロードは `IntegrityError` で失敗してしまいます。

利便性の問題もあります。integer id というのは、必ずしもオブジェクトを参照するための最も便利な方法というわけではありません。ときには、より自然な (ナチュラルな) 参照が助けになることがあります。

このような理由のために Django が提供しているのが、ナチュラルキー (natural key) です。ナチュラルキーは、オブジェクトのインスタンスをプライマリーキーの値を使用せずに一意に識別するために使える値のタプルです。

### ナチュラルキーのデシリアライズ

次の2つのモデルを考えてみてください。

    from django.db import models

    class Person(models.Model):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)

        birthdate = models.DateField()

        class Meta:
            constraints = [
                models.UniqueConstraint(
                    fields=["first_name", "last_name"],
                    name="unique_first_last_name",
                ),
            ]

    class Book(models.Model):
        name = models.CharField(max_length=100)
        author = models.ForeignKey(Person, on_delete=models.CASCADE)

通常は、`Book` のシリアライズされたデータは、著者 (author) を参照するために整数を使うことになります。たとえば、JSON では、Book は次のようにシリアライズされるでしょう。

    ...
    {"pk": 1, "model": "store.book", "fields": {"name": "Mostly Harmless", "author": 42}}
    ...

これは、著者を参照するのに特に自然な方法とは言えません。著者のプライマリーキーの値を知っていなければなりませんし、しかも、プライマリーキーの値は安定していて予測可能でなければなりません。

しかし、Person にナチュラルキーの処理を追加した場合、フィクスチャはもっとずっと人間によってわかりやすくなります。ナチュラルキーの処理を追加するには、Person のデフォルトの Manager を `get_by_natural_key()` を使用して定義します。Person の場合、よいナチュラルキーは、first name と last name のペアになるでしょう。

    from django.db import models

    class PersonManager(models.Manager):
        def get_by_natural_key(self, first_name, last_name):
            return self.get(first_name=first_name, last_name=last_name)

    class Person(models.Model):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        birthdate = models.DateField()

        objects = PersonManager()

        class Meta:
            constraints = [
                models.UniqueConstraint(
                    fields=["first_name", "last_name"],
                    name="unique_first_last_name",
                ),
            ]

新しい本では、`Person` オブジェクトを参照するためにナチュラルキーが使えます。

    ...
    {
        "pk": 1,
        "model": "store.book",
        "fields": {"name": "Mostly Harmless", "author": ["Douglas", "Adams"]},
    }
    ...

シリアライズされたデータをロードしようとするとき、Django は `get_by_natural_key()` メソッドを使って `["Douglas", "Adams"]` を実際の `Person` オブジェクトのプライマリーキーに解決します。

注釈

ナチュラルキーに使用するフィールドは、オブジェクトを一意に識別できる必要があります。これは通常、モデルがナチュラルキーのフィールドや複数フィールドに対してユニーク制約 (単一フィールドに対する `unique=True`、または複数フィールドにわたる `UniqueConstraint` や `unique_together`) を持つことを意味します。しかし、一意性がデータベースレベルで強制される必要はありません。一連のフィールドが実際に一意であるという確信がある場合は、それらのフィールドをナチュラルキーとして使用できます。

プライマリーキーがないオブジェクトのデシリアライズには、モデルのマネージャに `get_by_natural_key()` メソッドがあるかどうかを常にチェックします。ある場合は、これを使用して、デシリアライズされるオブジェクトのプライマリーキーを設定します。

### ナチュラルキーのシリアライズ

それでは、オブジェクトをシリアライズするときに、Django にナチュラルキーを発行させるにはどうすればいいのでしょうか？ はじめに、もう1つのメソッドを追加する必要があります。今回は、次のようにモデル自体に追加します。

    class Person(models.Model):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
        birthdate = models.DateField()

        objects = PersonManager()

        class Meta:
            constraints = [
                models.UniqueConstraint(
                    fields=["first_name", "last_name"],
                    name="unique_first_last_name",
                ),
            ]

        def natural_key(self):
            return (self.first_name, self.last_name)

メソッドは、常にナチュラルキーの他ルプを返す必要があります。この例では、`(first name, last name)` です。そして、`serializers.serialize()` を呼ぶときに、`use_natural_foreign_keys=True` または `use_natural_primary_keys=True` 引数を提供します。

    >>> serializers.serialize(
    ...     "json",
    ...     [book1, book2],
    ...     indent=2,
    ...     use_natural_foreign_keys=True,
    ...     use_natural_primary_keys=True,
    ... )

`use_natural_foreign_keys=True` が指定されたときは、Django は `natural_key()` メソッドを使用して、メソッドを定義している型のオブジェクトへの外部キーの参照をシリアライズします。

`use_natural_primary_keys=True` が指定されたときは、Django はこのオブジェクトのシリアライズされたデータ内に、プライマリーキーを提供しません。プライマリーキーは、デシリアライズ時に計算可能であるためです。

    ...
    {
        "model": "store.person",
        "fields": {
            "first_name": "Douglas",
            "last_name": "Adams",
            "birth_date": "1952-03-11",
        },
    }
    ...

これは、シリアライズされたデータを既存のデータベースに読み込む必要があり、シリアライズされた主キーの値がすでに使用されていないことを保証できず、デシリアライズされたオブジェクトが同じ主キーを保持していることを保証する必要がない場合に便利です。

`dumpdata` を使用してシリアライズデータを生成する場合は、 `dumpdata --natural-foreign` と `dumpdata --natural-primary` コマンドラインフラグを使用してナチュラルキーを生成します。

注釈

`natural_key()` と `get_by_natural_key()` の両方を定義する必要はありません。もし Django にシリアライズ時にナチュラルキーを出力させたくないが、 ナチュラルキーを読み込む機能は残しておきたい場合は、 `natural_key()` メソッドを実装しなくても構いません。

逆に、（特別な理由で）Django にシリアライズ時にナチュラルキーを出力させたいが、そのキーの値を読み込ませたく ない 場合は、 `get_by_natural_key()` メソッドを定義しなければいいだけです。

### ナチュラルキーと前方参照

ナチュラル外部キー を使用するとき、データをシリアライズする必要があるけれども、オブジェクトの外部キーが参照している他のオブジェクトが、まだシリアライズされていないような場合があります。このことを「前方参照 (forward reference)」と呼びます。

たとえば、フィクスチャに次のようなオブジェクトがあると想定してください。

    ...
    {
        "model": "store.book",
        "fields": {"name": "Mostly Harmless", "author": ["Douglas", "Adams"]},
    },
    ...
    {"model": "store.person", "fields": {"first_name": "Douglas", "last_name": "Adams"}},
    ...

この状況を処理するには、`serializers.deserialize()` に `handle_forward_references=True` を渡す必要があります。これにより、`DeserializedObject` インスタンスに `deferred_fields` 属性が設定されます。この属性が `None` ではない `DeserializedObject` インスタンスを追跡して、後でそれらに対して `save_deferred_fields()` を呼び出す必要があります。

典型的な使用方法は次のようになります。

    objs_with_deferred_fields = []

    for obj in serializers.deserialize("json", data, handle_forward_references=True):
        obj.save()
        if obj.deferred_fields is not None:
            objs_with_deferred_fields.append(obj)

    for obj in objs_with_deferred_fields:
        obj.save_deferred_fields()

これが機能するには、参照しているモデル上の `ForeignKey` に `null=True` が設定されている必要があります。

### シリアライズ中の依存関係

フィクスチャ内のオブジェクトの順番に注意することで、明示的に前方参照を扱わずに済むことがよくあります。

これを支援するために、 `dumpdata --natural-foreign` オプションを使用して `dumpdata` を呼び出すと、標準の主キーオブジェクトをシリアライズする前に、`natural_key()` メソッドを持つ任意のモデルがシリアライズされます。

しかし、これは必ずしも十分とは限りません。ナチュラルキーが別のオブジェクトを参照する場合 (ナチュラルキーの一部として外部キーまたは別のオブジェクトへのナチュラルキーを使用する場合)、ナチュラルキーが依存するオブジェクトが、ナチュラルキーが要求する前にシリアライズされたデータ内に存在することを保証できる必要があります。

この順序を制御するには、 `natural_key()` メソッドに依存関係を定義します。これは `natural_key()` メソッド自体に `dependencies` 属性を設定することで行います。

たとえば、上の例の `Book` モデルにナチュラルキーを追加してみましょう:

    class Book(models.Model):
        name = models.CharField(max_length=100)
        author = models.ForeignKey(Person, on_delete=models.CASCADE)

        def natural_key(self):
            return (self.name,) + self.author.natural_key()

`Book` のナチュラルキーは名前と著者の組み合わせです。つまり、 `Person` は `Book` の前にシリアライズされなければなりません。この依存関係を定義するために、1行追加します:

    def natural_key(self):
        return (self.name,) + self.author.natural_key()

    natural_key.dependencies = ["example_app.person"]

この定義により、すべての `Person` オブジェクトは `Book` オブジェクトよりも先にシリアライズされます。また、`Book` を参照するオブジェクトは `Person` と `Book` の両方がシリアライズされた後にシリアライズされます。