每年到这个时间点都会有一大批计算机专业的学生被毕业设计按在地上摩擦。我看后台咨询量最大的题目除了各种商城系统、管理系统就是“图书管理系统”这种经典题型。今天专门挑一个非常具体、非常有代表性的题目来聊——基于Django的图书管理系统设计。这个题目乍一看是“烂大街”的选题但正因为烂大街才值得好好拆解为什么大家都选它怎么把它做出亮点里面涉及的所有技术点都串起来应该怎么做。不管你是完全零基础、只学了点Python语法还是已经能写点小项目但没系统走完一个全栈流程这篇文章都能给你一套可以照着做的完整思路。我会从选题逻辑讲到数据库设计从Django的MTV机制讲到爬虫数据采集再到数据可视化大屏的实现最后把答辩和文案准备的那些坑也一并说清楚。所有内容都围绕“基于Django的图书管理系统”这个核心展开该有的代码、该解释的原理、该注意的细节我都会放在里面。1. 项目选题与整体设计思路剖析1.1 为什么图书管理系统是毕业设计的“常青树”很多人觉得图书管理系统太老了没新意。但你仔细想想一个毕业设计要满足三件事能独立完成、能讲清楚、能顺利通过答辩。图书管理系统的价值恰恰在这三点上非常均衡。首先是业务逻辑清晰。图书、读者、借阅、归还、分类管理这些实体和关系连外行都能看懂所以你在答辩时不需要花大量时间给评委解释业务背景直接把技术亮点抛出来就行。其次是可扩展性强。一个基础的借还书系统做出来只是及格你可以往里面加推荐算法、加数据可视化、加爬虫自动采集书目、加小程序前端这些都是现成的加分项。标题里提到爬虫、大数据、数据可视化、小程序其实就是这个题目常见的“升级套餐”。最后是安全隐患小。图书管理系统的业务不敏感数据量也不大不会涉及支付、用户隐私等高危场景做的时候不用担心太多合规问题适合学生练手。我的建议是不要因为它“老”就嫌弃老题新做才是聪明人的玩法。1.2 技术选型为什么是Django而不是Spring Boot、PHP或Servlet题目列举了JAVA、PHP、C#、C等多种技术栈但核心落在了Django上。这说明此类系统用Django做是最顺手的原因有三点。第一开发效率高。Django自带的admin后台可以让你在半小时内拥有一个可用的数据管理界面很适合作初期验证。图书管理系统需要的大部分功能如用户认证、ORM、表单处理Django都内置了不需要自己造轮子。第二全栈体验完整。Django采用的是MTV模式Model模型、Template模板、View视图三层架构配合URL路由基本能让你体验到一个完整Web项目的开发流程。相比前后端分离的Spring BootVue方案Django的“一套代码跑通前后端”的模式对新手更友好。第三生态契合数据相关扩展。标题里提到爬虫、数据可视化、大数据这些用Python来做是最顺畅的。Django项目里直接写爬虫脚本、用pandas做数据分析、把结果渲染到ECharts图表里全程不需要切换语言。我见过不少做Spring Boot图书管理系统的同学后端倒是写得很框架化但到数据分析和可视化阶段就卡住了。而Django这边可以用Python一条龙搞定。所以如果题目已经锁定了Django就别纠结安心走这条路。1.3 功能模块拆解与角色权限的底层设计一个图书管理系统的核心功能拆开来看其实就三类图书管理、读者管理、借阅管理。但要想让系统真的“能用”还必须加上用户认证、分类管理和数据统计。我建议把系统的角色分成三层系统管理员、图书管理员、普通读者。系统管理员负责后台配置和权员管理图书管理员负责图书录入、上架、下架以及处理借书还书操作普通读者通过前端页面检索图书、查看详情、发起借阅。权限这块Django本身自带用户认证体系你可以直接沿用也可以用更精细的RBAC基于角色的访问控制模型。图书管理系统用简单的RBAC足够给用户分配一个role字段用装饰器或中间件控制不同角色能访问的URL。比如login_required保证只有登录用户能借书再加一个user_passes_test(lambda u: u.is_staff)限制只有管理员能访问后台编辑页面。业务状态这一点很容易被忽略我重点提醒一下。借阅记录不能只有“借出”和“归还”两个状态建议至少包含申请中、已借出、已归还、逾期未还、已拒借。这样前端读者能查到申请进度管理员能在后台看到待办事项答辩时讲到这一步评委会觉得你考虑到了真实业务场景。1.4 数据库设计五张核心表把整个系统撑起来数据库设计决定了系统能跑多远。图书管理系统不建议上来就设计十几张表五张核心表就能覆盖大多数功能。第一张是BookCategory图书分类表字段就两个分类名称和分类描述。注意给分类名称加唯一约束否则会出现“文学”和“文学 ”这种重复数据。第二张是Book图书表核心字段包括书名、作者、ISBN号、出版社、出版日期、总库存、可借库存、封面图片、分类外键。ISBN建议加唯一索引因为同一本书的ISBN应该是唯一的。库存字段要区分总库存和可借库存每次借还时更新可借库存否则业务数据会对不上。第三张是Reader读者表建议直接用Django内置的User表做一对一扩展学号/工号、姓名、学院、联系方式、借阅额度。不要另起炉灶自己搞一张用户表自带的认证体系更安全、更省事。第四张是BorrowRecord借阅记录表核心字段有读者外键、图书外键、借书时间、应还时间、实际归还时间、状态。这张表是整个系统最核心的表也是后期做数据统计的主要数据来源。第五张是Announcement公告表非必选但加上它能丰富前端首页的内容也让管理员有个发布通知的入口属于花小钱办大事的设计。外键关系的设计原则是不需要级联删除操作。比如删除一本图书时如果有未归还的借阅记录直接用数据库约束拦下来不要让系统把借阅记录一起删了不然数据会变得非常混乱。2. Django核心机制与关键原理解读2.1 MTV模式到底怎么回事别再叫它MVCDjango的学习资料里经常出现MTV这个词——Model、Template、View。很多同学看到MVC就往上套在答辩时脱口而出“这是MVC架构”评委不一定会纠正你但你自己得知道区别在哪。Django里的View是业务逻辑层接收HTTP请求处理数据返回响应。它的职责对应MVC里的Controller。Django里的Template是展示层负责HTML渲染对应MVC里的View。Model则对应MVC里的Model负责和数据库打交道。简单来说MTV的V是“业务处理者”MTV的T才是“页面展示者”。写代码时这个分层非常明确models.py里定义数据结构views.py里写业务逻辑templates目录里放HTML模板urls.py做路由分发。你想查一本书的列表URL先命中urls.py然后调用对应的view函数这个函数通过Book.objects.all()从数据库取数据再把数据打包成字典传到template里渲染成HTML最后返回给浏览器。整个过程我建议你在答辩时画一张流程图就能讲清楚这是最基础的送分题。2.2 ORM不写SQL也能完成所有增删改查Django的ORM对象关系映射设计得相当优雅我能不用原生SQL就尽量不用。图书管理系统的所有数据库操作都可以用ORM完成。常用的查询操作包括Book.objects.all()查所有Book.objects.get(id1)查单条Book.objects.filter(category__name文学)按分类查Book.objects.exclude(stock0)排除无库存的书Book.objects.order_by(-pub_date)按出版日期倒序。如果你需要在搜索功能里同时按书名和作者查就用Q对象Book.objects.filter(Q(title__icontainskeyword) | Q(author__icontainskeyword))icontains表示不区分大小写的模糊查询。分页用Django自带的Paginator几行代码就能搞定不用自己写前后端分页逻辑。更新数据时注意不要这样写先book Book.objects.get(id1)再把book.stock减1最后book.save()。这在高并发场景下会出问题因为两步操作之间存在时间差。正确写法是原子更新from django.db.models import F Book.objects.filter(id1).update(stockF(stock) - 1)F表达式会把加减操作放在数据库层面完成避免并发冲突。这个细节放在毕设里就是加分项在答辩时能讲出来会让评委眼前一亮。2.3 用户认证、会话管理与登录权限控制图书管理系统必须区分“登录用户”和“游客”。Django内置的认证系统提供了大部分基础能力包括用户表、session管理、密码哈希加密。你的关键代码应该放在用户扩展上。定义好Reader模型后用Django的信号机制在User创建时自动创建关联的Reader记录from django.db.models.signals import post_save from django.dispatch import receiver from django.contrib.auth.models import User receiver(post_save, senderUser) def create_reader(sender, instance, created, **kwargs): if created: Reader.objects.create(userinstance, student_idinstance.username)登录视图我建议直接用django.contrib.auth的authenticate和login函数不要在request.session里用session[key]user_id这种原始方案。登录后用户信息可以通过request.user拿到模板里用{% if user.is_authenticated %}判断是否显示个人中心或退出按钮。视图访问控制这是很多新手会漏掉的一环。只写login视图却没有给其他视图加保护这意味着游客可以直接输入/borrow/的URL地址来访问借书接口。正确的做法是给需要登录的视图加上login_required装饰器。需要区分角色的再加一个自定义装饰器或者用user_passes_test。2.4 爬虫数据采集这部分的红线必须说清楚说到标题里的爬虫这个词我得先泼一盆冷水。图书管理系统如果需要“批量导入书目数据”爬虫确实是最直接的手段。但你一定要想清楚三个问题数据源是否允许爬取、你爬下来的数据用途是什么、爬取频率是否会影响对方服务器。我的建议是毕设项目里尽量选有正规API或者明确允许数据访问的公开图书网站比如出版社的公开书目接口、政府开放的图书馆数据等。不要拿技术手段去突破对方网站的反爬机制不要爬需要登录才能访问的数据更不要把个人隐私数据或者受版权保护的内容拿来当实验材料。爬虫本身不是违法的但未经授权抓取不属于你的数据就很容易迈过红线。安全合法的爬虫代码核心逻辑其实很简单用requests获取网页用BeautifulSoup解析数据再把结构化数据存入模型import requests from bs4 import BeautifulSoup url https://example.com/books headers {User-Agent: Mozilla/5.0} resp requests.get(url, headersheaders, timeout5) soup BeautifulSoup(resp.text, html.parser) for item in soup.select(.book-item): title item.select_one(.title).text.strip() author item.select_one(.author).text.strip() # 保存到数据库 Book.objects.update_or_create(titletitle, defaults{author: author})update_or_create是个宝藏方法重复爬取时不会产生重复数据。爬虫在毕设里是加分项但前提是你把“合规意识”写进代码注释里答辩时主动提一句“只抓取公开数据遵守robots协议”这个态度就对了。2.5 数据可视化与“大数据”的落地思路图书管理系统里的数据量离“大数据”差得远但这不妨碍你用大数据分析的方法论去处理业务数据。数据可视化是更好的切入角度。最常见的可视化工具有三种路线用ECharts在前端画图表、用Matplotlib在后端生成图片、用Django模板直接渲染数据表格。我的推荐是ECharts理由是动态交互效果好答辩演示时观感最佳。可视化的数据来源就是借阅记录表。比如统计每月的借阅量用ORM按月分组from django.db.models import Count from django.db.models.functions import TruncMonth from datetime import date monthly_data ( BorrowRecord.objects .filter(borrow_date__yeardate.today().year) .annotate(monthTruncMonth(borrow_date)) .values(month) .annotate(totalCount(id)) .order_by(month) )拿到monthly_data后转成JSON格式传到前端ECharts用ajax请求接口填充图表数据。这类图表我建议至少做三个月度借阅趋势折线图、分类占比饼图、图书借阅排名条形图。这三个图表能覆盖时间、分类和排行三个维度信息量足够开发量也不大。大数据方面你不需要真的上Hadoop或Spark毕设阶段只要你用了pandas做数据分析、用了聚合查询来统计特征本质上就是大数据分析的基础流程。真到答辩环节评委更看重你对数据的理解而不是你部署了多牛的集群。3. 实操过程从零开始搭建整个系统3.1 环境准备与虚拟环境管理这一节写给刚入门的朋友老手可以直接跳过。动手开发前先把Python环境理清楚。第一步是安装Python哪怕你电脑上已经装了Python我也建议先确认版本Django 4.x版本需要Python 3.8以上。命令行输入python --version看一下结果。Windows电脑如果提示找不到命令大概率是安装时没勾选“Add Python to PATH”重装一下就能解决。第二步是创建虚拟环境。这一步很多人偷懒不做直接pip install django装到全局环境里。短期看是省事但等你后面装了别的项目依赖版本冲突会越积越多。正确做法python -m venv venv # Windows激活虚拟环境 venv\Scripts\activate # macOS / Linux激活虚拟环境 source venv/bin/activate看到命令行前面出现(venv)就说明虚拟环境生效了。然后安装Djangopip install django pip install requests beautifulsoup4 pandas我顺手把爬虫和数据处理的依赖也装上了后面扩展功能时直接用。3.2 创建项目与数据库配置在命令行里执行django-admin startproject library_system cd library_system python manage.py startapp books这样会生成一个名为library_system的主项目目录和一个名为books的应用目录。如果你后面要做用户模块扩展再创建一个users应用要做图表统计再创建一个stats应用。把不同功能拆成不同app比全堆在books里要清晰很多。数据库配置这部分开发阶段我建议直接用自带的SQLite零配置一个文件搞定。如果你实验环境装了MySQL可以切换过去。这里我直接给出MySQL的配置写法DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: library_db, USER: root, PASSWORD: yourpassword, HOST: 127.0.0.1, PORT: 3306, OPTIONS: {charset: utf8mb4}, } }用MySQL还需要装驱动在项目目录下执行pip install pymysql然后在__init__.py里加两行import pymysql pymysql.install_as_MySQLdb()3.3 Models模型设计与核心代码在books/models.py里我把前面设计的核心表模型写出来。这里注意Django的字段设计文本类用CharField要指定max_length多行文本用TextField日期字段用DateField数字字段用IntegerField外键用ForeignKey在字符串引用里写Reader这样的模型名就行。from django.db import models from django.contrib.auth.models import User class BookCategory(models.Model): name models.CharField(分类名称, max_length50, uniqueTrue) desc models.TextField(分类描述, blankTrue) class Meta: verbose_name 图书分类 verbose_name_plural verbose_name def __str__(self): return self.name class Book(models.Model): title models.CharField(书名, max_length200) author models.CharField(作者, max_length100) isbn models.CharField(ISBN号, max_length20, uniqueTrue) publisher models.CharField(出版社, max_length100, blankTrue) pub_date models.DateField(出版日期, nullTrue, blankTrue) total_stock models.IntegerField(总库存, default1) available_stock models.IntegerField(可借库存, default1) cover models.ImageField(封面, upload_tocovers/, blankTrue, nullTrue) category models.ForeignKey(BookCategory, on_deletemodels.PROTECT, verbose_name分类) created_at models.DateTimeField(创建时间, auto_now_addTrue) class Meta: verbose_name 图书 verbose_name_plural verbose_name def __str__(self): return self.title class Reader(models.Model): user models.OneToOneField(User, on_deletemodels.CASCADE, verbose_name用户) student_id models.CharField(学号/工号, max_length20, uniqueTrue) name models.CharField(姓名, max_length30) college models.CharField(学院, max_length100, blankTrue) phone models.CharField(联系方式, max_length20, blankTrue) max_borrow models.IntegerField(最大借阅数量, default10) def __str__(self): return self.name class BorrowRecord(models.Model): STATUS_CHOICES ( (pending, 申请中), (borrowed, 已借出), (returned, 已归还), (overdue, 逾期未还), (rejected, 已拒借), ) reader models.ForeignKey(Reader, on_deletemodels.PROTECT, verbose_name读者) book models.ForeignKey(Book, on_deletemodels.PROTECT, verbose_name图书) borrow_date models.DateTimeField(借书时间, nullTrue, blankTrue) due_date models.DateField(应还日期, nullTrue, blankTrue) return_date models.DateTimeField(实际归还时间, nullTrue, blankTrue) status models.CharField(状态, max_length20, choicesSTATUS_CHOICES, defaultpending) created_at models.DateTimeField(申请时间, auto_now_addTrue) class Meta: verbose_name 借阅记录 verbose_name_plural verbose_name ordering [-created_at] def __str__(self): return f{self.reader.name}-{self.book.title}有几个字段设计细节值得你留意。on_deletemodels.PROTECT表示如果有借阅记录关联了某本书那么这本书不允许直接删除这比CASCADE更安全能在一定程度上避免误删导致的数据丢失。ordering [-created_at]让所有借阅记录默认按申请时间倒序显示省得每个视图都写order_by。模型写完以后执行两条命令让Django把数据表创建出来python manage.py makemigrations python manage.py migratemakemigrations会生成一个迁移脚本migrate才会真正执行建表。执行完以后再用python manage.py createsuperuser创建管理员账号就可以先登录Django自带后台体验一下数据录入。3.4 视图函数与URL路由的设计思路以登录为例完成后的流程是用户填写表单后端校验成功后跳转到首页。视图代码我会这样写from django.shortcuts import render, redirect from django.contrib.auth import authenticate, login from django.contrib import messages def login_view(request): if request.method POST: username request.POST.get(username) password request.POST.get(password) user authenticate(request, usernameusername, passwordpassword) if user is not None: login(request, user) return redirect(dashboard) else: messages.error(request, 用户名或密码错误) return render(request, books/login.html)图书检索视图也很常见重点在于关键词搜索和分页from django.core.paginator import Paginator from django.db.models import Q from .models import Book def book_list(request): keyword request.GET.get(keyword, ) books Book.objects.all() if keyword: books books.filter( Q(title__icontainskeyword) | Q(author__icontainskeyword) | Q(isbn__icontainskeyword) ) paginator Paginator(books, 10) # 每页10条 page_number request.GET.get(page) page_obj paginator.get_page(page_number) return render(request, books/book_list.html, {page_obj: page_obj, keyword: keyword})URL路由配置要分层。首页在library_system/urls.py里用include把books应用的urls包含进来from django.contrib import admin from django.urls import path, include urlpatterns [ path(admin/, admin.site.urls), path(, include(books.urls)), ]然后在books/urls.py里定义具体路径from django.urls import path from . import views app_name books urlpatterns [ path(, views.dashboard, namedashboard), path(books/, views.book_list, namebook_list), path(books/int:book_id/, views.book_detail, namebook_detail), path(books/int:book_id/borrow/, views.borrow_book, nameborrow_book), path(records/, views.my_records, namemy_records), path(records/int:record_id/return/, views.return_book, namereturn_book), path(login/, views.login_view, namelogin), path(register/, views.register_view, nameregister), path(logout/, views.logout_view, namelogout), ]这里用到了一个命名空间的技巧app_name books模板里就可以用{% url books:book_list %}来引用URL以后哪怕URL路径改了模板代码也不用动。3.5 前端模板与静态文件组织Django的模板系统直接支持继承我们一般先写一个base.html放公共的导航栏和JS/CSS引用所有页面都继承它。base.html里用{% block content %}{% endblock %}占住位置子模板只需要写{% extends base.html %}然后填充自己的内容。前端我建议用Bootstrap或AdminLTE。Bootstrap适合普通管理系统界面AdminLTE适合带侧边栏的管理后台风格。图书管理系统用AdminLTE做后台、Bootstrap做前台观感会好很多。模板文件放在books/templates/books/目录下静态文件放在books/static/books/目录下。背景知识补充Django默认的模板查找顺序是“每个app的templates目录”静态文件查找顺序是“每个app的static目录”。这也是为什么我们要在app内建这两个目录的原因。模板里引用静态文件{% load static %} link relstylesheet href{% static books/css/bootstrap.min.css %}模板渲染时传参很灵活比如图书详情页def book_detail(request, book_id): book Book.objects.get(idbook_id) return render(request, books/book_detail.html, {book: book})前端模板里就能直接{{ book.title }}、{{ book.author }}这样输出还能用{% if book.available_stock 0 %}判断能否借阅。3.6 借书还书核心业务逻辑实现借书这一步是整个系统最容易写错的地方核心在于“并发安全和业务状态不能乱”。我建议用Django的事务机制把库存扣减和借阅记录创建放在同一个原子块里from django.db import transaction from django.utils import timezone from datetime import timedelta from django.contrib import messages login_required def borrow_book(request, book_id): reader request.user.reader book Book.objects.select_for_update().get(idbook_id) if book.available_stock 1: messages.error(request, 库存不足暂时无法借阅) return redirect(books:book_detail, book_idbook_id) if BorrowRecord.objects.filter(readerreader, status__in[pending, borrowed, overdue]).count() reader.max_borrow: messages.error(request, 已达最大借阅数量) return redirect(books:book_detail, book_idbook_id) with transaction.atomic(): book.available_stock book.available_stock - 1 book.save() record BorrowRecord.objects.create( readerreader, bookbook, borrow_datetimezone.now(), due_datetimezone.now().date() timedelta(days30), statusborrowed, ) return redirect(books:my_records)select_for_update()表示在事务里行锁防止两个人同时借同一本库存只剩1本的书。transaction.atomic()保证如果后面创建记录失败库存扣减也会回滚两边不会出现数据不一致。还书逻辑反着来把状态改成returned写清实际归还时间再把可借库存加回去。这里只改状态不删记录借阅历史才完整后续统计才有据可依。如果借阅记录超过due_date还没归还我建议做一个每日定时任务扫描自动把状态改成overdue。用Django的celery可能有点重了直接用系统的定时任务跑一个manage.py命令行脚本就够了。毕设答辩讲到这个点说明你对真实系统的边界情况有思考是明显的加分项。4. 常见问题与避坑经验实录4.1 虚拟环境与依赖版本冲突现象python manage.py runserver命令执行后提示ModuleNotFoundError: No module named django或者Django版本忽高忽低导致语法兼容问题。原因多半是在激活虚拟环境之前就执行了命令或者pip把包安装到了全局环境而不是虚拟环境。排查方式命令行输入pip list看有没有Django如果没有就说明装了但没装在当前环境。确认命令行前有没有(venv)前缀。执行python -m pip install django用python -m pip可以确保pip对应的是当前Python解释器。另一类高频问题是Pillow相关的因为ImageField需要Pillow库。如果迁移时报错ModuleNotFoundError: No module named PIL执行pip install Pillow即可。4.2 静态文件404新手最容易崩的坑现象模板明明引用了bootstrap.min.css但浏览器控制台报404页面完全没有样式。原因你可能没有在项目根目录的settings.py里配置静态文件路径或者静态文件没放在app的static目录下。解决方式STATIC_URL /static/ STATICFILES_DIRS [ BASE_DIR / static, ]如果放在books/static/books/下模板里用{% load static %} link relstylesheet href{% static books/css/bootstrap.min.css %}部署阶段还需要执行python manage.py collectstatic把静态文件收集到一个统一目录再交给nginx或CDN来处理。4.3 数据库迁移与报错处理makemigrations的时候提示“No changes detected”怎么办八成是app没有注册到INSTALLED_APPS里。还有一种情况是模型已经改过并迁移过没有新增变更所以提示无变化。migrate的时候报django.db.utils.OperationalError: no such table这通常是因为你手动在数据库里删过表但迁移记录还在。最简单的解决方式是删掉数据库文件开发环境重新migrate或者把对应app的迁移记录从django_migrations表里删掉再重新迁移。改字段以后报TypeError: __init__() got an unexpected keyword argument max_length这类报错说明你拼错了字段参数。比如ImageField没有max_lengthTextField不需要指定max_lengthDateField没有defaultnow的写法。4.4 部署阶段的性能与安全问题图书管理系统开发完以后如果不部署到公网只是一个本地项目答辩的含金量会打折扣。部署方案我推荐一条对毕设来说性价比最高的路线DNS服务器域名解析到云服务器服务器上用waitressWindows或gunicornLinux跑Django前面再用nginx做反向代理和静态文件处理。部署时最先要做三件事把DEBUG改成False、配置ALLOWED_HOSTS、收集静态文件。ALLOWED_HOSTS不配置就会出现DisallowedHost报错DEBUGTrue会暴露详细的报错信息这是一个明显安全隐患静态文件不收集页面就是纯HTML没有样式。数据库这块部署到云服务器后尽量把SQLite换成MySQL或PostgreSQL因为SQLite在高并发下会有性能瓶颈。连接信息不能写死在代码里从环境变量读取比较好。密码等敏感信息也不要提交到代码仓库哪怕你是个人项目。4.5 答辩、文案与源码“免费领”的理性提醒最后说一个网上经常看到的“免费领源码”的坑。很多同学看到“免费领源码”就盲目去加好友但你要明白毕设的核心目的是让你掌握技术。就算你拿到了源码不自己跑一遍、不读懂代码逻辑、不亲手改几个功能到了答辩现场评委问两句就会露馅。所以我给的建议是源码可以作为参考但拿到手以后必须做三件事——跑通它、改需求、理解原理。比如源码里用的是SQLite你就改成MySQL源码里的图表类型是柱状图你就改成动态折线图源码里的借阅规则是30天你就加一个续借功能。改过以后这个系统才能说是“你的系统”。答辩PPT也不要只是贴几张截图就完事。至少包含选题背景和意义、技术选型理由、功能架构图、数据库ER图、核心页面截图、测试结果、部署环境。讲演示时按用户角色走流程管理员登录→录入图书→读者注册→检索图书→申请借阅→管理员审核→归还图书→数据统计。整个流程一气呵成评委的体验感会很好。结语这套系统后续还可以怎么扩展如果你把上面的内容全部做完了你的图书管理系统已经能支撑起一个合格甚至优秀的毕业设计。但如果你想在有限时间内再多做一些亮点我给你三个后续扩展方向作为参考。其一微信小程序端。Django写一套JSON接口小程序端调用接口完成图书检索和借阅申请相当于做了一次前后端分离改造。标题里出现小程序这个词说明这也是评委关注的热门方向。其二推荐算法。根据读者的借阅历史用简单的协同过滤算法或“同分类热门图书”来做推荐列表就能展现一定的智能化水平。不用复杂模型用pandas算相似度就行。其三数据可视化大屏。把月度统计、分类占比、阅读排行、用户增长做成一个宽屏大页面放在演示环节开场视觉效果直接拉满。我个人在实际做这类项目时的体会是图书管理系统的技术难点不多真正拉开差距的是细节——库存并发处理、权限控制、数据一致性、异常页面提示、部署运维这些真实工程问题。很多同学习惯把demo做得“能用就行”但如果你愿意在每个环节多想一步为什么这套流程做下来你收获的绝不仅仅是一个毕设分数而是一套完整的Web开发思维。我强烈建议你动手敲一遍哪怕慢一点也不要只做“代码的搬运工”。