1
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に定義したaliasの名前をレスポンスに使用する

Posted at

まえがき

先日Django-Ninjaでバリデーションエラーをハンドリングする記事を書きました。
その記事の一番最後で、

これ書いている途中で色々試してたら、Python組み込みの型の名前を レスポンスしなくちゃいけないときとかどうしよう って悩みが生まれてしまいました。
listっていうキーを含んだJSONをレスポンスしたいけど、Schemaでlistっていうフィールド名は使っちゃまずいし。
aliasをFieldに設定してみたけど、思ってた挙動とは違ったし。
どうしよう。わかんない。 誰か教えてほしい。

ていう疑問を書いてたんですけど、Django-NinjaのGitHubを読んでたら解決方法が載っていたので、早速試す。

解決策

by_alias=Trueを指定してあげるといいみたいです。
Django-Ninjaの内側(?)で動いているPydanticは、デフォルトではby_aliasはFalseなんだそう(当然か)。

実装

実装方法は2パターン見つけました。
1つは全体に作用する方法で、もう一つはViews.pyで定義する関数別に設定する方法。
それと、もう一つRouterクラス別に一括で設定する方法もあるみたいです。
それについては参考にしたIssueを見てみてください……。

レスポンスSchema

class TestOut(Schema):
    id: int = Field(
        description="ID",
    )
    str_: str | None = Field( # フィールド名は`str_`
        alias="str", # aliasは`str`
        description="your message.",
    )

1つめ

全体に作用するものです。
urls.pyでURLにAPIを渡す際に、API全体の(APIに含まれる全Routerの?)by_aliasをTrueにする。

api = NinjaAPI(renderer=ORJSONRenderer())

def set_all_by_alias(api):
    for _pth, router in api._routers:
          for view in router.path_operations.values():
               for op in view.operations:
                     op.by_alias = True

set_all_by_alias(api)

2つめ

個別に作用するものです。
Views.pyで@router.get()を使う際に、by_aliasをTrueにする。

GitHubでは@router.get()でサンプルコードが書かれていたんですけど、手元で試したらapi.get("", by_alias=True)でも大丈夫でした。
Django-Ninjaを見てみるとdefault_routerというものがNinjaAPIの内側にあるようなので、それが勝手に使用されているのかな。
(適当言ってます。api.get()api.default_router.get()は同じなのかな。)

@api.get("", by_alias=True)
def test(request, parameters: Query[TestIn]):
    return {
        "id": parameters.id,
        "str": parameters.value, # レスポンスのdictではキーにaliasの方を使用してる!
    }

結果

こうなりました。
ちゃんとaliasが効いてレスポンスのキーがstrになってる。

by_alias=Falseの状態

フィールド名に使用しているstr_(アンダースコアが付いてます)がそのまま返っていますね。
これが嫌でなんとかaliasをレスポンスに使えないかなと悩んでました。

{"id":1,"str_":"!!TESTING!!"}

by_alias=Trueの状態

ちゃんとaliasで定義したstrがレスポンスに使われてます。
やったあ。

{"id":1,"str":"!!TESTING!!"}

あとがき

意外と単純でした。
少し躓いたのは、Views.pyでreturnするdictのキーをaliasで定義した名前にしなくちゃいけないところです。
これをしないでフィールド名のほうをキーに使用すると、レスポンスSchemaでバリデーションエラーが起きちゃいました。

GitHubというか、モジュール自体の実装やIssues, Discussionsを見ることって大切だなって思いました。
私なんかが悩んでることって、当然他の誰かも悩んでいますよね。そりゃ。
矮小な悩みすぎて私以外悩んでいない場合もありそうですけど……。

テストコードを書いた経験が少なくて、pytestのmockとかfixtureとか、あとtoxあたり(toxってなに)が全然わからない。
それが超直近の悩みです。仕事上の。

そんなかんじです。悩んでばかりだ。

じゃあね。

参考

1
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
1
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?