数据库操作
方法论: 数据库就是 Excel 表格,学会增删改查就够了。
📖 本节目标
学完本节,你将能够:
- ✅ 在 Supabase 创建用户表(像创建 Excel 表格一样简单)
- ✅ 理解数据库的“增删改查“(这是最核心的)
- ✅ 用 Python 代码插入/查询数据(复制粘贴就能用)
- ✅ 实现注册接口连接真实数据库(真正能用的功能)
预计用时: 40 分钟
安心提示: 这节课会出现很多代码,但你不需要记住它们!重点是理解“数据怎么存、怎么取“的逻辑,具体代码可以让 AI 帮你写。
1. 在 Supabase 创建表
1.1 回顾:数据库 = Excel
还记得第一节讲的吗?
数据库 = 一堆 Excel 表格的集合
用户表 (users)
┌────┬──────────┬─────────────────────┬──────────────┬─────────────────────┐
│ id │ username │ email │ password_hash│ created_at │
├────┼──────────┼─────────────────────┼──────────────┼─────────────────────┤
│ 1 │ zhangsan │ zhang@example.com │ abc123... │ 2025-01-15 10:30:00 │
│ 2 │ lisi │ li@example.com │ def456... │ 2025-01-15 11:00:00 │
└────┴──────────┴─────────────────────┴──────────────┴─────────────────────┘
1.2 创建用户表(users)
步骤1: 进入 Table Editor
- 登录 supabase.com
- 选择你的项目
- 左侧菜单点击 “Table Editor”
步骤2: 创建新表
- 点击 “Create a new table”
- 填写信息:
表基本信息:
- Name:
users - Description: 用户表
表字段(Columns):
| 列名 | 类型 | 默认值 | 其他设置 |
|---|---|---|---|
id | int8 | 自动生成 | ✅ Primary Key |
username | text | - | ✅ Unique, ✅ Not Null |
email | text | - | 可选 |
password_hash | text | - | ✅ Not Null |
created_at | timestamptz | now() | - |
- 点击 “Save” 创建表
成功!你的第一张表创建好了! 🎉
1.3 理解字段含义(生活化解释)
| 字段 | 类型 | 说明 | 生活化类比 |
|---|---|---|---|
| id | int8 (整数) | 主键,唯一标识每个用户 | = 身份证号 每个人独一无二 |
| username | text (文本) | 用户名,唯一不能重复 | = 你的昵称 不能和别人重复 |
text (文本) | 邮箱 | = 你的邮箱地址 可以不填 | |
| password_hash | text (文本) | 加密后的密码 | = 密码的加密形式 黑客看了也没用 |
| created_at | timestamptz (时间) | 创建时间,自动填充 | = 注册时间 自动记录,不用你管 |
看晕了没关系! 这些专业术语(int8、timestamptz)都是给数据库看的,你只需要知道:
int8= 数字(像身份证号)text= 文字(像名字)timestamptz= 时间(自动记录,还能处理时区问题)
如何让 AI 帮忙? 当你要创建新表时,直接对 AI 说:“帮我设计一个XX表,需要存XXX信息”,它会告诉你用什么类型。
2. SQL 基础 CRUD
2.1 什么是 SQL?
SQL = 和数据库对话的语言
就像你用中文和人对话,用 SQL 和数据库对话。
重要说明:为什么要学 SQL?
- SQL 是数据库的“通用语言“,会了它你就懂数据库的工作原理
- 但是写网站时,你主要会用 Python SDK(第 3 节),不需要手写 SQL
- 这里的 SQL 主要是:
- 理解概念(知道增删改查是什么)
- 调试工具(在 Supabase SQL Editor 里快速测试)
- 让 AI 帮你写(给 AI 描述需求,它会生成 SQL)
AI 协作提示:你可以对 AI 说:“帮我写一个 SQL 查询,找出所有邮箱不为空的用户”,它会直接生成代码。
2.2 插入数据(INSERT)
语法:
INSERT INTO 表名 (列1, 列2, 列3)
VALUES (值1, 值2, 值3);
实际例子(在 Supabase SQL Editor 运行):
- 左侧菜单点击 “SQL Editor”
- 点击 “New query”
- 输入:
INSERT INTO users (username, email, password_hash)
VALUES ('zhangsan', 'zhang@example.com', 'abc123hashed');
- 点击 “Run” 或按
Ctrl+Enter
成功! 刷新 Table Editor,应该能看到新增的数据。
2.3 查询数据(SELECT)
查询所有用户:
SELECT * FROM users;
条件查询(查找用户名为 zhangsan 的用户):
SELECT * FROM users WHERE username = 'zhangsan';
只查询特定字段:
SELECT id, username, email FROM users;
排序(按创建时间倒序):
SELECT * FROM users ORDER BY created_at DESC;
限制返回数量(只返回前 10 条):
SELECT * FROM users LIMIT 10;
组合使用:
SELECT id, username, email
FROM users
WHERE email IS NOT NULL
ORDER BY created_at DESC
LIMIT 10;
2.4 更新数据(UPDATE)
语法:
UPDATE 表名
SET 列1 = 新值1, 列2 = 新值2
WHERE 条件;
实际例子:
UPDATE users
SET email = 'new_email@example.com'
WHERE username = 'zhangsan';
⚠️ 重要: WHERE 条件一定要写!否则会更新所有行!
2.5 删除数据(DELETE)
语法:
DELETE FROM 表名 WHERE 条件;
实际例子:
DELETE FROM users WHERE id = 1;
⚠️ 危险: 实际项目建议用“软删除“(添加 is_deleted 字段),而不是真删除。
3. 用 Python 连接 Supabase
这才是重点! 从这里开始,你会学到在真实项目中如何用 Python 操作数据库。前面的 SQL 你看懂概念就行,具体写代码主要用这节的方法。
3.0 文件结构说明(先看这里!)
在开始写代码前,我们要建立这样的文件夹结构:
我的项目/
├── db_config.py # 数据库连接配置(专门存 Supabase URL 和 Key)
├── main.py # 主程序(你的 FastAPI 应用)
└── test_db.py # 测试文件(测试数据库连接,测完可以删)
为什么要分文件?
db_config.py:把密码(Key)单独放一个文件,安全+方便管理main.py:主程序,这里写你的接口代码test_db.py:先用这个文件测试能不能连上数据库,测通了再写主程序
3.1 安装 Supabase 库
pip install supabase
如果报错怎么办?(常见问题)
报错 1: pip: command not found
- 原因: Python 没装好或者环境变量没配置
- AI 提示: 复制这个报错,问 AI:“我运行 pip install supabase 报错了:[粘贴报错内容],怎么办?”
报错 2: ERROR: Could not find a version...
- 原因: 网络问题或者拼写错误
- 解决: 检查网络,确认命令拼写正确,或者换个镜像源(问 AI:“pip 安装报错怎么换镜像源?”)
3.2 获取连接信息
在 Supabase 项目中:
- 点击左侧 “Settings”(齿轮图标)
- 点击 “API”
- 找到这两个信息:
- Project URL:
https://xxx.supabase.co - anon public key: 一串很长的字符串
- Project URL:
3.3 创建连接
创建 db_config.py(在项目文件夹里新建这个文件):
from supabase import create_client, Client
# Supabase 连接配置
SUPABASE_URL = "https://xxx.supabase.co" # 替换成你的 URL
SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI..." # 替换成你的 Key
# 创建客户端
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
代码解释(你需要懂的逻辑):
SUPABASE_URL和SUPABASE_KEY:这是你家门牌号+钥匙,告诉 Python “去哪里找数据库”create_client:这行代码建立连接,就像拿着钥匙开门supabase:这是连接对象,后面所有操作都通过它
你不需要懂的语法细节(让 AI 写就行):
: Client是什么?(类型注解,机器看的,你不用管)create_client的实现原理?(底层封装,你不用管)
AI 协作提示:如果 Key 填错了连不上,复制报错信息问 AI:“我的 Supabase 连接报错了:[报错内容],怎么检查?”
安全提示(重要!):
- 这个
SUPABASE_KEY是你的数据库钥匙,不要分享给别人! - 如果要把代码上传到 GitHub 或发给朋友,记得:
- 先创建一个
.gitignore文件,里面写上db_config.py(这样 Git 就不会上传它) - 或者分享代码时把 Key 删掉,只留个示例:“替换成你的 Key”
- 先创建一个
- 如果不小心泄露了 Key,去 Supabase 项目设置里重新生成一个新的(别担心,很简单)
3.4 插入数据
创建 test_db.py:
from db_config import supabase
# 插入一条用户数据
data = {
"username": "test_user",
"email": "test@example.com",
"password_hash": "hashed_password_123"
}
response = supabase.table('users').insert(data).execute()
print("插入成功!")
print("新用户 ID:", response.data[0]['id'])
运行:
python test_db.py
3.5 查询数据
from db_config import supabase
# 查询所有用户
response = supabase.table('users').select("*").execute()
print("所有用户:")
for user in response.data:
print(f"ID: {user['id']}, 用户名: {user['username']}")
# 条件查询
response = supabase.table('users').select("*").eq('username', 'zhangsan').execute()
if response.data:
print("找到用户:", response.data[0])
else:
print("用户不存在")
3.6 更新数据
from db_config import supabase
# 更新用户邮箱
supabase.table('users').update({
"email": "new_email@example.com"
}).eq('username', 'zhangsan').execute()
print("更新成功!")
3.7 删除数据
from db_config import supabase
# 删除用户
supabase.table('users').delete().eq('id', 1).execute()
print("删除成功!")
4. 实战:用户注册连接数据库
4.1 完整代码
db_config.py (数据库配置):
from supabase import create_client, Client
SUPABASE_URL = "https://xxx.supabase.co" # 替换
SUPABASE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI..." # 替换
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
main.py (主程序):
from fastapi import FastAPI
from pydantic import BaseModel, Field, EmailStr
from typing import Optional, Any
import hashlib
from db_config import supabase
# ===== 数据模型 =====
class UserRegisterRequest(BaseModel):
username: str = Field(..., min_length=3, max_length=50)
password: str = Field(..., min_length=6)
email: Optional[EmailStr] = None
class Response(BaseModel):
code: int
msg: str
data: Optional[Any] = None
class R:
@staticmethod
def success(data: Any = None, msg: str = "操作成功"):
return Response(code=200, msg=msg, data=data)
@staticmethod
def error(msg: str = "操作失败", code: int = 500):
return Response(code=code, msg=msg, data=None)
# ===== FastAPI 应用 =====
app = FastAPI(title="我的后端 API", version="1.0.0")
@app.post("/api/users/register", response_model=Response)
def register(user: UserRegisterRequest):
"""用户注册接口(连接真实数据库)"""
# 1. 检查用户名是否已存在
existing_user = supabase.table('users').select("*").eq('username', user.username).execute()
if existing_user.data:
return R.error(msg="用户名已存在", code=400)
# 2. 密码加密
password_hash = hashlib.sha256(user.password.encode()).hexdigest()
# 3. 插入数据库
try:
new_user = supabase.table('users').insert({
"username": user.username,
"email": user.email,
"password_hash": password_hash
}).execute()
return R.success(
msg="注册成功",
data={"user_id": new_user.data[0]['id']}
)
except Exception as e:
return R.error(msg=f"注册失败: {str(e)}", code=500)
@app.get("/api/users", response_model=Response)
def list_users():
"""查看所有用户"""
response = supabase.table('users').select("id, username, email, created_at").execute()
return R.success(data=response.data)
@app.get("/api/users/{user_id}", response_model=Response)
def get_user(user_id: int):
"""获取单个用户信息"""
response = supabase.table('users').select("*").eq('id', user_id).execute()
if not response.data:
return R.error(msg="用户不存在", code=404)
return R.success(data=response.data[0])
# ===== 启动应用 =====
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
4.2 测试
启动应用:
python main.py
测试注册(访问 http://localhost:8000/docs):
POST /api/users/register
{
"username": "xiaoming",
"password": "123456",
"email": "xiaoming@example.com"
}
成功响应:
{
"code": 200,
"msg": "注册成功",
"data": {
"user_id": 3
}
}
在 Supabase Table Editor 查看,应该能看到新增的用户!
5. SQLAlchemy ORM 入门(进阶,初学者可跳过)
重要提示:新手可以直接跳过这一节! 前面学的 Supabase SDK 已经完全够用了。这一节是给以后想深入了解的人准备的。
5.1 什么是 ORM?
ORM = Object-Relational Mapping(对象关系映射)
通俗解释(翻译官类比):
想象你要和一个只会德语的人交流,但你不会德语:
- 不用 ORM:你得先学德语,然后写德语句子(= 手写 SQL 语句)
- 用 ORM:你找了个翻译官,你说中文(= 写 Python 对象),翻译官自动帮你翻译成德语(= ORM 自动生成 SQL)
你的代码:user = User(username='zhangsan')
↓ (ORM 自动翻译)
SQL语句:INSERT INTO users (username) VALUES ('zhangsan')
5.2 为什么这一节可以跳过?
| 场景 | Supabase SDK | SQLAlchemy ORM |
|---|---|---|
| 学习难度 | ✅ 简单(5 分钟上手) | ❌ 复杂(需要学模型定义) |
| 适用数据库 | 只能用 Supabase | 任何 SQL 数据库 |
| 是否够用 | ✅ 小项目完全够 | 大公司/复杂项目才需要 |
建议:现在用 Supabase SDK 就行,等你做大项目或者公司要求用本地数据库时,再回来学这一节。
想了解的同学点这里展开(可选)
5.3 安装 SQLAlchemy
pip install sqlalchemy psycopg2-binary
5.4 定义模型
创建 models/user.py:
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime
Base = declarative_base()
class User(Base):
"""用户表模型"""
__tablename__ = "users"
id = Column(Integer, primary_key=True, autoincrement=True)
username = Column(String(50), unique=True, nullable=False)
email = Column(String(100))
password_hash = Column(String(255), nullable=False)
created_at = Column(DateTime, default=datetime.utcnow)
def to_dict(self):
"""转换为字典"""
return {
"id": self.id,
"username": self.username,
"email": self.email,
"created_at": self.created_at.isoformat() if self.created_at else None
}
5.4 使用 ORM(示例)
注意: Supabase Python SDK 已经很方便了,ORM 主要用于更复杂的场景(本地 PostgreSQL、MySQL 等)。
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models.user import User
# 连接数据库(需要 PostgreSQL 连接字符串)
DATABASE_URL = "postgresql://user:password@host:5432/database"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(bind=engine)
# 使用
db = SessionLocal()
# 创建用户
new_user = User(
username="zhangsan",
email="zhang@example.com",
password_hash="hashed_password"
)
db.add(new_user)
db.commit()
# 查询用户
user = db.query(User).filter(User.username == "zhangsan").first()
print(user.to_dict())
# 关闭连接
db.close()
再次提醒:初学者真的不需要看这一节!用 Supabase SDK 就够了。
6. 常见问题
Q1: Supabase SDK 和 SQLAlchemy 有什么区别?
A:
| 特性 | Supabase SDK | SQLAlchemy ORM |
|---|---|---|
| 简单度 | ✅ 简单直接 | ⚠️ 需要定义模型 |
| 学习成本 | 低 | 中等 |
| 适用场景 | Supabase 云数据库 | 任何 SQL 数据库 |
| 推荐 | 新手/小项目 | 大项目/本地数据库 |
建议: 本项目用 Supabase SDK 就够了。
Q2: 为什么不把密码明文存储?
A: 数据库被黑客入侵时,用户密码不会泄露。
# ❌ 明文
password = "123456" # 黑客直接看到
# ✅ 加密
password_hash = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5..." # 无法反推原密码
Q3: created_at 时间不对怎么办?
A: Supabase 默认用 UTC 时间,需要转换成本地时间。
from datetime import datetime, timezone
# UTC 转北京时间(+8 小时)
created_at_utc = user['created_at'] # "2025-01-15T02:30:00Z"
created_at_local = datetime.fromisoformat(created_at_utc.replace('Z', '+00:00'))
created_at_beijing = created_at_local.astimezone(timezone(timedelta(hours=8)))
Q4: 如何防止 SQL 注入?
A: 用 Supabase SDK 或 ORM,不要自己拼接 SQL。
# ❌ 危险(可能被 SQL 注入)
username = request.username
query = f"SELECT * FROM users WHERE username = '{username}'"
# ✅ 安全(使用参数化查询)
supabase.table('users').select("*").eq('username', username).execute()
💡 Vibe Coding 提示
到这里,你应该已经理解:
- 数据库就是 Excel 表格(这是核心理解)
- SQL 是增删改查的语言(懂概念就行,不用背)
- Supabase SDK 操作数据库很简单(复制代码改改就能用)
- 用户注册接口可以连接真实数据库了(你做出来真东西了!)
还不太懂?没关系!这样做:
-
先跑通代码:
- 把上面的代码复制下来
- 替换你自己的 Supabase URL 和 Key
- 运行一遍,看看能不能成功
-
遇到报错不要慌:
- 复制完整的报错信息
- 问 AI:“我运行XX代码报错了:[粘贴报错],怎么解决?”
- AI 会告诉你具体问题在哪里
-
用 AI 帮你写代码:
- 不需要记住语法!
- 当你想加新功能时,对 AI 说:“帮我写一个查询所有用户的 Python 代码,用 Supabase SDK”
- 把 AI 生成的代码复制进去,测试一下就行
-
验证 AI 写得对不对:
- 运行代码,看看结果对不对
- 去 Supabase Table Editor 看看数据有没有变化
- 如果不对,把结果告诉 AI,它会帮你调整
记住 Vibe Coding 的核心:
- 你需要理解“为什么这样做“(比如为什么要加密密码)
- 具体语法让 AI 帮你写(比如
supabase.table().insert()的写法) - 数据库只是存数据的地方,别被技术术语吓到
AI 协作清单(收藏这个!):
- “帮我设计一个XX表,需要存储XXX信息”(设计表结构)
- “帮我写一个查询XX的 Python 代码,用 Supabase SDK”(写查询代码)
- “我的代码报错了:[报错内容],怎么办?”(调试报错)
- “这段代码是什么意思:[粘贴代码]”(理解代码逻辑)
- “怎么验证这个功能是不是正常的?”(测试验证)
📚 下一步
👉 完整功能实现
学习三层架构、JWT 认证,实现生产级别的后端代码。
返回 后端开发基础 查看完整目录。