diff --git a/nbs/tutorials/quickstart_for_web_devs.ipynb b/nbs/tutorials/quickstart_for_web_devs.ipynb index 9bddc6a5..b43db0c5 100644 --- a/nbs/tutorials/quickstart_for_web_devs.ipynb +++ b/nbs/tutorials/quickstart_for_web_devs.ipynb @@ -1519,7 +1519,14 @@ " Button(\"Upload\", type=\"submit\", cls='secondary'),\n", " ),\n", " Div(id=\"result-one\")\n", - " )\n", + " ),\n", + " Article(\n", + " Form(hx_post=\"/upload-multi\", hx_target=\"#result-multi\")(\n", + " Input(type=\"file\", name=\"files\", multiple=True), # <3>\n", + " Button(\"Upload\", type=\"submit\", cls='secondary'),\n", + " ),\n", + " Div(id=\"result-multi\")\n", + " ) \n", " )\n", " )\n", "\n", @@ -1534,13 +1541,20 @@ " ) \n", "\n", "@rt('/upload')\n", - "async def post(file: UploadFile): # <3>\n", - " card = FileMetaDataCard(file) # <4>\n", - " filebuffer = await file.read() # <5>\n", - " (upload_dir / file.filename).write_bytes(filebuffer) # <6>\n", + "async def post(file: UploadFile): # <4>\n", + " card = FileMetaDataCard(file) # <5>\n", + " filebuffer = await file.read() # <6>\n", + " (upload_dir / file.filename).write_bytes(filebuffer) # <7>\n", " return card\n", "\n", - "serve()" + "@rt('/upload-multi')\n", + "async def post(files: list[UploadFile]): # <8>\n", + " cards = [] # <9>\n", + " for file in files:\n", + " cards.append(FileMetaDataCard(file)) # <10>\n", + " filebuffer = await file.read()\n", + " (upload_dir / file.filename).write_bytes(filebuffer)\n", + " return cards" ] }, { @@ -1549,16 +1563,15 @@ "source": [ "1. Every form rendered with the `Form` FT component defaults to `enctype=\"multipart/form-data\"`\n", "2. Don't forget to set the `Input` FT Component's type to `file`\n", - "3. The upload view should receive a [Starlette UploadFile](https://www.starlette.io/requests/#request-files) type. You can add other form variables\n", - "4. We can access the metadata of the card (filename, size, content_type, headers), a quick and safe process\n", - "5. In order to access the contents contained within a file we use the `await` method to read() it. As files may be quite large or contain bad data, this is a seperate step from accessing metadata\n", - "6. This step shows how to use Python's built-in `pathlib.Path` library to write the file to disk." + "3. In order for the `Input` FT Component to accept multiple files, we set `multiple=True`\n", + "4. The upload view should receive a [Starlette UploadFile](https://www.starlette.io/requests/#request-files) type. You can add other form variables\n", + "5. We can access the metadata of the card (filename, size, content_type, headers), a quick and safe process\n", + "6. In order to access the contents contained within a file we use the `await` method to read() it. As files may be quite large or contain bad data, this is a seperate step from accessing metadata\n", + "7. This step shows how to use Python's built-in `pathlib.Path` library to write the file to disk.\n", + "8. The multiple upload view receives a variable with the type `list[UploadFile]. This tells FastHTML to treat in the incoming request as having a list of files to process. In this example the variable is named `files`.\n", + "9. We want to provide a response of one or more `FileMetaDataCard` FT Components, so we set up a list named `cards` to contain them\n", + "10. Get the metadata for the incoming file and use it to construct the `FileMetaDataCard` FT Components. Then we append that to the `cards` list that will be the response of this view." ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] } ], "metadata": {