You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Flask项目中使用BYTEA在PostgreSQL存储上传图片的方案咨询

React+Flask应用图片存入PostgreSQL BYTEA字段的实现方案

问题背景

我正在开发一款前端采用React、服务端使用Flask/Python的应用,需要支持用户上传图片并将图片存入PostgreSQL数据库,计划使用BYTEA类型存储图片,目前已有相关实现代码如下:

现有实现代码

1. 数据库表结构(SQLAlchemy定义)

class Items(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    item_description = db.Column(db.String(640))
    item_name = db.Column(db.String(60))
    username = db.Column(db.String(120))
    item_pic = db.Column(BYTEA)
    date = db.Column(db.Date, default=datetime.datetime.utcnow)
    price = db.Column(db.Float)

2. React端图片上传表单代码

<div className="flex text-sm text-gray-600">
  <label
    htmlFor="file_upload"
    className="relative cursor-pointer bg-white rounded-md font-medium text-indigo-600 hover:text-indigo-500 focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-indigo-500"
  >
    <span>Upload a file</span>
    <input 
      id="file_upload" 
      name="file_upload" 
      type="file" 
      className="sr-only" 
      onChange={handleInputs}
    />
  </label>
  <p className="pl-1">or drag and drop</p>
</div>

注:文件类型的input出于浏览器安全限制不支持手动赋值,已删除原代码中无效的value={product.file_upload}属性

3. 原有前端请求代码(存在问题)

原有直接将文件对象放入JSON传输的写法无法正常传输二进制文件,需要修改。

// 原有错误写法,仅作展示
function onClickSave() {
  const requestData = { 
    company_website: product.company_website, 
    price: product.price, 
    about: product.about,
    file_upload: product.file_upload,
  };

  fetch('/save_product', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(requestData),
  })
    .then((response) => response.json())
    .then((data) => {
      console.log(data);
    });
}

核心疑问解答

推荐在Flask服务端完成BYTEA格式转换,原因如下:

  • JSON不支持直接传输二进制流,React端直接转码后传输体积会增加30%左右,性能更低
  • SQLAlchemy原生支持将Python二进制对象直接映射到PostgreSQL的BYTEA字段,不需要额外转码操作

具体实现步骤

第一步:修改React端上传与请求逻辑

使用FormData格式传输文件和其他字段,不需要手动处理二进制转码:

  1. 首先修改文件选择的事件处理函数:
const handleInputs = (e) => {
  if (e.target.name === 'file_upload') {
    // 直接存储原始File对象到状态中
    setProduct(prev => ({
      ...prev,
      file_upload: e.target.files[0]
    }))
    return
  }
  // 其他普通字段的原有处理逻辑
  setProduct(prev => ({
    ...prev,
    [e.target.name]: e.target.value
  }))
}
  1. 修改提交请求的逻辑:
function onClickSave() {
  const formData = new FormData()
  // 追加普通字段
  formData.append('company_website', product.company_website)
  formData.append('price', product.price)
  formData.append('about', product.about)
  // 追加上传的文件
  if (product.file_upload) {
    formData.append('file_upload', product.file_upload)
  }

  fetch('/save_product', {
    method: 'POST',
    // 不要手动设置Content-Type,浏览器会自动生成带边界标识的multipart/form-data类型
    body: formData
  })
  .then(res => res.json())
  .then(data => console.log(data))
}

第二步:修改Flask端接口逻辑

直接读取上传文件的二进制内容,赋值给对应字段即可,SQLAlchemy会自动适配BYTEA类型:

from flask import request, jsonify

@app.route('/save_product', methods=['POST'])
def save_product():
    # 读取FormData中的普通字段
    company_website = request.form.get('company_website')
    price = request.form.get('price', type=float)
    about = request.form.get('about')
    # 读取上传的文件对象
    upload_file = request.files.get('file_upload')

    # 初始化数据对象,其余字段根据你的业务逻辑补全
    new_item = Items(
        item_description=about,
        price=price,
        # 其余字段自行补充赋值
    )
    # 写入图片二进制内容
    if upload_file:
        new_item.item_pic = upload_file.read()
    
    db.session.add(new_item)
    db.session.commit()
    return jsonify({"status": "success", "item_id": new_item.id})

可选:图片回显处理

如果需要前端展示存储的图片,可在Flask查询后将二进制内容转Base64返回:

import base64

@app.route('/get_item/<int:item_id>')
def get_item(item_id):
    item = Items.query.get_or_404(item_id)
    res = {
        "item_name": item.item_name,
        "price": item.price,
        "item_description": item.item_description
    }
    if item.item_pic:
        # 转为Base64格式的data URL,可直接放在img标签的src属性中展示
        pic_b64 = base64.b64encode(item.item_pic).decode('utf-8')
        # 建议上传时同时存储文件的mime类型到数据库,此处直接对应使用更准确
        res['item_pic'] = f'data:image/png;base64,{pic_b64}'
    return jsonify(res)

内容的提问来源于stack exchange,提问作者trufflewaffle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 03:06:04