1. 系统简介
该实验设计开发一个简单的图书管理数据库系统,包括图书馆内书籍的信息、学校在校师生的信息以及师生的借阅信息。此系统用户面向图书管理员和借阅读者,图书馆管理员可以完成图书、读者等基本信息的增加、删除和修改、查看;读者可以进行图书的借阅、查看、预约等操作。构建基于B/S架构,MySQL数据库为基础,应用Django框架建设过程和方法。本系统主要包含以下基本功能,主要是前台展示和后台管理两部分,其中前台展示包括登陆模块、首页展示、书籍检索、分类查看等。
系统开发技术及工具:Python Django HTML MySQL数据库 Windows11系统 PyCharm
2.2 功能需求描述
图书出借时考虑的问题:
读者是否因为超期、罚款等情况被关闭了借阅权限;
读者是否已经借满其限额。
该书是否不在库中;
如果不存在以上情况,则可以出借。
读者想借的书如果不在库中(已经被出借),读者可以预约该图书
对读者信息进行查看、添加、修改、删除。将读者分为不同类别,赋以不同权限。
对管理员的登录账号、密码进行添加、修改、删除。
对违规信息进行查看、添加、修改、删除。
数据库需要描述的数据信息包括以下几种:
(1)读者信息
(2)书籍信息
(3)管理员信息
(4)读者与书籍之间的关系(借阅关系E-R图)
图书管理系统由三个实体:图书实体,读者实体,管理员实体,图书种类实体组成,共六个表如下:
1、书籍表
属性:图书编号,ISBN,书名,作者,出版社,出版日期,价格,学科类型,藏书类型,总量,余量
主键:图书编号
2、读者表
属性:读者编号,读者姓名,联系电话,邮箱地址,所在系,权限状况
主键:读者编号
3、管理员用户表
属性:编号,账号,密码,姓名
4、借阅表
属性:图书编号,读者编号,借阅日期,应还日期
5、预约信息
属性:编号,图书编号,读者编号,预约日期
6、违规表
属性:编号,读者编号,图书编号,逾期(0/1),破坏书籍(0/1)
1、图书实体E-R图
图书具有图书编号,ISBN,书名,作者,出版社,出版日期,价格,总量,余量等九个属性,便于读者在使用图书馆管理系统时,更加准确的定位到所选图书的位置,了解图书的信息。也可以方便读者利用碎片化的信息,从大量的图书中筛选自己可能心仪图书。
2、图书馆管理员实体E-R图
图书管理员实体具有编号,账号,密码,姓名,联系方式
3、读者实体E-R图
读者具有读者编号,读者姓名,联系电话,邮箱地址,备注,便于图书管理员及时的维护管理借阅系统,明确每一本图书的去向,对与图书馆图书的情况有一个把握。维护图书管理系统的正常运行。
4、总体E-R图
在图书管理系统中,一名读者可以借阅多本图书,多名图书管理员同时管理多本图书,一名读书管理员可以同时管理多名读者。通过实体之间的相互联系,构成了图书管理系统的总体E-R图。
1、读者表(reader)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
编号 |
|
reader_id |
int |
11 |
学号 |
|
password |
char |
20 |
密码 |
|
name |
char |
10 |
读者姓名 |
|
telephone |
char |
15 |
联系电话 |
|
|
char |
30 |
邮箱地址 |
|
dept |
char |
20 |
所在院系 |
|
right |
int |
1 |
借阅权限(0或1) |
2、图书表(book)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
编号 |
|
bookname |
char |
20 |
书籍名称 |
|
author |
char |
20 |
书籍作者 |
|
pubdate |
date |
出版日期 |
||
publish |
char |
30 |
出版社 |
|
price |
decimal |
7,2 |
非空 |
价格 |
ISBN |
char |
17 |
非空 |
书籍ISBN码 |
bookclass |
int |
11 |
外键 |
学科类型 |
total |
int |
非空 |
总量 |
|
margin |
int |
非空 |
余量 |
|
booktype |
int |
11 |
外键 |
藏书类型 |
列名 |
类型 |
长度 |
约束 |
备注 |
id |
Int |
主键 |
|
|
usernum |
Char |
20 |
|
|
password |
Char |
11 |
|
|
username |
char |
10 |
管理员姓名 |
4.借阅表(borrow)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
借阅编号 |
|
readerid |
int |
读者编号 |
||
bookid |
int |
图书编号 |
||
borrowdate |
date |
出借日期 |
||
due |
date |
应还日期 |
5.预约表(preconcert)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
预约编号 |
|
readerid |
int |
读者编号 |
||
bookid |
int |
图书编号 |
||
predate |
date |
预约日期 |
6.违规表(break_rule)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
违规编号 |
|
reader_id |
int |
读者编号 |
||
book_id |
int |
图书编号 |
||
verdue |
int |
逾期(0或1) |
||
destory |
int |
破坏书籍(0或1) |
1、读者表(reader)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
编号 |
|
reader_id |
int |
11 |
学号 |
|
password |
char |
20 |
密码 |
|
name |
char |
10 |
读者姓名 |
|
telephone |
char |
15 |
联系电话 |
|
|
char |
30 |
邮箱地址 |
|
dept |
char |
20 |
所在院系 |
|
right |
int |
1 |
借阅权限(0或1) |
2、图书表(book)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
编号 |
|
bookname |
char |
20 |
书籍名称 |
|
author |
char |
20 |
书籍作者 |
|
pubdate |
date |
出版日期 |
||
publish |
char |
30 |
出版社 |
|
price |
decimal |
7,2 |
非空 |
价格 |
ISBN |
char |
17 |
非空 |
书籍ISBN码 |
bookclass |
int |
11 |
外键 |
学科类型 |
total |
int |
非空 |
总量 |
|
margin |
int |
非空 |
余量 |
|
booktype |
int |
11 |
外键 |
藏书类型 |
列名 |
类型 |
长度 |
约束 |
备注 |
id |
Int |
主键 |
|
|
usernum |
Char |
20 |
|
|
password |
Char |
11 |
|
|
username |
char |
10 |
管理员姓名 |
4.借阅表(borrow)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
借阅编号 |
|
readerid |
int |
读者编号 |
||
bookid |
int |
图书编号 |
||
borrowdate |
date |
出借日期 |
||
due |
date |
应还日期 |
5.预约表(preconcert)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
预约编号 |
|
readerid |
int |
读者编号 |
||
bookid |
int |
图书编号 |
||
predate |
date |
预约日期 |
6.违规表(break_rule)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
违规编号 |
|
reader_id |
int |
读者编号 |
||
book_id |
int |
图书编号 |
||
verdue |
int |
逾期(0或1) |
||
destory |
int |
破坏书籍(0或1) |
1、读者表(reader)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
编号 |
|
reader_id |
int |
11 |
学号 |
|
password |
char |
20 |
密码 |
|
name |
char |
10 |
读者姓名 |
|
telephone |
char |
15 |
联系电话 |
|
|
char |
30 |
邮箱地址 |
|
dept |
char |
20 |
所在院系 |
|
right |
int |
1 |
借阅权限(0或1) |
2、图书表(book)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
编号 |
|
bookname |
char |
20 |
书籍名称 |
|
author |
char |
20 |
书籍作者 |
|
pubdate |
date |
出版日期 |
||
publish |
char |
30 |
出版社 |
|
price |
decimal |
7,2 |
非空 |
价格 |
ISBN |
char |
17 |
非空 |
书籍ISBN码 |
bookclass |
int |
11 |
外键 |
学科类型 |
total |
int |
非空 |
总量 |
|
margin |
int |
非空 |
余量 |
|
booktype |
int |
11 |
外键 |
藏书类型 |
列名 |
类型 |
长度 |
约束 |
备注 |
id |
Int |
主键 |
|
|
usernum |
Char |
20 |
|
|
password |
Char |
11 |
|
|
username |
char |
10 |
管理员姓名 |
4.借阅表(borrow)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
借阅编号 |
|
readerid |
int |
读者编号 |
||
bookid |
int |
图书编号 |
||
borrowdate |
date |
出借日期 |
||
due |
date |
应还日期 |
5.预约表(preconcert)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
预约编号 |
|
readerid |
int |
读者编号 |
||
bookid |
int |
图书编号 |
||
predate |
date |
预约日期 |
6.违规表(break_rule)
列名 |
类型 |
长度 |
约束 |
备注 |
id |
int |
主键 |
违规编号 |
|
reader_id |
int |
读者编号 |
||
book_id |
int |
图书编号 |
||
verdue |
int |
逾期(0或1) |
||
destory |
int |
破坏书籍(0或1) |
选择Pycharm工具进行本次项目的制作
目录说明:
manage.py:一个命令行工具,可以说Django项目就是从这个文件开始执行的。
_init _.py:一个空文件,表示mytest应该被看做一个python包;
settings.py:整个项目的配置参数文件;
urls.py:项目的URL声明,一般项目的顶级url正则匹配放置在这里;
wsgi.py:项目与WSGI兼容的Web服务器入口;
2.创建应用
(1)项目创建完成后需要有具体的应用
(2)创建后生成目录:
admin.py: 模型注册和后台管理相关的文件;
_init_.py: 应用应该被看做一个Python包;
migrations: 用来放置应用模型的迁移脚本文件;
models.py: 定义模型;
test.py: 放置项目的测试文件;
viems.py: 定义视图;
(3)添加应用
打开settings.py,INSTALLED_APPS下添加:'app01'
在settings.py下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'BookSystem',
'USER':'root',
'PASSWORD':'root',
'HOST':'localhost',
'POST':3306,
}
}
另外django连接mysql需要pymysql包的支持,所以先安装pymysql:
在终端:pip install pymysql
安装完毕,需要导入到django中,打开应用_init_.py文件,加入代码:
import pymysql
pymysql.install_as_MySQLdb() # 与mysql交互的函数
4.相关代码展示
4.1. urls层
#读者
path("reader/search/", views.reader_search),
path("reader/classify/", views.reader_classify2),
path("reader//classify/", views.reader_classify),
path("reader/order/", views.reader_order),
path("reader/borrow/",views.reader_borrow),
path("reader/first/", views.reader_first),
path("reader/rule/", views.reader_rule),
path("popular/book/", views.popular_book),
#管理员
#图书管理
path("book/list/",views.book_list),
path("book/add/",views.book_add),
path("book//edit/",views.book_edit),
path("book//delete/", views.book_delete),
#用户管理
path("user/list/", views.user_list),
path("user/add/",views.user_add),
path("user//edit/",views.user_edit),
path("user//delete/", views.user_delete),
#管理管理员
path("admin/list/", views.admin_list),
path("admin/add/",views.admin_add),
path("admin//edit/",views.admin_edit),
path("admin//delete/", views.admin_delete),
#违规
path("rule/list/", views.rule_list),
path("rule/add/",views.rule_add),
path("rule//edit/",views.rule_edit),
path("rule//delete/", views.rule_delete),
#登录
path("login/",views.login),
path("log/", views.log)
4.2.models层
class reader(models.Model):
""""读者表"""
reader_id=models.IntegerField(verbose_name="学号")
password=models.CharField(verbose_name="密码",max_length=20)
name=models.CharField(verbose_name="读者姓名",max_length=10)
telephone=models.CharField(verbose_name="联系电话",max_length=15)
email=models.CharField(verbose_name="邮箱地址",max_length=30)
dept=models.CharField(verbose_name="所在院系",max_length=20)
right=models.IntegerField(verbose_name="借阅权限(0或1)")
class book(models.Model):
""""图书表"""
bookname=models.CharField(verbose_name="书籍名称",max_length=20)
author=models.CharField(verbose_name="书籍作者",max_length=20)
pubdate=models.DateField(verbose_name="出版日期")
publish=models.CharField(verbose_name="出版社",max_length=30)
price = models.DecimalField(verbose_name="价格", max_digits=7, decimal_places=2, default=0)
ISBN=models.CharField(verbose_name="书籍ISBN码",max_length=17)
bookclass_choices=(
(1,"哲学、宗教"),
(2,"社会科学总论"),
(3,"政治、法律"),
(4,"军事"),
(5,"经济"),
)
bookclass=models.IntegerField(verbose_name="学科类型",choices=bookclass_choices)
total=models.IntegerField(verbose_name="总量")
margin=models.IntegerField(verbose_name="余量")
booktype_choices=(
(1,"图书"),
(2,"期刊")
)
booktype=models.IntegerField(verbose_name="藏书类型",choices=booktype_choices)
class admin(models.Model):
""""管理员用户表"""
usernum=models.CharField(verbose_name="管理员账号",max_length=20)
password=models.CharField(verbose_name="账号密码",max_length=11)
username=models.CharField(verbose_name="管理员姓名",max_length=10)
class borrow(models.Model):
""""借阅表"""
readerid=models.IntegerField(verbose_name="读者编号")
bookid=models.IntegerField(verbose_name="图书编号")
borrowdate=models.DateField(verbose_name="出借日期")
due=models.DateField(verbose_name="应还日期")
class preconcert(models.Model):
""""预约表"""
readerid = models.IntegerField(verbose_name="读者编号")
bookid = models.IntegerField(verbose_name="图书编号")
predate = models.DateField(verbose_name="预约日期")
class break_rule(models.Model):
""""违规表"""
readerid=models.IntegerField(verbose_name="读者编号")
bookid=models.IntegerField(verbose_name="图书编号")
overdue_choices = (
(0, "无"),
(1, "逾期")
)
overdue=models.IntegerField(verbose_name="逾期(0/1)",choices=overdue_choices)
destory_choices = (
(0, "无"),
(1, "损坏")
)
destory=models.IntegerField(verbose_name="破坏书籍(0/1)",choices=destory_choices)
4.3.views层
# ###############################管理员###################################
#管理图书
def book_list(request):
b = models.book.objects.all()
return render(request, 'book_list.html', {'b': b})
class BookAdd(forms.ModelForm):
class Meta:
model=models.book
fields=["bookname","author","pubdate","publish","ISBN","price","bookclass","total","margin","booktype"]
# widgets={
# "bookname":forms.TextInput(attrs={"class":"form-control"})
# }
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加class=“form——control”
for name, field in self.fields.items():
# if name=="password":
# continue
field.widget.attrs = {"class": "form-control"}
def book_add(request):
if request.method == "GET":
bookadd = BookAdd()
return render(request, 'book_add.html', {'bookadd': bookadd})
#用户POST提交数据,数据校验
bookadd=BookAdd(data=request.POST)
if bookadd.is_valid():
#如果数据合法,保存到数据库
bookadd.save()
return redirect('/book/list/')
#校验失败
return render(request, 'book_add.html', {'bookadd': bookadd})
def book_edit(request,nid):
""""编辑书籍"""
row_object = models.book.objects.filter(id=nid).first()
if request.method == "GET":
# 根据id去数据库获取要编辑的那一行数据
bookadd = BookAdd(instance=row_object)
return render(request, "book_edit.html", {'bookadd': bookadd})
bookadd=BookAdd(data=request.POST,instance=row_object)
if bookadd.is_valid():
# 如果数据合法,保存到数据库
bookadd.save()
return redirect('/book/list/')
return render(request, "book_edit.html", {'bookadd': bookadd})
def book_delete(request,nid):
""""删除图书"""
models.book.objects.filter(id=nid).delete()
return redirect('/book/list/')
#管理用户
def user_list(request):
b = models.reader.objects.all()
return render(request, 'user_list.html', {'b': b})
class User(forms.ModelForm):
class Meta:
model=models.reader
fields=["reader_id","password","name","telephone","email","dept","right"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加class=“form——control”
for name, field in self.fields.items():
# if name=="password":
# continue
field.widget.attrs = {"class": "form-control"}
def user_add(request):
if request.method == "GET":
user=User()
return render(request, 'user_add.html', {'user': user})
#用户POST提交数据,数据校验
user=User(data=request.POST)
if user.is_valid():
#如果数据合法,保存到数据库
user.save()
return redirect('/user/list/')
#校验失败
return render(request, 'user_add.html', {'user': user})
def user_edit(request,nid):
""""编辑用户"""
row_object = models.reader.objects.filter(id=nid).first()
if request.method == "GET":
# 根据id去数据库获取要编辑的那一行数据
user = User(instance=row_object)
return render(request, "user_edit.html", {'user': user})
user=User(data=request.POST,instance=row_object)
if user.is_valid():
# 如果数据合法,保存到数据库
user.save()
return redirect('/user/list/')
return render(request, "user_edit.html", {'user': user})
def user_delete(request,nid):
""""删除用户"""
models.reader.objects.filter(id=nid).delete()
return redirect('/user/list/')
#管理管理员
def admin_list(request):
b = models.admin.objects.all()
return render(request, 'admin_list.html', {'b': b})
class Admin(forms.ModelForm):
class Meta:
model=models.admin
fields=["usernum","password","username"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加class=“form——control”
for name, field in self.fields.items():
# if name=="password":
# continue
field.widget.attrs = {"class": "form-control"}
def admin_add(request):
if request.method == "GET":
admin=Admin()
return render(request, 'admin_add.html', {'admin': admin})
#用户POST提交数据,数据校验
admin=Admin(data=request.POST)
if admin.is_valid():
#如果数据合法,保存到数据库
admin.save()
return redirect('/admin/list/')
#校验失败
return render(request, 'admin_add.html', {'admin': admin})
def admin_edit(request,nid):
""""编辑管理员"""
row_object = models.admin.objects.filter(id=nid).first()
if request.method == "GET":
# 根据id去数据库获取要编辑的那一行数据
admin =Admin(instance=row_object)
return render(request, "admin_edit.html", {'admin': admin})
admin=Admin(data=request.POST,instance=row_object)
if admin.is_valid():
# 如果数据合法,保存到数据库
admin.save()
return redirect('/admin/list/')
return render(request, "admin_edit.html", {'admin': admin})
def admin_delete(request,nid):
""""删除管理员"""
models.admin.objects.filter(id=nid).delete()
return redirect('/admin/list/')
#违规
def rule_list(request):
b = models.break_rule.objects.all()
return render(request, 'rule_list.html', {'b': b})
class Rule(forms.ModelForm):
class Meta:
model=models.break_rule
fields=["readerid","bookid","overdue","destory"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加class=“form——control”
for name, field in self.fields.items():
# if name=="password":
# continue
field.widget.attrs = {"class": "form-control"}
def rule_add(request):
if request.method == "GET":
rule=Rule()
return render(request, 'rule_add.html', {'rule': rule})
#用户POST提交数据,数据校验
rule=Rule(data=request.POST)
if rule.is_valid():
#如果数据合法,保存到数据库
rule.save()
return redirect('/rule/list/')
#校验失败
return render(request, 'rule_add.html', {'rule': rule})
def rule_edit(request,nid):
""""编辑管理员"""
row_object = models.break_rule.objects.filter(id=nid).first()
if request.method == "GET":
# 根据id去数据库获取要编辑的那一行数据
rule=Rule(instance=row_object)
return render(request, "rule_edit.html", {'rule': rule})
rule=Rule(data=request.POST,instance=row_object)
if rule.is_valid():
# 如果数据合法,保存到数据库
rule.save()
return redirect('/rule/list/')
return render(request, "rule_edit.html", {'rule': rule})
def rule_delete(request,nid):
""""删除管理员"""
models.break_rule.objects.filter(id=nid).delete()
return redirect('/rule/list/')
# ###############################登录#############################################
""""用户登录"""
class LoginForm(forms.Form):
reader_id=forms.CharField(
label="学号",
widget=forms.TextInput,
required=True
)
password=forms.CharField(
label="密码",
widget=forms.PasswordInput,
required=True
)
def clean_password(self):
password = self.cleaned_data.get("password")
return md5(password)
def login(request):
if request.method=="GET":
form = LoginForm()
return render(request, 'login.html', {'form': form})
form=LoginForm(data=request.POST)
if form.is_valid():
#去数据库校验用户名和密码是否正确,获取用户对象
admin_object=models.reader.objects.filter(reader_id=request.POST.get('reader_id'),password=request.POST.get('password')).first()
if not admin_object:
form.add_error("password","用户名或密码错误!")
return render(request,'login.html',{'form':form})
#网站生成随机字符串
request.session["info"]={'reader_id':admin_object.reader_id,'password':admin_object.password}
return redirect('/reader/first/')
return render(request,'login.html',{'form':form})
"""""管理员登录"""
class LogForm(forms.Form):
usernum=forms.CharField(
label="管理员账号",
widget=forms.TextInput,
required=True
)
password=forms.CharField(
label="密码",
widget=forms.PasswordInput,
required=True
)
def clean_password(self):
password = self.cleaned_data.get("password")
return md5(password)
def log(request):
if request.method=="GET":
form = LogForm()
return render(request, 'log.html', {'form': form})
form=LogForm(data=request.POST)
if form.is_valid():
#去数据库校验用户名和密码是否正确,获取用户对象
admin_object=models.admin.objects.filter(usernum=request.POST.get('usernum'),password=request.POST.get('password')).first()
if not admin_object:
form.add_error("password","用户名或密码错误!")
return render(request,'log.html',{'form':form})
#网站生成随机字符串
request.session["info"]={'usernum':admin_object.usernum,'password':admin_object.password}
return redirect('/book/list/')
return render(request,'log.html',{'form':form})