使用python的 FastApi框架开发图书管理系统-前后端分离项目分享

今天给大家分享一个 我最近使用python 框架 fastapi 写的一个web项目 ,叫图书管理系统。项目主要是来巩固 python的编程技术。使用的是前端后 分离开发。

主要实现的功能:

1、用户管理:可以新增、编辑、删除用户信息。

2、图书管理:添加、修改、删除图书,并能够查看图书列表。

3、借阅管理:记录图书借阅、归还情况。

4、数据展示:通过前端页面展示系统中的图书、用户信息,提供了简洁、易用的界面。
使用技术

FastAPI:后端使用FastAPI框架

MySQL 5.7:作为关系型数据库管理系统,MySQL用于存储用户和图书信息,并支持CRUD操作。

Vue 2:前端使用Vue2框架,配合Element UI组件库,提供响应式页面和现代化用户界面。

Element UI:帮助实现简洁且功能丰富的UI设计,极大提高了前端开发效率。

先给大家看一下 页面效果

首页:

代码结构:

菜单个别页面截图:

项目零星代码:

bash 复制代码
<template>
  <div class="home-container">
    <el-container>
      <el-aside width="200px">
        <el-menu
          :default-active="$route.path"
          class="el-menu-vertical"
          background-color="#304156"
          text-color="#bfcbd9"
          active-text-color="#409EFF"
          router
        >
          <el-menu-item index="/">
            <i class="el-icon-s-home"></i>
            <span slot="title">首页</span>
          </el-menu-item>
          <el-submenu index="1">
            <template slot="title">
              <i class="el-icon-reading"></i>
              <span>图书管理</span>
            </template>
            <el-menu-item index="/category/list">
              <i class="el-icon-collection"></i>
              <span slot="title">图书分类</span>
            </el-menu-item>
            <el-menu-item index="/book/list">
              <i class="el-icon-notebook-2"></i>
              <span slot="title">图书列表</span>
            </el-menu-item>
          </el-submenu>
          <el-submenu index="2">
            <template slot="title">
              <i class="el-icon-document"></i>
              <span>借用归还</span>
            </template>
            <el-menu-item index="/borrow/list">
              <i class="el-icon-document-copy"></i>
              <span slot="title">借用列表</span>
            </el-menu-item>
            <el-menu-item index="/return/list">
              <i class="el-icon-document-checked"></i>
              <span slot="title">归还列表</span>
            </el-menu-item>
          </el-submenu>
          <el-submenu index="3">
            <template slot="title">
              <i class="el-icon-user-solid"></i>
              <span>会员管理</span>
            </template>
            <el-menu-item index="/member/list">
              <i class="el-icon-user"></i>
              <span slot="title">会员列表</span>
            </el-menu-item>
            <el-menu-item index="/recharge/list">
              <i class="el-icon-money"></i>
              <span slot="title">充值记录</span>
            </el-menu-item>
          </el-submenu>
          <el-submenu index="4">
            <template slot="title">
              <i class="el-icon-user"></i>
              <span>系统管理</span>
            </template>
            <el-menu-item index="/admin/list">
              <i class="el-icon-user"></i>
              <span slot="title">管理员列表</span>
            </el-menu-item>
          </el-submenu>
        </el-menu>
      </el-aside>
      
      <el-container>
        <el-header>
          <div class="header-right">
            <el-dropdown trigger="click" @command="handleCommand">
              <span class="el-dropdown-link">
                {{ userInfo ? userInfo.username : 'admin' }}<i class="el-icon-arrow-down el-icon--right"></i>
              </span>
              <el-dropdown-menu slot="dropdown">
                <el-dropdown-item command="logout">退出登录</el-dropdown-item>
              </el-dropdown-menu>
            </el-dropdown>
          </div>
        </el-header>
        
        <el-main>
          <router-view />
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>

<script>
import { mapState } from 'vuex'

