まえがき
お久しぶりです。
今も前回の記事同様にDjango-Ninjaを使ってAPIを作っています。
今回は、SchemaのフィールドをSchema内で定義した関数を用いて値解決する方法についてです。
レビューへ出す前に、しっかりとこのようなFW思想に沿ったやり方でコーディングしたかったのですが、このあたりは自分の知識が薄くて、仕事がいそがしかったこともあって、全然できていませんでした。
Django-NinjaのDiscussionsを見ていたら、いい感じに解決する方法があったため、そちらを試したよっていう記事です。
やりたかったこと
- レスポンスを生成するSchema内で返却値を動的に解決する
例えば、データベースからORMを使って{"id":1, "value": "value"}
を取得したとします。
ここでは、valueの値はvalueになってます。
これは、DB操作するときにSQLやORMで解決するには、あまりにも実装が面倒そうだったから、一時的にvalueという文字列を返している……ということにしてください。
そして、valueの値はidの数字に「だ🐘パオーン!」とつけたものにするとします。
上記をまとめると、以下のような感じ。
- Schemaに渡される前(DBから取ってきたもの)
{
"id": 1,
"value": "value"
}
- Schemaに渡された後(実際にAPIが返すもの)
{
"id": 1,
"value": "1だ🐘パオーン!"
}
伝わるでしょうか…。
やり方
公式のDiscussionsを見ていたら、それっぽいことを聞いているスレッドがあったので、それを参考にしてみました。
自分で試してみた方法は2通りで、どっちが優れているとか、どういう状況で使うとか、そのあたりはわかっていないんですけど、とりあえずできたという感じです。
resolve_xxx()を使う
staticmethodでデコレートされたresolve_xxx()
を使う方法です。
これは、Django-Ninjaの公式のドキュメントにも似たようなことが書いてあったのかな。
レスポンスSchemaのコード
class TestOut(Schema):
id: int = Field(
description="ID",
)
value: str= Field(
description="id + 'だ🐘パオーン!'",
)
@staticmethod
def resolve_value(input):
return str(input["id"]) + "だ🐘パオーン!"
こんな感じ。公式だと、input["id"]
の部分が、input.id
みたいなフィールドで書かれていて、これがちょっとよくわかんないんですけど、とりあえずこれでいけました。
(viewsでreturnしているのがインスタンスじゃなくて辞書型だからなのかな……。)
pydanticのcomputed_fieldを使う
わたしが参考にしたDiscussionだと、これが勧められていました。
どうやら、NinjaがVer1.0になった際、resolve_xxx(self, ...)
)が使えなくなって、pydanticの組み込み機能に置き換える必要があったみたいです。
上で書いた方法と何が違ったのか、selfが使えて何が嬉しかったのかがよくわかんないんですけど、とりあえず、そういう感じでした。。。
レスポンスSchemaのコード
class TestOut(Schema):
id: int = Field(
description="ID",
)
@computed_field
@property
def value(self) -> str:
return str(self.id) + "だ🐘パオーン!"
どっちがいいんだろう?
できました。
どっちを使えばいいのかがよくわからないですけど。
ただ、computed_fieldを使った方法だと、例えばSchemaに既にvalueフィールドがある際に、それは書き換えられないよ!ってエラーが出ちゃうんですよね。
そうすると、openpaiを生成するときにSchema定義がちゃんとされていないみたいで、それはあまり嬉しくないです。。。
適当なフィールドを用意して、aliasでフィールド名をつけてあげたらいいのかもしれないんですけど、それはなんかちょっと、面倒というか回りくどいことをしている感じがします。。。
あとがき
とりあえずこれで、Schemaの外でおりゃーと無理矢理に実装していた値解決のコードが、Schema内で定義できるようになりました。
へたに色々ファイルを増やしたり、どこに書いて値を書き換えたらいいんだろうと悩むくらいなら、Schemaでなんとかしたいなって思ってたので、スッキリしていい感じです。
最近、仕事自体は楽しいんですけど、上司とのコミュニケーションがしんどくて、そっちの悩みが日に日に大きくなっているので、久しぶりにこうしてたくさん文字を書いて、ちょっとリラックスできました。
今度、精神科を受診して色々相談するつもりです。
みなさんも心の健康には気をつけてくださいね。
そんな感じ。
じゃあね。