python 如何使用Jinja2模板和FastAPI上传csv文件,并在修改后返回?

omvjsjqw  于 2022-11-27  发布在  Python
关注(0)|答案(2)|浏览(187)

我使用FastAPI上传一个csv文件,对它进行一些修改,然后将它返回到HTML页面。我使用Jinja2作为模板引擎,在前端使用HTML。
如何使用Jinja2模板上传csv文件,修改后返回给客户端?
Python代码

from fastapi.templating import Jinja2Templates
from fastapi import FastAPI, File, UploadFile, Request
from io import BytesIO
import pandas as pd
import uvicorn

app = FastAPI()
templates = Jinja2Templates(directory="templates")

@app.get("/")
def form_post(request: Request):
result = "upload file"
return templates.TemplateResponse('home.html', context={'request': request, 'result': result})

@app.post("/")
def upload(request: Request, file: UploadFile = File(...)):

    contents1 = file.file.read()
    buffer1 = BytesIO(contents1)
    test1 = pd.read_csv(buffer1)
    buffer1.close()
    file.file.close()
    test1 = dict(test1.values)
    
    return templates.TemplateResponse('home.html', context={'request': request, 'result': test1})

if __name__ == "__main__":
    uvicorn.run(app)

HTML代码

\<!DOCTYPE html\>
\<html lang="en"\>
\<head\>
\<meta charset="UTF-8"\>
\<title\>RUL_PREDICTION\</title\>
\</head\>
\<body\>
\<h1\>RUL PREDICTION\</h1\>
\<form method="post"\>
\<input type="file" name="file" id="file"/\>
\<button type="submit"\>upload\</button\>
\</form\>
\<p\>{{ result }}\</p\>
\</body\>
\</html\>
7uhlpewt

7uhlpewt1#

下面的工作示例源自答案herehere以及hereherehere,我建议您查看这些答案以了解更多详细信息和说明。

示例数据

数据.csv

Id,name,age,height,weight
1,Alice,20,62,120.6
2,Freddie,21,74,190.6
3,Bob,17,68,120.0

选项1 -在新CSV文件中返回修改的数据

应用程序.py

from fastapi import FastAPI, File, UploadFile, Request, Response, HTTPException
from fastapi.templating import Jinja2Templates
from io import BytesIO
import pandas as pd

app = FastAPI()
templates = Jinja2Templates(directory='templates')

@app.post('/upload')
def upload(file: UploadFile = File(...)):
    try:
        contents = file.file.read()
        buffer = BytesIO(contents) 
        df = pd.read_csv(buffer)
    except:
        raise HTTPException(status_code=500, detail='Something went wrong')
    finally:
        buffer.close()
        file.file.close()

    # remove a column from the DataFrame
    df.drop('age', axis=1, inplace=True)
    
    headers = {'Content-Disposition': 'attachment; filename="modified_data.csv"'}
    return Response(df.to_csv(), headers=headers, media_type='text/csv')
    

@app.get('/')
def main(request: Request):
    return templates.TemplateResponse('index.html', {'request': request})

模板/索引.html

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
   </head>
   <body>
      <form method="post" action="/upload"  enctype="multipart/form-data">
         <label for="csvFile">Choose a CSV file</label>
         <input type="file" id="csvFile" name="file" onchange="enableSubmitBtn();"><br><br>
         <input type="submit" id="submitBtn" value="submit" disabled>
      </form>
      <script>
         function enableSubmitBtn() {
            document.getElementById('submitBtn').removeAttribute("disabled");
         }
      </script>
   </body>
</html>

选项2 -在新的Jinja 2模板中返回修改的数据

如果您希望返回一个包含修改后数据的新Jinja 2模板,而不是上面演示的csv文件,您可以使用下面的。
方法1
使用pandas.DataFrame.to_html()将DataFrame呈现为HTML表。您可以选择在to_html()函数中使用classes参数来传递class名称或名称列表,这些名称将在前端的样式表中用于设置表的样式。此外,您可以通过在to_html()中指定border=0来删除border

应用程序.py

# ... (rest of code is same as in Option 1)

@app.post('/upload')
def upload(request: Request, file: UploadFile = File(...)):
    # ... (rest of code is same as in Option 1)

    context = {'request': request, 'table': df.to_html()}
    return templates.TemplateResponse('results.html', context)

模板/结果.html

<!DOCTYPE html>
<html>
    <body>{{ table | safe }}</body>
</html>

方法二
使用pandas.DataFrame.to_dict()将DataFrame转换为字典并返回它。

应用程序.py

# ... (rest of code is same as in Option 1)

@app.post('/upload')
def upload(request: Request, file: UploadFile = File(...)):
    # ... (rest of code is same as in Option 1)

    context = {'request': request, 'data': df.to_dict(orient='records'), 'columns': df.columns.values}
    return templates.TemplateResponse('results.html', context)

模板/结果.html

<!DOCTYPE html>
<html>
    <body>
        <table style="width:50%">
            <tr>
                {% for c in columns %}<td>{{ c }}</td>{% endfor %}
            </tr>
            {% for d in data %}
                <tr>
                    {% for v in d.values() %}
                        <td>{{ v }}</td>
                    {% endfor %}
                    <br>
                </tr>
            {% endfor %}
        </table>
    </body>
</html>
fv2wmkja

fv2wmkja2#

以下方法可能有效:

@app.post("/")
def upload(file: UploadFile):

    with open("temp.csv", "wb") as f:
        for row in file.file:
            f.write(row)
    
    with open("temp.csv", "r", encoding="utf-8") as csv:
        # modifications
    

    return FileResponse(path="temp.csv", filename="new.csv", media_type="application/octet-stream")

相关问题