export default {
  name: 'Home',
  computed: {
    ...mapState('user', ['userInfo'])
  },
  methods: {
    handleCommand(command) {
      if (command === 'logout') {
        this.$store.dispatch('user/resetToken').then(() => {
          this.$router.push('/login')
        })
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.home-container {
  height: 100vh;
  
  .el-container {
    height: 100%;
  }

  .el-aside {
    background-color: #304156;
    
    .el-menu {
      border: none;
    }
  }

  .el-header {
    background-color: #fff;
    box-shadow: 0 1px 4px rgba(0,21,41,.08);
    display: flex;
    justify-content: flex-end;
    align-items: center;
    
    .header-right {
      .el-dropdown-link {
        cursor: pointer;
        color: #409EFF;
      }
    }
  }

  .el-main {
    background-color: #f0f2f5;
    padding: 0;
  }
}
</style>

再分享一段pyhon 后端代码:

bash 复制代码
from datetime import timedelta
from typing import Optional
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from core.config import settings
from core.security import create_access_token
from core.response import ResponseModel
from core.exceptions import CustomException
from core.deps import get_current_admin
from db.database import get_db
from models.admin import Admin
from schemas.admin import AdminLogin, Token, AdminResponse, AdminCreate, AdminUpdate, AdminListResponse
import hashlib

router = APIRouter()

@router.post("/login")
async def login(login_data: AdminLogin, db: Session = Depends(get_db)):
    # 查询管理员
    admin = db.query(Admin).filter(Admin.username == login_data.username).first()
    if not admin:
        raise CustomException(msg="用户名或密码错误")
    
    # MD5加密密码进行比对
    md5_password = hashlib.md5(login_data.password.encode()).hexdigest()
    if admin.password != md5_password:
        raise CustomException(msg="用户名或密码错误")
    
    # 生成访问令牌
    access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": str(admin.id)},
        expires_delta=access_token_expires
    )
    
    token = Token(
        access_token=access_token,
        token_type="bearer"
    )
    
    return ResponseModel.success(
        data=token.model_dump(),
        msg="登录成功"
    )

@router.get("/info")
async def get_admin_info(admin: Admin = Depends(get_current_admin)):
    return ResponseModel.success(
        data=AdminResponse.model_validate(admin),
        msg="获取成功"
    )

@router.get("/list")
async def get_admin_list(
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin),
    page: int = Query(1, ge=1),
    page_size: int = Query(10, ge=1, le=100),
    username: Optional[str] = None
):
    query = db.query(Admin)
    if username:
        query = query.filter(Admin.username.like(f"%{username}%"))
    
    total = query.count()
    items = [AdminResponse.model_validate(item) for item in query.offset((page - 1) * page_size).limit(page_size).all()]
    
    response = AdminListResponse(total=total, items=items)
    return ResponseModel.success(data=response.model_dump())

@router.get("/detail/{admin_id}")
async def get_admin_detail(
    admin_id: int,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin)
):
    admin = db.query(Admin).filter(Admin.id == admin_id).first()
    if not admin:
        raise CustomException(msg="管理员不存在")
    return ResponseModel.success(data=AdminResponse.model_validate(admin))

@router.post("/create")
async def create_admin(
    admin_in: AdminCreate,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin)
):
    # 检查用户名是否已存在
    if db.query(Admin).filter(Admin.username == admin_in.username).first():
        raise CustomException(msg="用户名已存在")
    
    # MD5加密密码
    md5_password = hashlib.md5(admin_in.password.encode()).hexdigest()
    admin = Admin(
        username=admin_in.username,
        password=md5_password,
        nickname=admin_in.nickname,
        is_super=admin_in.is_super,
        created_by=current_admin.username
    )
    db.add(admin)
    db.commit()
    db.refresh(admin)
    return ResponseModel.success(data=AdminResponse.model_validate(admin))

@router.put("/update/{admin_id}")
async def update_admin(
    admin_id: int,
    admin_in: AdminUpdate,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin)
):
    admin = db.query(Admin).filter(Admin.id == admin_id).first()
    if not admin:
        raise CustomException(msg="管理员不存在")
    
    update_data = admin_in.model_dump()
    admin.nickname = update_data['nickname']
    
    db.commit()
    db.refresh(admin)
    return ResponseModel.success(data=AdminResponse.model_validate(admin))

@router.delete("/delete/{admin_id}")
async def delete_admin(
    admin_id: int,
    db: Session = Depends(get_db),
    current_admin: Admin = Depends(get_current_admin)
):
    admin = db.query(Admin).filter(Admin.id == admin_id).first()
    if not admin:
        raise CustomException(msg="管理员不存在")
    
    # 不允许删除超级管理员
    if admin.is_super:
        raise CustomException(msg="不能删除超级管理员")
    
    db.delete(admin)
    db.commit()
    return ResponseModel.success()

项目虽然功能不是很复杂,但是对于刚开始学习编程的小伙伴,有可能也是有难度的,不过如果自己能尝试着 敲一些项目,会对自己的学习到的编程知识有一个更深的体会。对此项目有兴趣的小伙伴可以去看看学习一下。【非开源项目】
https://wwwoop.com/home/Index/projectInfo?goodsId=98&typeParam=1&subKey=-1

相关推荐
夏末蝉未鸣01几秒前
python transformers库笔记(BertForTokenClassification类)
python·自然语言处理·transformer
hackchen4 分钟前
Go与JS无缝协作:Goja引擎实战之错误处理最佳实践
开发语言·javascript·golang
铲子Zzz1 小时前
Java使用接口AES进行加密+微信小程序接收解密
java·开发语言·微信小程序
小小小新人121232 小时前
C语言 ATM (4)
c语言·开发语言·算法
Two_brushes.2 小时前
【linux网络】网络编程全流程详解:从套接字基础到 UDP/TCP 通信实战
linux·开发语言·网络·tcp/udp
weixin_418813872 小时前
Python-可视化学习笔记
笔记·python·学习
小白学大数据2 小时前
R语言爬虫实战:如何爬取分页链接并批量保存
开发语言·爬虫·信息可视化·r语言
争不过朝夕,又念着往昔2 小时前
Go语言反射机制详解
开发语言·后端·golang
Azxcc02 小时前
C++异步编程入门
开发语言·c++
Danceful_YJ2 小时前
4.权重衰减(weight decay)
python·深度学习·机器学习