ホームページ >バックエンド開発 >Python チュートリアル >FastAPI POST リクエストで JSON とファイルのアップロードの両方を受け入れるにはどうすればよいですか?
具体的には、以下の例を機能させたいと考えています:
from typing import List from pydantic import BaseModel from fastapi import FastAPI, UploadFile, File app = FastAPI() class DataConfiguration(BaseModel): textColumnNames: List[str] idColumn: str @app.post("/data") async def data(dataConfiguration: DataConfiguration, csvFile: UploadFile = File(...)): pass # read requested id and text columns from csvFile
これが POST リクエストの適切な方法ではない場合は、アップロードされた CSV ファイルから必要な列を選択する方法を教えてください。 FastAPI.
FastAPI ドキュメントによると:
パス操作で複数の Form パラメータを宣言できますが、JSON として受け取ることが期待される Body フィールドも宣言することはできません。リクエストには、application/json ではなく application/x-www-form-urlencoded を使用してエンコードされた本文が含まれるため (フォームにファイルが含まれている場合、次のようにエンコードされます)
これは FastAPI の制限ではなく、HTTP プロトコルの一部です。
最初に python-multipart をインストールする必要があることに注意してください。アップロードされたファイルは「フォーム データ」として送信されるため、まだ行っていません。例:
pip install python-multipart
以下の例では、エンドポイントは通常の def で定義されていますが、(ニーズに応じて) async def を使用することもできることにも注意してください。 FastAPI の def と async def の詳細については、この回答をご覧ください。
両方のファイルと辞書/JSON データのリストをアップロードする方法をお探しの場合は、お問い合わせください。この回答、および実際の例については、この回答とこの回答 (主に次のメソッドの一部に基づいています) をご覧ください。
ここで説明されているように、File と Form を使用してファイルとフォーム フィールドを同時に定義できます。以下は実際の例です。多数のパラメーターがあり、それらをエンドポイントとは別に定義したい場合は、代わりに依存関係クラスまたは Pydantic モデルを使用して、デカールするフォーム フィールドを宣言する方法に関するこの回答を参照してください。
app.py
from fastapi import Form, File, UploadFile, Request, FastAPI from typing import List from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates app = FastAPI() templates = Jinja2Templates(directory="templates") @app.post("/submit") def submit( name: str = Form(...), point: float = Form(...), is_accepted: bool = Form(...), files: List[UploadFile] = File(...), ): return { "JSON Payload": { "name": name, "point": point, "is_accepted": is_accepted, }, "Filenames": [file.filename for file in files], } @app.get("/", response_class=HTMLResponse) def main(request: Request): return templates.TemplateResponse("index.html", {"request": request})
以下のテンプレートにアクセスして、上記の例をテストできます。 http://127.0.0.1:8000。テンプレートに Jinja コードが含まれていない場合は、単純な HTMLResponse を返すこともできます。
templates/index.html
<!DOCTYPE html> <html> <body> <form method="post" action="http://127.0.0.1:8000/submit" enctype="multipart/form-data"> name : <input type="text" name="name" value="foo"><br> point : <input type="text" name="point" value=0.134><br> is_accepted : <input type="text" name="is_accepted" value=True><br> <label for="files">Choose file(s) to upload</label> <input type="file">
この例をテストすることもできます。 /docs にあるインタラクティブな OpenAPI/Swagger UI autodoc を使用します。例: http://127.0.0.1:8000/docs、または以下に示すように Python リクエストを使用します:
test.py
from typing import List from pydantic import BaseModel from fastapi import FastAPI, UploadFile, File app = FastAPI() class DataConfiguration(BaseModel): textColumnNames: List[str] idColumn: str @app.post("/data") async def data(dataConfiguration: DataConfiguration, csvFile: UploadFile = File(...)): pass # read requested id and text columns from csvFile
Pydantic モデルと依存関係を使用して、パラメーター化された変数 Base が Base クラスに依存していることを /submit エンドポイント (以下の例) に通知することもできます。このメソッドは、ベース データをクエリ (本体ではなく) パラメータとして期待し、その後 Pydantic モデル (この場合はベース モデル) に対して検証され、変換されることに注意してください。また、重大なセキュリティ リスクが生じるため、クエリ文字列を通じて機密データを決して渡さないようにしてください。このトピックの詳細については、この回答をご覧ください。
Pydantic モデル インスタンスを返すときFastAPI エンドポイント (たとえば、以下の /submit エンドポイント) から (この場合はベース)、で説明されているように、jsonable_encoder を使用して舞台裏で自動的に JSON 文字列に変換されます。この回答の詳細。ただし、モデルをエンドポイント内で独自に JSON 文字列に変換したい場合は、Pydantic の model_dump_json() (Pydantic V2 の場合) (base.model_dump_json() など) を使用して、カスタム レスポンスを直接返すことができます。先ほどのリンクされた回答で説明したとおり。したがって、jsonable_encoder の使用を避けます。それ以外の場合、モデルを自分で辞書に変換するには、Pydantic の model_dump() (Pydantic V2 の場合)、たとえば、base.model_dump() を使用するか、単に dict(base) を使用することもできます (上記のリンクされた回答で説明されているように、エンドポイントでは、FastAPI は引き続き舞台裏で jsonable_encoder を使用します)。関連する Pydantic メソッドとドキュメントについては、この回答も参照してください。
クエリ パラメーターに Pydantic モデルを使用することとは別に、この回答で示されているように、エンドポイントでクエリ パラメーターを直接定義することもできます。 、この回答とこの回答と同様に、
基本的なクエリパラメータに加えて、次の /submit エンドポイントは multipart/form-data としてエンコードされたファイルも期待します。リクエストの本文。
app.py
pip install python-multipart
ここでも、以下のテンプレートを使用してテストできます。今回は JavaScript を使用してアクションを変更します。 form 要素の属性を使用して、フォーム データをクエリ パラメータとして URL の代わりに渡します。 form-data.
templates/index.html
from fastapi import Form, File, UploadFile, Request, FastAPI from typing import List from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates app = FastAPI() templates = Jinja2Templates(directory="templates") @app.post("/submit") def submit( name: str = Form(...), point: float = Form(...), is_accepted: bool = Form(...), files: List[UploadFile] = File(...), ): return { "JSON Payload": { "name": name, "point": point, "is_accepted": is_accepted, }, "Filenames": [file.filename for file in files], } @app.get("/", response_class=HTMLResponse) def main(request: Request): return templates.TemplateResponse("index.html", {"request": request})
以上がFastAPI POST リクエストで JSON とファイルのアップロードの両方を受け入れるにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。