Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

数据库操作

方法论: 数据库就是 Excel 表格,学会增删改查就够了。


📖 本节目标

学完本节,你将能够:

  • ✅ 在 Supabase 创建用户表(像创建 Excel 表格一样简单)
  • ✅ 理解数据库的“增删改查“(这是最核心的)
  • ✅ 用 Python 代码插入/查询数据(复制粘贴就能用)
  • ✅ 实现注册接口连接真实数据库(真正能用的功能)

预计用时: 40 分钟

安心提示: 这节课会出现很多代码,但你不需要记住它们!重点是理解“数据怎么存、怎么取“的逻辑,具体代码可以让 AI 帮你写。


1. 在 Supabase 创建表

1.1 回顾:数据库 = Excel

还记得第一节讲的吗?

数据库 = 一堆 Excel 表格的集合

用户表 (users)
┌────┬──────────┬─────────────────────┬──────────────┬─────────────────────┐
│ id │ username │ email               │ password_hash│ created_at          │
├────┼──────────┼─────────────────────┼──────────────┼─────────────────────┤
│ 1  │ zhangsan │ [email protected]   │ abc123...    │ 2025-01-15 10:30:00 │
│ 2  │ lisi     │ [email protected]      │ def456...    │ 2025-01-15 11:00:00 │
└────┴──────────┴─────────────────────┴──────────────┴─────────────────────┘

1.2 创建用户表(users)

步骤1: 进入 Table Editor

  1. 登录 supabase.com
  2. 选择你的项目
  3. 左侧菜单点击 “Table Editor”

步骤2: 创建新表

  1. 点击 “Create a new table”
  2. 填写信息:

表基本信息:

  • Name: users
  • Description: 用户表

表字段(Columns):

列名类型默认值其他设置
idint8自动生成✅ Primary Key
usernametext-✅ Unique, ✅ Not Null
emailtext-可选
password_hashtext-✅ Not Null
created_attimestamptznow()-
  1. 点击 “Save” 创建表

成功!你的第一张表创建好了! 🎉

1.3 理解字段含义(生活化解释)

字段类型说明生活化类比
idint8 (整数)主键,唯一标识每个用户= 身份证号 每个人独一无二
usernametext (文本)用户名,唯一不能重复= 你的昵称 不能和别人重复
emailtext (文本)邮箱= 你的邮箱地址 可以不填
password_hashtext (文本)加密后的密码= 密码的加密形式 黑客看了也没用
created_attimestamptz (时间)创建时间,自动填充= 注册时间 自动记录,不用你管

看晕了没关系! 这些专业术语(int8timestamptz)都是给数据库看的,你只需要知道:

  • int8 = 数字(像身份证号)
  • text = 文字(像名字)
  • timestamptz = 时间(自动记录,还能处理时区问题)

如何让 AI 帮忙? 当你要创建新表时,直接对 AI 说:“帮我设计一个XX表,需要存XXX信息”,它会告诉你用什么类型。


2. SQL 基础 CRUD

2.1 什么是 SQL?

SQL = 和数据库对话的语言

就像你用中文和人对话,用 SQL 和数据库对话。

重要说明:为什么要学 SQL?

  • SQL 是数据库的“通用语言“,会了它你就懂数据库的工作原理
  • 但是写网站时,你主要会用 Python SDK(第 3 节),不需要手写 SQL
  • 这里的 SQL 主要是:
    1. 理解概念(知道增删改查是什么)
    2. 调试工具(在 Supabase SQL Editor 里快速测试)
    3. 让 AI 帮你写(给 AI 描述需求,它会生成 SQL)

AI 协作提示:你可以对 AI 说:“帮我写一个 SQL 查询,找出所有邮箱不为空的用户”,它会直接生成代码。

2.2 插入数据(INSERT)

语法:

INSERT INTO 表名 (列1, 列2, 列3)
VALUES (值1, 值2, 值3);

实际例子(在 Supabase SQL Editor 运行):

  1. 左侧菜单点击 “SQL Editor”
  2. 点击 “New query”
  3. 输入:
