ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

FastAPI——掘金头条项目简介

FastAPI——掘金头条项目简介 1 Routers目录介绍1.1路由目录先创建news.py文件1第一步导入 from fastapi import APIRouter2第二步创建APIRouter 路由接口实例 通过创建的实例在项目中进行运行router APIRouter(prifex /api/news , tags news)prifex参数是路由地址的默认前缀tags参数是接口分类用这个路由接口实例的接口会在这一类接口里面3第三步router.get(/categories)修饰器修饰然后进行函数操作router.get(/categories) async def get_categories(): return {message: 获取分类成功}4第四步main.py文件中进行声明挂载和注册路由from news import router (先进行导包)app.include_router(news.router) 路由挂载 在fastapi下面总结问题1什么是模块化路由有什么优势模块化路由就是把每个业务功能的接口拆分到独立的文件里面载统一挂载到主应用中优势项目结构更清晰项目更容易维护2 一个简单的crud全流程1.根据接口文档进行接口设计1创建路由实例接口router APIRouter(prefix/news,tags[news])router.get(/categories)async def get_catergories(db: AsyncSession Depends(get_db),skip 0,limit 10):category await categories(db,skip,limit) #在router中进行封装数据库的操作调用返回结果orm对象return {“code”: 200,message: 获取新闻分类成功data: category}2.定义模块进行导包from sqlalchemy.orm import DeclarativeBase, Mapped创建基础依赖项class Base(DeclarativeBase):created_time : Mapped[datetime] mapped_column(DateTime,default datetime.now,comment 创建时间,creat)update_timeMapped[datetime] mapped_column(Datetime datetime.now,onupdate datetime.now,comment 更新时间)创建表对象class category(Base):__tablename__ news_categoryid : Mapped[int] mapped_column(Interger,primary_keyTrue,autoincrement True)name Mappde[int] mapped_column(String(50),unique True,nullable true,comment 分类名称)3.在crud里面进行数据库操作封装async def catrgories(db:AsyncSession,skip,limit):stmt select(category).offset(skip).limit(limit)result await db.execute(stmt) #获取结果集return result.scalars().all() #返回List[categories]集合结果4.在路由处理器里面调用crud方法响应结果3 解决跨域问题cors:是一种浏览器安全机制用于允许运行在一个源的web应用通过浏览器向另一个源的服务器发起跨域Http请求并在服务器授权的前提下获取资源同源三个条件协议域名端口前端Vuehttp://localhost:5173/后端FastAPIhttp://127.0.0.1:8000/解决问题添加CORS中间件1导包from fastapi.middleware.cors import CORSMiddlewareapp.add_middleware(CORSMidddleware,allow_origins[*],allow_credentials True,allow_methods[*],allow_headers [*])4.对新闻分类和News列表的crud操作1.新闻分类1创建路由接口与路由实例router APIRouter(prefix /api/news,targs [news])router.get(categories)async def getcategories(db: AsyncSession Depends(get_db),skip: int 0,limit: int 0):category await categories(db,skip,limit)return {message : 新闻分类“code”: 200,date: category}(2) 创建moderl实例用来操作先创建一个基类覆盖多个字节可以重复使用class Base(DeclarativeBase):create_at : Mapped[datetime] mapped_column(DateTime,defaultdatetime.now,comment 创建时间)update_at : Mapped[datetime] mapped_column(Datetime,default datetime.now,onupdate datetime.now,comment 更新时间)#创建表类class category(Base):__tablename__ categoryid : Mapped[int] mapped_column(Integer,primary_key True,autoincrement True)name : Mapped[str] mapper_column(String,unique True,nullable True,comment 名字)3进行数据库操作的封装先导包要操作的表的modelfrom models.news import categoryasync def categories(db:AsyncSession,skip:int0,limit:int 10):simt select(category).offset(skip).limit(limit)result await db.excuse(simt)return result.scalars().all()(4) 回到Router层进行调用数据库的封装操作向前端响应2. News列表的crud操作操作逻辑与上述相同3.新闻详细内容的跨域资源共享添加中间件cors在主函数中app.add_middleware(CORSMiddleware,allow_origins [*]allow_credentials Trueallow_headers [*])5.用户模块功能1.用户注册基础路由6.用户注册生成token1.创建token的模型类class UserToken(Base): 用户令牌表ORM模型 __tablename__ user_token id: Mapped[int] mapped_column(Integer, primary_keyTrue, autoincrementTrue, comment令牌ID) user_id: Mapped[int] mapped_column(Integer, ForeignKey(user.id), nullableFalse, comment用户ID) token: Mapped[str] mapped_column(String(255), uniqueTrue, nullableFalse, comment令牌值) expires_at: Mapped[datetime] mapped_column(DateTime, nullableFalse, comment过期时间) created_at: Mapped[datetime] mapped_column(DateTime, defaultdatetime.now(), comment创建时间) __table_args__ ( Index(token_UNIQUE, token), Index(namefk_user_token_user_idx, expressions[user_id]), ) def __repr__(self): return fUserToken(id{self.id}, user_id{self.user_id}, token{self.token})2.在crud中进行操作生成token 并且返回#生成token async def create_token(db:AsyncSession,user_id:int): #生成token 设置过期时间-》查询数据库当前用户是否有token-》有更新没有添加 token str(uuid.uuid4()) expires_at datetime.datetime.now() datetime.timedelta(days30) query select(UserToken).where(UserToken.id user_id) result await db.execute(query) user_token result.scalars().one_or_none() if user_token: user_token.token token user_token.expires_at expires_at else: user_token UserToken(token token,expires_at expires_at,user_id user_id) db.add(user_token) await db.commit() return tokendatetime.timedelta(days 30) # 时间增量30天3.调用生成token方法并返回响应token await create_token(db,user.id)7.封装正确返回响应1.将原本的返回进行封装# return { # code:200, # message:success, # date:{ # token: token, # userInfo: { # id: user.id, # username: user.username, # bio:user.bio, # avatar: user.avatar # } # } # }response_date UserAuthResponse(token token,userInfoUserAuthResponse.model_validate(user))2.创建成功响应工具类responsedef success_response(message:str success,date None): content { code:200, message:message, date:date } #把任何fastapi,Pydance,ORM对象都响应成-》code ,message,date正常的JSON格式 return JSONResponse(content jsonable_encoder(content))3.总结我们把与前端数据响应在py中运用的对象称为pydantic 类创建在schemas中而与数据库操作相关的成为orm类是在sqlarm类中 crud进行操作from typing import Optional from pydantic import BaseModel, Field class UserInfoBase(BaseModel): 用户信息基础数据模型 nickname: Optional[str] Field(None, max_length50, description昵称) avatar: Optional[str] Field(None, max_length255, description头像URL) gender: Optional[str] Field(None, max_length10, description性别) bio: Optional[str] Field(None, max_length500, description个人简介) #userINfo class UserInfo(UserInfoBase): id: int username: str #模型配置类 model_config ConfigDict( populate_by_nameTrue, #允许别名alias和数据库字段名兼容 from_attributesTrue #允许从orm对象中取值 ) #date数据类型 class UserAuthResponse(BaseModel): token: str user_info: UserInfo Field(...,aliasuserInfo) #模型配置 model_config ConfigDict( populate_by_nameTrue, #alias和字段名兼容用的 from_attributesTrue #允许从ORM对象中取值 ) 以上操作可以将数据库获得的orm对象进行转化为-》pydancy对象Field(...,alias userInfo) #起了别名user_info: UserInfo Field(...,aliasuserInfo) #模型配置 model_config ConfigDict( populate_by_nameTrue, #alias和字段名兼容用的 from_attributesTrue #允许从ORM对象中取值 )4.最终进行封装转换调用response_date UserAuthResponse(token token,userInfoUserAuthResponse.model_validate(user)) UserAuthResponse.model_validate(user)会让本属于orm对象的user转化为pydance #这里调用了success_response()方法返回响应 return success_response(注册成功,response_date)**{字典} 就能解包获得字典内部的数据去除大括号
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进