2021年9月14日火曜日

marshmallow の post_dump の挙動を確認してみた

marshmallow の post_dump の挙動を確認してみた

概要

marshmallow の load と dump 時に自動的にコールされる pre_ post_ 系のデコレータの処理の挙動を確認してみました

環境

  • macOS 11.5.2
  • Python 3.8.3
  • marshmallow 3.13.0

インストール

  • pipenv install marshmallow

サンプルコード

from marshmallow import (
    Schema, pre_load, post_load, post_dump, fields
)

class User():
    def __init__(self, email, age):
        self.email = email
        self.age = age

class UserSchema(Schema):

    email = fields.Str(required=True)
    age = fields.Integer(required=True)

    @pre_load(pass_many=True)
    def remove_envelope(self, data, many, **kwargs):
        # ルート要素 (result or results) を data から取得する
        # 取得した data[namespace] は post_load で item に格納される
        namespace = 'results' if many else 'result'
        return data[namespace]

    @post_load
    def lowerstrip_email(self, item, many, **kwargs):
        # 各 item に格納されている値を加工する場合はこちらを使います
        # many=True の場合は自動的に複数回コールされます
        item['email'] = item['email'].lower().strip()
        return item

    @post_dump(pass_many=True)
    def add_envelope(self, data, many, **kwargs):
        # many=True の場合は results をルートキーとする dict を返却します
        namespace = 'results' if many else 'result'
        return {namespace: data}

schema = UserSchema()
result = schema.load({"result": {"age": "1", "email": "test1@mail"}})
print(result)
result = schema.load({"results": [{"age": "2", "email": "test2@mail"}, {"age": "3", "email": "test3@mail"}]}, many=True)
print(result)

user4 = User("test4@mail", 4)
result = schema.dump(user4)
print(result)
user5 = User("test5@mail", 5)
user6 = User("test6@mail", 6)
result = schema.dump([user5, user6], many=True)
print(result)

解説、挙動の確認

schema.load がコールされた場合には pre_load と post_load が自動的にコールされます
schema.dump がコールされた場合は pre_dump と post_dump が自動的にコールされます

load は dict -> dict の変換します
指定したキーの値配下の情報を取得しています

dump は class -> dict の変換をします
こちらのほうがよく使う手法になるかなと思います

pre_ ではデータの加工は行わず必要なデータの取得などを行います
post_ 側でデータを加工するので post_ 側に渡すデータを必ず return する必要があります
many=True の場合は post_ が自動的に複数回コールされて各要素分だけ処理されます

最後に

  • pre_ はデータの加工をする対象の抽出
  • post_ でデータの加工をする

というのが主な使い方になるかなと思います

参考サイト

0 件のコメント:

コメントを投稿