使用 Python 将文件上传到 Supabase Storage 并记录元数据
使用 Python 将文件上传到 Supabase Storage 并记录元数据
在现代应用开发中,文件上传功能是必不可少的需求。Supabase 作为一款优秀的开源 BaaS 平台,提供了强大的存储服务。本文将详细介绍如何使用 Python 将本地文件上传到 Supabase Storage,并将文件的元数据保存到数据库中。
前置准备
前提条件:windows中部署supabase与测试
环境变量配置
首先,我们需要配置必要的环境变量。创建一个 .env
文件或在系统环境中设置以下变量:
SUPABASE_PUBLIC_URL=http://localhost:8000 # 或你的实际 Supabase URL
ANON_KEY=你的匿名密钥
SERVICE_ROLE_KEY=你的服务角色密钥(可选,用于数据库写入)
数据库表结构
在 Supabase Studio 中执行以下 SQL 语句来创建存储元数据的表:
-- 创建上传文件记录表
create table if not exists public.uploaded_files (id bigserial primary key,bucket text not null,path text not null unique,url text not null,created_at timestamptz not null default now()
);-- 创建存储桶
insert into storage.buckets (id, name)
values ('avatars', 'avatars');-- 设置存储策略:允许公开访问
create policy "Avatar images are publicly accessible."on storage.objects for selectusing ( bucket_id = 'avatars' );-- 设置存储策略:允许任何人上传
create policy "Anyone can upload an avatar."on storage.objects for insertwith check ( bucket_id = 'avatars' );-- 设置存储策略:允许更新
create policy "Anyone can update an avatar."on storage.objects for updatewith check ( bucket_id = 'avatars' );
完整实现代码
下面是完整的 Python 实现:
import os
import mimetypes
from supabase import create_client, Client
from dotenv import load_dotenv# 加载环境变量
load_dotenv()# 初始化 Supabase 客户端
SUPABASE_URL = os.getenv("SUPABASE_PUBLIC_URL", "http://localhost:8000")
ANON_KEY = os.getenv("ANON_KEY")
SERVICE_ROLE_KEY = os.getenv("SERVICE_ROLE_KEY")if not ANON_KEY:raise RuntimeError("请先设置 ANON_KEY 环境变量")# 创建客户端实例
supabase: Client = create_client(SUPABASE_URL, ANON_KEY)
admin_client: Client | None = create_client(SUPABASE_URL, SERVICE_ROLE_KEY) if SERVICE_ROLE_KEY else Nonedef upload_file_and_save(file_path: str, bucket: str = "avatars"):"""上传本地文件到 Supabase Storage,并把元数据写入 public.uploaded_files 表Args:file_path: 本地文件路径bucket: 存储桶名称,默认为 'avatars'Returns:dict: 包含上传结果和数据库记录的信息"""# 检查文件是否存在if not os.path.exists(file_path):raise FileNotFoundError(f"文件不存在: {file_path}")# 提取文件名并构建存储路径file_name = os.path.basename(file_path)storage_path = f"uploads/{file_name}" # 可以按需组织路径,例如加上用户ID目录# 猜测文件类型content_type = mimetypes.guess_type(file_path)[0] or "application/octet-stream"# 1) 上传文件到 Supabase Storagewith open(file_path, "rb") as f:data = f.read()upload_res = supabase.storage.from_(bucket).upload(storage_path,data,{"content-type": content_type})# 检查上传错误if getattr(upload_res, "error", None):raise RuntimeError(f"上传失败: {upload_res.error}")# 2) 获取公开访问 URLpublic_url = supabase.storage.from_(bucket).get_public_url(storage_path)# 3) 将元数据写入数据库row = {"bucket": bucket, "path": storage_path, "url": public_url}target_client = admin_client or supabaseinsert_res = target_client.table("uploaded_files").insert(row).execute()# 输出结果print("上传成功:", public_url)print("数据库写入:", insert_res.data)return {"url": public_url, "db": insert_res.data}if __name__ == "__main__":# 使用示例:上传本地文件upload_file_and_save("./example.png")
代码详解
1. 环境配置和客户端初始化
load_dotenv()
SUPABASE_URL = os.getenv("SUPABASE_PUBLIC_URL", "http://localhost:8000")
ANON_KEY = os.getenv("ANON_KEY")
supabase: Client = create_client(SUPABASE_URL, ANON_KEY)
我们使用 python-dotenv
加载环境变量,并创建 Supabase 客户端实例。ANON_KEY
用于基本的存储操作,而 SERVICE_ROLE_KEY
是可选的,用于需要更高权限的数据库写入操作。
2. 文件上传流程
文件检查和处理:
if not os.path.exists(file_path):raise FileNotFoundError(f"文件不存在: {file_path}")file_name = os.path.basename(file_path)
storage_path = f"uploads/{file_name}"
首先检查文件是否存在,然后构建在 Storage 中的存储路径。你可以根据需要修改路径结构,例如添加用户ID:f"users/{user_id}/{file_name}"
。
文件类型检测:
content_type = mimetypes.guess_type(file_path)[0] or "application/octet-stream"
使用 mimetypes
库自动检测文件类型,确保正确设置 Content-Type。
文件上传:
with open(file_path, "rb") as f:data = f.read()upload_res = supabase.storage.from_(bucket).upload(storage_path,data,{"content-type": content_type})
以二进制模式读取文件内容,并使用 Supabase 客户端上传到指定存储桶。
3. 错误处理和结果获取
if getattr(upload_res, "error", None):raise RuntimeError(f"上传失败: {upload_res.error}")public_url = supabase.storage.from_(bucket).get_public_url(storage_path)
检查上传结果中的错误,如果上传成功则获取文件的公开访问 URL。
4. 元数据存储
row = {"bucket": bucket, "path": storage_path, "url": public_url}
target_client = admin_client or supabase
insert_res = target_client.table("uploaded_files").insert(row).execute()
将文件的元信息(存储桶、路径、URL)写入数据库,便于后续查询和管理。
运行方式
- 安装依赖:
uv pip install supabase python-dotenv
-
准备环境:
- 配置
.env
文件 - 在 Supabase 中执行前置 SQL
- 配置
-
运行脚本:
uv run upload_example.py
上传成功: http://localhost:8000/storage/v1/object/public/avatars/uploads/image.png?
数据库写入: [{'id': 1, 'bucket': 'avatars', 'path': 'uploads/image.png', 'url': 'http://localhost:8000/storage/v1/object/public/avatars/uploads/image.png?', 'created_at': '2025-10-01T06:34:49.03286+00:00'}]