0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Django-NinjaでSchema内のフィールド値を動的に決定する!

Posted at

まえがき

お久しぶりです。
今も前回の記事同様に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でなんとかしたいなって思ってたので、スッキリしていい感じです。

最近、仕事自体は楽しいんですけど、上司とのコミュニケーションがしんどくて、そっちの悩みが日に日に大きくなっているので、久しぶりにこうしてたくさん文字を書いて、ちょっとリラックスできました。

今度、精神科を受診して色々相談するつもりです。
みなさんも心の健康には気をつけてくださいね。

そんな感じ。

じゃあね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?