#python #fastapi #starlette
Вопрос:
Я изучал этот примерный проект. Очень лаконично и по существу, а также приятный сюрприз: диалоговое окно сохранения файла (стандартное диалоговое окно файла рабочего стола, открытое из Chrome).
Ответственный кодекс:
src/html.py
:
@app.post('/download')
def form_post(request: Request, num: int = Form(...), multiply_by_2: bool = Form(False), action: str = Form(...)):
if action == 'convert':
result = spell_number(num, multiply_by_2)
return templates.TemplateResponse('download.html', context={'request': request, 'result': result, 'num': num})
elif action == 'download':
# Requires aiofiles
result = spell_number(num, multiply_by_2)
filepath = save_to_text(result, num)
return FileResponse(filepath, media_type='application/octet-stream', filename='{}.txt'.format(num))
templates/download.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sample Form</title>
</head>
<body>
<form method="post">
<input type="number" name="num" value="{{ num }}"/>
<input type="checkbox" id="multiply_by_2" name="multiply_by_2" value="True">
<label for="multiply_by_2">Multiply by 2amp;nbsp;</label>
<input type="submit" name="action" value="convert">
<input type="submit" name="action" value="download">
</form>
<p>Result: {{ result }}</p>
</body>
</html>
Я не вижу никаких подсказок в диалоговом окне файла FileResponse
, а тем более в появившемся диалоговом окне Сохранения файла. Кстати, мне тоже нужен диалог открытия файла. Я пытался исследовать это, но безуспешно.
Как это работает?
UPD, чтобы было понятнее.
Я играю с чем-то вроде этого:
from tkinter import Tk
from tkinter.filedialog import askopenfilename
...
@app.post("/open")
def form_post(
request: Request,
action: str = Form("open"),
):
if action == "open":
root = Tk()
root.withdraw()
# ensure the file dialog pops to the top window
root.wm_attributes('-topmost', 1)
fname = askopenfilename(parent=root)
print(f"Chosen file: {fname}")
return templates.TemplateResponse("open.html", context={"request": request})
elif action == "save":
# Requires aiofiles
return FileResponse(
"templates/legacy/download.html",
media_type="text/html",
filename="download.html",
)
На данный момент кнопка save
использует диалоговое окно Сохранения файла системы, в то время как кнопка open
использует диалоговое окно открытия tkinter. Это подойдет, потому что все это просто приложение с веб — интерфейсом. Тем не менее, это выглядит и кажется немного нелепым.
Есть ли способ заставить браузер обслуживать открытый файл Dialg?
Ответ №1:
Диалоговое окно файла-это то, что Chrome показывает для такого ответа ( application/octet-stream
). Платформа на стороне сервера не отвечает за создание диалогового окна сохранения файла; она просто предоставляет ответ, и браузер делает то, что он обычно делает для такого рода ответа.
Вы можете использовать Content-Disposition
заголовок в своем ответе, чтобы указать браузеру, что он должен отображать диалоговое окно загрузки вместо содержимого напрямую (если он изначально поддерживает тип mime). Content-Disposition
Заголовок также позволяет указать имя файла по умолчанию для диалогового окна сохранения (но только имя файла, а не путь).
За диалог открытия файла будет отвечать HTML, используя <input type="file" name="name_matching_fastapi_parameter">
. Затем вы можете сообщить FastAPI, что ожидаете, что параметр представляет собой файл с UploadFile
типом.
Из ссылки FastAPI:
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File(...)):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
return {"filename": file.filename}
Комментарии:
1. Большое вам спасибо, @MatsLindh! Поэтому
application/octet-stream
вызывает Диалоговое окно Сохранения файла . Мне очень жаль, но я не могу найти тип MIME, который вызвал бы диалоговое окно открытия файла . Существует ли такой тип?2. Я вижу, что тип MIME отвечает только за тип файла (как и должно быть). Я все еще не вижу, как заказать диалоговое окно открытия файла .
3. Это было бы то, что вы делаете в своем HTML; когда пользователь нажимает кнопку «Обзор» на
input type="file"
элементе, откроется диалоговое окно выбора файла. Вы не можете сделать это из своего кода FastAPI; это должно быть сделано в самом HTML.4. Я вставил
<input type="file" name="action" value="name">
его в шаблон, и у меня все в порядке с открытым диалогом . Тем не менее, я не могу собрать имя файла. Удивительно, но информации о том, как это сделать, особенно относящейся к FastAPI, очень мало.5. Если вы посмотрите на страницу для загрузки файла в качестве ссылки в ответе , вы обнаружите, что она содержит
filename
атрибут: имя файла: str с исходным именем файла, который был загружен (например myimage.jpg).