django-rest-framework 3.0 ネストされたシリアライザーで作成または更新する
質問
と django-rest-framework 3.0を使用しています。 で、これらの単純なモデルを持っています。
class Book(models.Model):
title = models.CharField(max_length=50)
class Page(models.Model):
book = models.ForeignKey(Books, related_name='related_book')
text = models.CharField(max_length=500)
そして、このJSONのリクエストを与えると
{
"book_id":1,
"pages":[
{
"page_id":2,
"text":"loremipsum"
},
{
"page_id":4,
"text":"loremipsum"
}
]
}
このJSONを処理するネストされたシリアライザーをどのように書けばよいのでしょうか?
page
に対して、与えられた
book
は、新しいページを作成するか、存在する場合は更新します。
class RequestSerializer(serializers.Serializer):
book_id = serializers.IntegerField()
page = PageSerializer(many=True)
class PageSerializer(serializers.ModelSerializer):
class Meta:
model = Page
シリアライザーをインスタンス化する際に
instance
でインスタンス化すると現在のものが更新されることは知っていますが、どのようにして
create
メソッドの中でどのように使えばよいのでしょうか?
どのように解決するのですか?
まず、新しいブックインスタンスの作成をサポートしたいのか、それとも既存のブックインスタンスの更新のみをサポートしたいのか。
もし、新しいブックインスタンスを作成したいだけなら、次のようなことができます。
class PageSerializer(serializers.Serializer):
text = serializers.CharField(max_length=500)
class BookSerializer(serializers.Serializer):
page = PageSerializer(many=True)
title = serializers.CharField(max_length=50)
def create(self, validated_data):
# Create the book instance
book = Book.objects.create(title=validated_data['title'])
# Create or update each page instance
for item in validated_data['pages']:
page = Page(id=item['page_id'], text=item['text'], book=book)
page.save()
return book
なお、私は
はしていません。
を含んでいます。
book_id
を追加していません。ブックインスタンスを作成するときには、ブックIDを含めることはありません。ブックインスタンスを更新するときは、リクエストデータではなくURLの一部としてブックIDを含めるのが一般的です。
ブックインスタンスの作成と更新の両方をサポートしたい場合、リクエストに含まれないページをどのように処理したいかを考える必要があります。 は はブックインスタンスに現在関連付けられています。
これらのページを黙って無視してそのままにしておくこともできますし、検証エラーを発生させることもできますし、削除することもできます。
リクエストに含まれていないすべてのページを削除したいと仮定しましょう。
def create(self, validated_data):
# As before.
...
def update(self, instance, validated_data):
# Update the book instance
instance.title = validated_data['title']
instance.save()
# Delete any pages not included in the request
page_ids = [item['page_id'] for item in validated_data['pages']]
for page in instance.books:
if page.id not in page_ids:
page.delete()
# Create or update page instances that are in the request
for item in validated_data['pages']:
page = Page(id=item['page_id'], text=item['text'], book=instance)
page.save()
return instance
また、以下のようなことも考えられます。
だけ
はブックの更新をサポートし、作成はサポートしない、ということもあり得ますが、その場合は
だけ
を含めるようにします。
update()
メソッドを含んでいます。
また、一括作成/削除を使用するなど、クエリの数を減らすさまざまな方法がありますが、上記の方法はかなり簡単な方法で仕事をこなすでしょう。
お分かりのように、ネストされたデータを処理する際に必要となる動作の種類には微妙なものがあります。したがって、さまざまなケースでどのような動作を期待しているのか、正確によく考えてみてください。
また、注意点として、私は
Serializer
ではなく、上記の例では
ModelSerializer
. この場合、シリアライザークラスにすべてのフィールドを明示的に含める方が簡単です。
ModelSerializer
がデフォルトで生成するフィールドの自動セットに頼るのではなく、シリアライザークラスにすべてのフィールドを明示的に含めるだけです。
関連
-
[解決済み】ネストされたディレクトリを安全に作成するには?
-
[解決済み] Django restフレームワーク、同じModelViewSetで異なるシリアライザーを使用する。
-
[解決済み] Django-Rest-Framework のシリアライザーで Request.User を取得する方法とは?
-
[解決済み] Django REST フレームワーク: 非モデルシリアライザー
-
[解決済み] SQLAlchemy: セッションの作成と再利用
-
[解決済み] 辞書のキーと値を交換するにはどうすればよいですか?
-
[解決済み] DataFrameに日付間の日数カラムを追加する pandas
-
[解決済み] Pythonで、ウェブサイトが404か200かを確認するためにurllibをどのように使用しますか?
-
[解決済み] あるメソッドが複数の引数のうち1つの引数で呼び出されたことを保証する
-
[解決済み] 認証プラグイン 'caching_sha2_password' はサポートされていません。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 2つの線分が交差しているかどうかを確認するにはどうすればよいですか?
-
[解決済み] django.db.migrations.exceptions.InconsistentMigrationHistory
-
[解決済み] 辞書のキーと値を交換するにはどうすればよいですか?
-
[解決済み] タプルのリストを複数のリストに変換するには?
-
[解決済み] 文字列から先頭と末尾のスペースを削除するには?
-
[解決済み] PyMongoで.sortを使用する
-
[解決済み] subprocess.run()の出力を抑制またはキャプチャするには?
-
[解決済み] virtualenv の `--no-site-packages` オプションを元に戻す。
-
[解決済み] Pythonの検索パスを他のソースに展開する
-
[解決済み] 認証プラグイン 'caching_sha2_password' はサポートされていません。