目录
[1. moudels/users.py](#1. moudels/users.py)
[2. utils/security.py](#2. utils/security.py)
[3. crud/users.py](#3. crud/users.py)
[4. routers/users.py](#4. routers/users.py)
1. moudels/users.py
python
from datetime import datetime
from typing import Optional
from sqlalchemy import Index, Integer, String, Enum, DateTime, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
"""
用户信息表ORM模型
"""
__tablename__ = 'user'
# 创建索引
__table_args__ = (
Index('username_UNIQUE', 'username'),
Index('phone_UNIQUE', 'phone'),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="用户ID")
username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, comment="用户名")
password: Mapped[str] = mapped_column(String(255), nullable=False, comment="密码(加密存储)")
nickname: Mapped[Optional[str]] = mapped_column(String(50), comment="昵称")
avatar: Mapped[Optional[str]] = mapped_column(String(255), comment="头像URL",
default='https://fastly.jsdelivr.net/npm/@vant/assets/cat.jpeg')
gender: Mapped[Optional[str]] = mapped_column(Enum('male', 'female', 'unknown'), comment="性别", default='unknown')
bio: Mapped[Optional[str]] = mapped_column(String(500), comment="个人简介", default='这个人很懒,什么都没留下')
phone: Mapped[Optional[str]] = mapped_column(String(20), unique=True, comment="手机号")
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now(), comment="创建时间")
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now(), onupdate=datetime.now(),
comment="更新时间")
def __repr__(self):
return f"<User(id={self.id}, username='{self.username}', nickname='{self.nickname}')>"
class UserToken(Base):
"""
用户令牌表ORM模型
"""
__tablename__ = 'user_token'
# 创建索引
__table_args__ = (
Index('token_UNIQUE', 'token'),
Index('fk_user_token_user_idx', 'user_id'),
)
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="令牌ID")
user_id: Mapped[int] = mapped_column(Integer, ForeignKey(User.id), nullable=False, comment="用户ID")
token: Mapped[str] = mapped_column(String(255), unique=True, nullable=False, comment="令牌值")
expires_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, comment="过期时间")
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now(), comment="创建时间")
def __repr__(self):
return f"<UserToken(id={self.id}, user_id={self.user_id}, token='{self.token}')>"
2. utils/security.py
python
from passlib.context import CryptContext
# 创建密码上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# 密码加密
def get_hash_password(password : str):
return pwd_context.hash(password)
3. crud/users.py
加密密码的包
python
pip install bcrypt==4.0.1
python
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from models.users import User
from schemas.users import UserRequest
from utils import security
# 根据用户名查询数据库
async def get_user_by_username(db: AsyncSession, username: str):
query = select(User).where(User.username == username)
result = await db.execute(query)
return result.scalar_one_or_none()
# 新增用户
async def create_user(db: AsyncSession, user_data: UserRequest):
# 密码加密
hashed_password = security.get_hash_password(user_data.password)
user = User(username=user_data.username, password=hashed_password)
db.add(user)
await db.commit()
await db.refresh(user) #刷新,从数据库读最新的
return user
4. routers/users.py
python
from fastapi import APIRouter
from fastapi.params import Depends
from sqlalchemy.ext.asyncio import AsyncSession
from common.result import Result
from config.db_confing import get_db
from schemas.users import UserRequest
from crud import users
router = APIRouter(prefix="/api/user", tags=["users"])
# 用户注册
@router.post("register")
async def register(user_data: UserRequest, db: AsyncSession = Depends(get_db)):
# 根据用户名查询数据库
db_user = await users.get_user_by_username(db, user_data.username)
if db_user:
return Result.error("用户已存在",400)
# 新增用户
user = await users.create_user(db, user_data)
return {
"code": 200,
"message": "注册成功",
"data": {
"token": "用户访问令牌",
"userInfo": {
"id": user.id,
"username": user_data.username,
"bio": user.bio,
"avatar": user.avatar
}
}
}