You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

3.5 KiB

用户模型增加 email 字段

修复时间:2025-01-18
影响范围:User 模型、Schema、Repository


修改内容

1. User 模型(app/models/user.py)

新增字段

email: Optional[str] = Field(default=None, max_length=255, index=True)

特性

  • 可选字段(允许为 NULL)
  • 最大长度 255 字符
  • 添加索引(提升查询性能)
  • 支持邮箱登录(预留)

2. UserResponse Schema(app/schemas/user.py)

新增字段

email: Optional[str] = None

位置:在 phone_verified 之后,username 之前


3. UserRepository(app/repositories/user_repository.py)

新增方法

async def get_by_email(self, email: str) -> Optional[User]:
    """通过邮箱查询用户"""
    statement = select(User).where(
        User.email == email.lower(),
        User.deleted_at.is_(None)
    )
    result = await self.session.exec(statement)
    return result.first()

特性

  • 邮箱统一转小写查询(不区分大小写)
  • 过滤已删除用户
  • 支持邮箱唯一性验证

数据库迁移

方式 1:手动 SQL(推荐用于开发环境)

-- 添加 email 字段
ALTER TABLE users
ADD COLUMN email VARCHAR(255);

-- 添加索引
CREATE INDEX idx_users_email ON users (LOWER(email))
WHERE deleted_at IS NULL AND email IS NOT NULL;

-- 添加唯一约束(可选)
ALTER TABLE users
ADD CONSTRAINT users_email_unique UNIQUE (email);

方式 2:使用 Alembic(推荐用于生产环境)

# 生成迁移文件
alembic revision --autogenerate -m "add_email_to_users"

# 执行迁移
alembic upgrade head

后续扩展

邮箱登录功能

  1. 发送验证码到邮箱

    POST /api/v1/auth/email/send-code
    {
      "email": "user@example.com"
    }
    
  2. 邮箱验证码登录

    POST /api/v1/auth/login/email
    {
      "email": "user@example.com",
      "code": "123456"
    }
    
  3. 绑定邮箱

    POST /api/v1/users/me/bind/email
    {
      "email": "user@example.com",
      "code": "123456"
    }
    

验证测试

1. 查看表结构

\d users

预期输出

Column    | Type                     | Nullable
----------+--------------------------+----------
email     | character varying(255)   | YES

2. 测试邮箱查询

# 在 Python shell 中测试
from app.repositories.user_repository import UserRepository
from app.core.database import get_session

async with get_session() as session:
    repo = UserRepository(session)
    user = await repo.get_by_email("test@example.com")
    print(user)

3. 测试 API 响应

curl -X GET http://localhost:8000/api/v1/users/me \
  -H "Authorization: Bearer $TOKEN"

预期响应

{
  "user_id": 1,
  "phone": "13800138000",
  "country_code": "+86",
  "phone_verified": true,
  "email": null,
  "username": "user_1705564800_a3f9",
  "nickname": null,
  "avatar_url": null,
  "ai_credits_balance": 100,
  "created_at": "2025-01-18T10:00:00Z"
}

注意事项

  1. email 字段为可选,不影响现有手机号登录功能
  2. 邮箱统一转小写存储和查询(不区分大小写)
  3. 添加了索引,提升查询性能
  4. 预留了邮箱登录功能的扩展接口
  5. ⚠️ 如需邮箱唯一性约束,需在数据库层面添加

修复完成时间:2025-01-18
影响文件:3 个
新增代码:约 15 行