FastAPI如何将多个图片URL以列表形式存入PostgreSQL数据库
问题场景
使用FastAPI实现多图片上传功能时,图片可正常保存到服务器静态目录,但数据库仅存储最后一张图片的访问URL,无法将所有图片URL以列表形式存入PostgreSQL对应表的img字段。
当前代码存在的核心问题:
- 文件写入循环中,存储文件路径的变量每次迭代都会被覆盖,循环结束后仅保留最后一个文件的路径
- SQLAlchemy模型的
img字段定义为普通字符串类型,不支持数组格式存储 - Pydantic返回模型的
img字段定义为字符串类型,与列表格式不匹配 - 接口构造Product实例时使用了
imgs_url字段名,与模型定义的img字段名不一致,存在参数错误 - 异常处理直接返回普通字典,不符合接口响应模型定义,会触发序列化错误
- 未提前判断存储目录是否存在,目录缺失时会触发文件写入错误
实现方案
1. 调整SQLAlchemy模型
PostgreSQL原生支持数组类型,直接使用SQLAlchemy提供的ARRAY类型存储URL列表,同时补全模型缺失的字段定义:
from sqlalchemy import Column, String, Text, Float from sqlalchemy.dialects.postgresql import ARRAY from sqlalchemy.orm import relationship class Product(Base): __tablename__ = "products" name = Column(String, nullable=False) price = Column(Float, nullable=False) description = Column(Text, nullable=False) owner = relationship("Vendor", back_populates="product") img = Column(ARRAY(String), nullable=False)
注意:修改模型结构后需要执行数据库迁移,同步表结构变更。
2. 调整Pydantic响应模型
将img字段类型修改为字符串列表,匹配数据库存储格式:
from pydantic import BaseModel from typing import List class ProductBase(BaseModel): name: str price: float description: str class ShowProduct(ProductBase): img: List[str] class Config: orm_mode = True
3. 修正上传接口逻辑
初始化空列表收集所有文件的访问URL,循环写入文件时逐个拼接URL加入列表,修正字段名、异常处理、路径拼接等问题:
import os from fastapi import APIRouter, Form, File, UploadFile, Depends, status, HTTPException from sqlalchemy.orm import Session from typing import List # 提前定义常量,不要放在循环内重复赋值 FILEPATH = "./static/product_images/" # 服务访问地址,生产环境替换为实际域名 SERVER_HOST = "http://localhost:8000" @router.post('/addProductFD', status_code=status.HTTP_201_CREATED, response_model=ShowProduct) async def create( name: str = Form(...), price: float = Form(...), description: str = Form(...), files: List[UploadFile] = File(...), db: Session = Depends(get_db), ): # 自动创建存储目录,已存在时不报错 os.makedirs(FILEPATH, exist_ok=True) file_urls = [] for file in files: try: # 生成唯一存储文件名 save_filename = imghex(file.filename) save_full_path = os.path.join(FILEPATH, save_filename) # 写入文件到服务器 contents = await file.read() with open(save_full_path, 'wb') as f: f.write(contents) # 拼接可访问的URL,加入列表 access_url = f"{SERVER_HOST}/static/product_images/{save_filename}" file_urls.append(access_url) except Exception: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="File upload failed" ) finally: await file.close() # 构造数据库记录,字段名与模型保持一致 new_product = Product( name=name, price=price, description=description, img=file_urls ) db.add(new_product) db.commit() db.refresh(new_product) return new_product
4. 配置静态文件访问
确保FastAPI主应用已挂载静态文件目录,否则拼接的图片URL无法正常访问:
from fastapi import FastAPI from fastapi.staticfiles import StaticFiles app = FastAPI() # 挂载静态资源目录 app.mount("/static", StaticFiles(directory="static"), name="static")
验证效果
完成上述修改后,上传多张图片时,所有图片的访问URL会按顺序存入PostgreSQL的img数组字段,接口返回结果也会以列表形式展示所有图片地址,符合预期存储要求。
内容的提问来源于stack exchange,提问作者pythonGo
相关产品推荐
相关产品推荐

