MENU

Django Ninjaチュートリアル⑧(ファイルアップロード)

Django-Ninjaチュートリアル⑧(ファイルアップロード)

前回までの記事はこちらです。

前回までの記事が読まれている前提で書いていきますので、まだ読んでいない方はこちらから読み進めて追いついてください。

それでは始めていきましょう。

目次

ファイルのアップロード

今回は、Django Ninjaにおけるファイルアップロードの手法を見ていきます。

様々なWebアプリケーションにおいても何かしらのイメージファイル等はアップロードする機会はあると思いますので、これも重要なパートかと思います。

それでは見ていきましょう。

ファイルアップロードの処理

Django Ninjaにおけるファイルアップロードの処理は、基本的に他のパラメータと設定は同じです。

まずは例を見てみます。
新しくapp/backend/example/api_v3.pyを作成します。

from ninja import NinjaAPI, File
from ninja.files import UploadedFile

app_v3 = NinjaAPI(
  title = "Django-Ninja Sample App3",
  version = "1.0.2"
)

@app_v3.post("/upload")
def upload_file(request, file: UploadedFile = File(...)):
  data = file.read()
  return {"name": file.name, "len": len(data)}

ここで読み込んでいるUploadedFileはDjangoのUploadFileのエイリアス(所謂、Djangoの提供している機能をDjango Ninja側で別の名前で参照するシンボル及び機能のこと)です。

そのため、アップロードされたファイルへのアクセスは、DjangoのUploadFileと同じ手法で行うことが可能です(例えば、read()multiple_chunks(chunk_size=None)chunks(chunk_size=None)namesizecontent_typeなど)。

複数のファイルを同時にアップロードする

また、通常、単一のファイルを毎回アップロードすることは効率が悪いため、アップロード先が同じ場合、一度に複数のファイルのアップロードをすることはよくあります。

Django Ninjaでは、下記のようにすることで、複数のファイルのアップロードを行うことが可能です。

from ninja import NinjaAPI, File
from ninja.files import UploadedFile
from typing import List # add

app_v3 = NinjaAPI(
  title = "Django-Ninja Sample App3",
  version = "1.0.2"
)

〜略〜

# add 2
@app_v3.post("/upload-files")
def upload_files(request, files: List[UploadedFile] = File(...)):
  return [f.name for f in files]

例では、filesの引数にtypingからimportしたListを使用しています。
そしてListにはUploadedFileを宣言し、入力されたFileデータから受け取るようにしています。

また、複数のファイルをアップロードする都合、返されるJSONにはアップロードされた複数のファイルがあります。
そのため、繰り返し処理により、Listから一つ一つのファイルを取り出して返しています。

自動生成ドキュメントの確認

それでは、作成された自動ドキュメントを確認していきます。

http://127.0.0.1:8000/api_v3/docsにアクセスします。

先ほど作成したupload-filesがあれば成功です。

単一ファイルをアップロードした場合

filesからファイルをアップロードできますし、「add string item」から、2つ目以降のファイルをアップロードすることも可能です。
そして、返される結果には、ファイル名がしっかりと返されています。

このように、Django Ninjaでもファイルアップロードへの対応ができ、Djangoの記述方法に倣った開発を進めることができます。

追加のフィールドを含むファイルアップロード

Djnago Ninjaにおいて、ファイルを他の属性を追加して送信するには、本文を multipart/form-dataエンコーディングで送信する必要があります。

HTTPプロトコルでは、デフォルトでファイルを application/json 形式で送信することはできません (クライアント側(フロントエンド側など)で何らかの方法でJSONにエンコードする必要があります)。

まずは、Schemaを設定します。
今回は、User情報を定義するUserDetailsというSchemaを定義します。

from ninja import Schema
from datetime import date

class UserDetails(Schema):
  first_nam: str
  last_name: str
  birthdate: date

このSchema設定はよくあるSchema設定です。

次に、APIを定義していきます。

APIは、Formフィールドを次のようにマークするだけで実行することができます。

from ninja import NinjaAPI, File, Form # add
from ninja.files import UploadedFile
from typing import List

from example.Schema.api_v3_schema import UserDetails # add

app_v3 = NinjaAPI(
  title = "Django-Ninja Sample App3",
  version = "1.0.2"
)

〜略〜

# add 3
@app_v3.post("/user")
def create_user(request, details: UserDetails = Form(...), file: UploadedFile = File(...)):
  return [details.dict(), file.name]

fileと一緒にUserDetailsの型定義をされたdetailsが引数として設定されています。
また、このdetailsFormデータからデータを受け取るように設定しています。

このケースでは、すべてのフィールドをフォームフィールドとして送信する必要がありますので注意してください。

http://127.0.0.1:8000/api_v3/docsを確認すると、以下のようにドキュメントが自動生成されると思います。

自動生成されたドキュメント

このように、fileに加えて他の属性を追加で送信することができるようになります。
ただし、detailsFormデータからデータを受け取ることから、detailsの各項目をFormデータから受け取る必要があります。

また、以下のように書き換えると、detailsについては、JSONの文字列として、単一のフィールドとして送信することもできます。
つまり、この場合に送信されるpayloadには、filedetails(JSON形式)が含まれていることになります。

# add 3
@app_v3.post("/user")
def create_user(request, details: UserDetails, file: UploadedFile = File(...)):
  return [details.dict(), file.name]

上記の例は、= Form(...)を削除したのみです。
これにより、自動生成ドキュメントも変更になります(paylodに含まれる情報はfiledetailsのみになります)。

detailsを単一のフィールドとして送信するよう設定した場合

最後に

今回は、Django Ninjaにおけるファイルアップロードの手法を見てきました。
シンプルな例を見てきましたが、それでも簡単にファイルのアップロードができることがわかったと思います。

Webアプリケーションでは画像などのイメージファイル等のアップロードは必須になるケースがほとんどだと思います。

また、ファイルだけではなく、複数の情報を一括して送信するケースにも対応できる構成もあり、工夫次第でデータの受け取りはスッキリしたものになりそうな気がします。

今回は、ここまでです。
次回もチュートリアルを地道に続けます。よろしければお付き合いください。

よろしくお願いします。

Django-Ninjaチュートリアル⑧(ファイルアップロード)

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

はじめまして、ふじです。
Python、Django、FastAPI、React.js、Next.jsを学習している、ずっと文系のプログラミング独学者です。

目次