如何在Python中处理SQL返回的Decimal类型数据并通过Streamlit成功下载为CSV文件
如何在Python中处理SQL返回的Decimal类型数据并通过Streamlit成功下载为CSV文件
看起来你遇到了两个核心问题:一是没法把数据库返回的字符串格式结果转换成带Decimal的有效Python对象,二是Streamlit的下载按钮没正确读取到文件内容。我来一步步帮你解决:
问题根源分析
- 字符串转Python对象失败:你的
out是字符串类型(比如"[{A: Decimal(1,2)}]"),literal_eval不认识Decimal类型,直接用eval又因为命名空间里没导入Decimal报错。 - CSV写入与下载的问题:你直接用
writer.writerows(out),但out是字符串,writerows会把字符串拆成单个字符逐行写入,导致CSV格式完全乱掉;而且写完文件后,文件指针停在末尾,Streamlit读取的时候就只能拿到空内容。
解决方案步骤
第一步:把字符串结果转换成真正的Python对象
首先要把数据库返回的字符串解析成带Decimal的字典列表,这里可以用eval并手动传入Decimal的命名空间:
from decimal import Decimal # 假设out是数据库返回的字符串格式结果 out = db.run_no_throw(query, include_columns=True) # 解析成Python对象,把Decimal传入eval的命名空间 try: data = eval(out, {"Decimal": Decimal}) except Exception as e: print(f"解析失败:{e}") data = []
这样就能得到真正的字典列表,每个值是Decimal类型,而不是字符串。
第二步:生成CSV内容并通过Streamlit下载
这里有两种靠谱的方式,推荐用内存流(避免本地文件的权限和指针问题):
方法一:用Pandas处理(更简洁)
现在数据已经是正确的Python对象了,Pandas可以直接处理Decimal类型,然后把DataFrame转换成CSV字符串,传给下载按钮:
import pandas as pd import streamlit as st if data: # 转换成DataFrame,Decimal会被自动处理成合适的数值类型 df = pd.DataFrame(data) # 把DataFrame转换成CSV字符串 csv_content = df.to_csv(index=False) # 下载按钮 st.download_button( label="Download data as CSV", data=csv_content, file_name="result.csv", mime="text/csv" )
方法二:用csv模块+内存流(更灵活)
如果不想用Pandas,可以用csv模块配合io.StringIO在内存中生成CSV内容:
import csv import io import streamlit as st if data: output = io.StringIO() writer = csv.writer(output, delimiter=",") # 写入表头(从第一个字典的键获取) if data: writer.writerow(data[0].keys()) # 写入每行数据,Decimal会自动转成字符串 for row in data: writer.writerow(row.values()) # 把指针移到开头 output.seek(0) # 下载按钮 st.download_button( label="Download data as CSV", data=output.getvalue(), file_name="result.csv", mime="text/csv" )
为什么之前的代码不行?
- 你直接对字符串
out用writerows,相当于把字符串的每个字符作为一行写入,所以CSV会变成一堆零散的字符。 - 写完本地文件后,文件指针在文件末尾,Streamlit读取的时候只能读到空内容;而且服务器上的本地文件可能不是每个请求都能正确访问到,用内存流更可靠。
备注:内容来源于stack exchange,提问作者Soumya
相关产品推荐
相关产品推荐