INSERT INTO users (username, email, password_hash)
VALUES ('zhangsan', '[email protected]', 'abc123hashed');
  1. 点击 “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 = '[email protected]'
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 项目中:

  1. 点击左侧 “Settings”(齿轮图标)
  2. 点击 “API”
  3. 找到这两个信息:
    • Project URL: https://xxx.supabase.co
    • anon public key: 一串很长的字符串

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_URLSUPABASE_KEY:这是你家门牌号+钥匙,告诉 Python “去哪里找数据库”
  • create_client:这行代码建立连接,就像拿着钥匙开门
  • supabase:这是连接对象,后面所有操作都通过它

你不需要懂的语法细节(让 AI 写就行):

  • : Client 是什么?(类型注解,机器看的,你不用管)
  • create_client 的实现原理?(底层封装,你不用管)

AI 协作提示:如果 Key 填错了连不上,复制报错信息问 AI:“我的 Supabase 连接报错了:[报错内容],怎么检查?”

安全提示(重要!)

  • 这个 SUPABASE_KEY 是你的数据库钥匙,不要分享给别人
  • 如果要把代码上传到 GitHub 或发给朋友,记得:
    1. 先创建一个 .gitignore 文件,里面写上 db_config.py(这样 Git 就不会上传它)
    2. 或者分享代码时把 Key 删掉,只留个示例:“替换成你的 Key”
  • 如果不小心泄露了 Key,去 Supabase 项目设置里重新生成一个新的(别担心,很简单)

3.4 插入数据

创建 test_db.py:

from db_config import supabase

# 插入一条用户数据
data = {
    "username": "test_user",
    "email": "[email protected]",
    "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": "[email protected]"
}).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": "[email protected]"
}

成功响应:

{
  "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 SDKSQLAlchemy 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="[email protected]",
    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 SDKSQLAlchemy 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 提示

到这里,你应该已经理解:

  1. 数据库就是 Excel 表格(这是核心理解)
  2. SQL 是增删改查的语言(懂概念就行,不用背)
  3. Supabase SDK 操作数据库很简单(复制代码改改就能用)
  4. 用户注册接口可以连接真实数据库了(你做出来真东西了!)

还不太懂?没关系!这样做:

  1. 先跑通代码

    • 把上面的代码复制下来
    • 替换你自己的 Supabase URL 和 Key
    • 运行一遍,看看能不能成功
  2. 遇到报错不要慌

    • 复制完整的报错信息
    • 问 AI:“我运行XX代码报错了:[粘贴报错],怎么解决?”
    • AI 会告诉你具体问题在哪里
  3. 用 AI 帮你写代码

    • 不需要记住语法!
    • 当你想加新功能时,对 AI 说:“帮我写一个查询所有用户的 Python 代码,用 Supabase SDK”
    • 把 AI 生成的代码复制进去,测试一下就行
  4. 验证 AI 写得对不对

    • 运行代码,看看结果对不对
    • 去 Supabase Table Editor 看看数据有没有变化
    • 如果不对,把结果告诉 AI,它会帮你调整

记住 Vibe Coding 的核心

  • 你需要理解“为什么这样做“(比如为什么要加密密码)
  • 具体语法让 AI 帮你写(比如 supabase.table().insert() 的写法)
  • 数据库只是存数据的地方,别被技术术语吓到

AI 协作清单(收藏这个!):

  • “帮我设计一个XX表,需要存储XXX信息”(设计表结构)
  • “帮我写一个查询XX的 Python 代码,用 Supabase SDK”(写查询代码)
  • “我的代码报错了:[报错内容],怎么办?”(调试报错)
  • “这段代码是什么意思:[粘贴代码]”(理解代码逻辑)
  • “怎么验证这个功能是不是正常的?”(测试验证)

📚 下一步

👉 完整功能实现

学习三层架构、JWT 认证,实现生产级别的后端代码。

返回 后端开发基础 查看完整目录。