flet
flet copied to clipboard
Documentation issue (filepicker section) or a bug.
Hi there, Can't seem to run following example to download file (even after changing the flet_fastapi to flet.fastapi ) :
Source: INFO section in the URL below, pasting it for convenience. :- https://flet.dev/docs/controls/filepicker
INFO To save a file from the web, you don't need to use the FilePicker object.
You can instead provides an API endpoint /download/:filename that returns the file content, and then use page.launch_url to open the url, which will trigger the browser's save file dialog.
Take FastAPI as an example, you can use the following code to implement the endpoint:
from fastapi import FastAPI, Response from fastapi.responses import FileResponse
app = flet_fastapi.app(main)
@app.get("/download/{filename}") def download(filename: str): path = prepare_file(filename) return FileResponse(path)
and then use page.launch_url("/download/myfile.txt") to open the url, for instance, when a button is clicked.
ft.ElevatedButton("Download myfile", on_click=lambda _: page.launch_url("/download/myfile.txt")) ########################
Is there a possibility to provide full working download example. I have spent considerable hours to resolve this with no headway yet :-(
Thanks for your help.
@mxav1111
import requests
import flet as ft
import asyncio
demo_url="https://miller.readthedocs.io/en/latest/data/english-words.txt"
demo_path="/home"
demo_file_name="english-words.txt"
txt_selected_dir=ft.Text(f"{demo_path}/{demo_file_name}")
def on_dialog_result(e: ft.FilePickerResultEvent):
txt_selected_dir.value=f"{e.path}/{txtfld_file_name.value}"
txt_selected_dir.update()
file_picker = ft.FilePicker(on_result=on_dialog_result)
txtfld_file_name=ft.TextField(demo_file_name)
txt_status=ft.Text("Status",size=21,color="red")
async def save_file(e):
response=requests.get(url=demo_url)
if response.ok:
txt_status.value="Response ok..."
txt_status.update()
await asyncio.sleep(2)
if response.status_code==200:
txt_status.value="Status 200."
txt_status.update()
await asyncio.sleep(2)
with open(txt_selected_dir.value if txt_selected_dir.value is not None else demo_file_name,"wb") as file:
txt_status.value="File download started.."
txt_status.update()
await asyncio.sleep(2)
for chunk in response.iter_content(chunk_size=10*1024):
file.write(chunk)
await asyncio.sleep(2)
txt_status.value="file download completed..."
txt_status.update()
def select_dir(e):
file_picker.get_directory_path(initial_directory=demo_path)
async def main(page:ft.Page):
page.overlay.append(file_picker)
page.update()
page.add(
ft.Row(
controls=[
ft.Text("File Name"),
txtfld_file_name
]
),
ft.ElevatedButton(
text="SELECT PATH",
on_click=select_dir
),
ft.ElevatedButton(
text="SAVE FILE",
on_click=save_file
),
txt_selected_dir,
txt_status
)
pass
ft.app(target=main)
Hello @burhansvural Thank so much. Example in the original doc allows download from the url (server) of the application itself i guess (if it works). If I understand correctly, yours is sourcing file from external URL. Currently I need to allow download of a generated file from flet url itself. Also this is browser based.
This one apparently has some issue in browser when running with parameter :- ft.app(target=main, view=ft.WEB_BROWSER) too but didn't check that part carefully yet.
BTW I also tried assets_dir with no luck. Following code from stackoverflow by some wise guys works with uvicorn but I wasn't able to convert this to run under flet server.
saveas.py
from fastapi import FastAPI from fastapi.responses import FileResponse from contextlib import asynccontextmanager import flet as ft import flet import flet.fastapi @asynccontextmanager async def lifespan(app: FastAPI): await flet.fastapi.app_manager.start() yield await flet.fastapi.app_manager.shutdown() app = FastAPI(lifespan=lifespan)
async def download(): headers = {'Content-Disposition': 'attachment; filename="test.txt"'} ## relative to the path given in @app.get .. same as without dot. so it seems it must be just the filename.. i.e. without path return FileResponse("test.txt", headers=headers)
async def main(page: flet.Page): async def download_file(e): await page.launch_url_async(url='/download', web_window_name='_self') ## This with regular combination picks from /download (maps to current start dir it seems) await page.add_async(flet.FilledButton(text="Download File", on_click=download_file)) await page.update_async() app.mount('/', flet.fastapi.app(main))
run as uvicorn saveas:app and then it will show the url.. go to that url and click download
Hopefully we will soon have a solution to download from application url itself (eg-> http://127.0.0.1:50064/pdf/generated.pdf)
Nevertheless, thanks for wonderful effort and sharing your precious time selflessly.
https://flet.dev/docs/guides/python/navigation-and-routing/#url-strategy-for-web
You can do this very easily by using the information here and adding some programming skills.
https://flet.dev/docs/guides/python/navigation-and-routing/#url-strategy-for-web
You can do this very easily by using the information here and adding some programming skills.
Thanks again. My programming skills aren't that great. Will need an example especially because what looks like is this would need another web server. For now, what i am trying is standalone app just by using built-in flet server (and hopefully without any customization unless it is confirmed that there's isn't any other way). Thanks for your help.
https://flet.dev/docs/guides/python/navigation-and-routing/#url-strategy-for-web
You can do this very easily by using the information here and adding some programming skills.
Thank a lot @burhansvural . This worked ... upload folder is named and created on the fly via user input in session_area_path variable, that's where user selected file is saved.
@app.put("/upload") async def flet_uploads(request: Request): await FletUpload(session_area_path+"/").handle(request)
if file_picker.result is not None and file_picker.result.files is not None: upload_url="" for f in file_picker.result.files: uf.append( FilePickerUploadFile( f.name, upload_url=page.get_upload_url(f.name, 600), ) ) print(f'upload_url from call to get_upload_url() using {f.name}={upload_url}') pdffile=f.name ## this would work since we are picking up only one file.
file_picker.upload(uf)
Thanks for all your help.
Resolved (based on input from @burhansvural and many posts from stackoverflow)