基于flask与数据库的图书管理系统开发

基于flask与数据库的图书管理系统开发

一、开发环境简介

该图书管理系统基于python语言,利用splite3小型数据库,结合sql数据库存储的数据,通过Visual Studio Code编辑器,在flask框架下调用style.css样式,创建网页模板。 在创建数据库表后,利用flask中的辅助方法,完成对数据库的连接,初始化,插入,删除,和查询等操作。与此同时,利用视图函数和网页模板相连接,实现对网页页面的连接操作。

基于flask与数据库的图书管理系统开发

二、系统实现功能模块图

a.注册模块
在此模块下的用户通过提示信息进行注册,在完成用户名以及密码设置后即可登陆系统,后期学院以及学号、邮箱信息可以通过个人或者管理员登陆进行修改,进而使用本系统进行后续的操作。
b.登陆模块
在此模块下设置了不同的权限管理,通过选择不同的登陆方式从而进入不同的环境,如用户登陆以及管理员登陆,对应可以完成不同的操作与功能。
c.管理员模块
如若选择的是管理员身份进行操作,可以在系统中有查看、添加、删除、修改图书信息,也可以对用户信息进行查看,实现修改信息和注销用户,同时在读者还书后实时更新图书归还状态。
d.用户模块
如若选择是用户登陆,可以进行个人信息修改、完善,同时也可以查阅图书信息,依据书名以及作者信息进行检索图书,借阅图书,同时查看自己的阅读记录。

基于flask与数据库的图书管理系统开发

三、代码设计实现

import time
from datetime import datetime
#日期相关操作,和time包连用表示、计算借还书日期

from sqlite3 import dbapi2 as sqlite3
#使用SQLite时,它的功能直接被集成在其中,应用会直接访问包含数据的文件,
#SQLITE功能简约,小型化,追求最大磁盘效率;MYSQL功能全面,综合化,追求最大并发效率。如果只是单机上用的,数据量不是很大,
# 需要方便移植或者需要频繁读/写磁盘文件的话,就用SQLite比较合适;如果是要满足多用户同时访问,或者是网站访问量比较大是使用MYSQL比较合适.

from flask import Flask, request, session, url_for, redirect, render_template, abort, g, flash, _app_ctx_stack

from hashlib import md5
#这是加密函数,将传进来的函数加密
from werkzeug import check_password_hash, generate_password_hash
#数据库中直接存放明文密码是很危险的,Werkzeug库中的security能够方便的实现散列密码的计算
#security库中 generate_password_hash(password,method...)函数将原始密码作为输入,以字符串形式输出密码的散列值
#check_password_hash(hash,password)函数检查给出的hash密码与明文密码是否相符

#CONFIGURATION
DATABASE = 'book.db'
DEBUG = True
SECRET_KEY = 'development key'
MANAGER_NAME = 'admin'
MANAGER_PWD = '123456'

# create our little application :
app = Flask(__name__)  #app是Flask的实例,它接收包或者模块的名字作为参数
app.config.from_object(__name__)

#设置一个名为 FLASKR_SETTINGS 环境变量来设定一个配置文件载入后是否覆盖默认值。
#静默开关告诉 Flask 不去关心这个环境变量键值是否存在。
app.config.from_envvar('FLASKR_SETTINGS', silent=True)

#数据库连接
def get_db():
	top = _app_ctx_stack.top
	#判断top中是否有sqlite_db , 如果top中不包含sqlite_db属性,通过SQLite创建一个简单的数据库连接并通过sqlite.Row对象来表示行。这样就可以将行看作是字典而不是元组。
	if not hasattr(top, 'sqlite_db'):        
		top.sqlite_db = sqlite3.connect(app.config['DATABASE'])
		top.sqlite_db.row_factory = sqlite3.Row  
	return top.sqlite_db

#这个装饰器的作用就是向请求上下文中注册一个函数,当上下文销毁时调用,实际上是一次请求完成后执行
@app.teardown_appcontext   
def close_database(exception):
	top = _app_ctx_stack.top
	#如果top中包含sqlite_db属性,则关闭数据库
	if hasattr(top, 'sqlite_db'):
		top.sqlite_db.close()

#初始化数据库
def init_db():
	with app.app_context():
		db = get_db()
		with app.open_resource('book.sql', mode='r') as f:
			db.cursor().executescript(f.read())
		db.commit()

#访问数据库
def query_db(query, args=(), one=False):
	cur = get_db().execute(query, args)
	rv = cur.fetchall()
	return (rv[0] if rv else None) if one else rv

#通过用户名(设置唯一,不可重名)给读者id
def get_user_id(username):
	rv = query_db('select user_id from users where user_name = ?', [username], one=True)
	return rv[0] if rv else None


@app.before_request    #此装饰函数会在请求前调用,它没有参 数
def before_request():
	g.user = None
	if 'user_id' in session:
		g.user = session['user_id']

@app.route('/')   #在本地服务器上运行网页主页文件
def index():
	return render_template('index.html')

@app.route('/manager_login', methods=['GET', 'POST'])  #运行manager_login网页文件,方法为POST , GET
def manager_login():    #管理员登陆
	error = None
	#判断输入的管理员账号和密码是否正确
	if request.method == 'POST':
		if request.form['username'] != app.config['MANAGER_NAME']:
			error = 'Invalid username'
		elif request.form['password'] != app.config['MANAGER_PWD']:
			error = 'Invalid password'
		else:
			session['user_id'] = app.config['MANAGER_NAME']
			return redirect(url_for('manager'))
	return render_template('manager_login.html', error = error)

#读者登录
@app.route('/reader_login', methods=['GET', 'POST'])
def reader_login():
	error = None
	if request.method == 'POST':
		user = query_db('''select * from users where user_name = ?''',  #在服务器中查询所输入的名称
				[request.form['username']], one=True)
		if user is None:    #判断用户名是否为空
			error = 'Invalid username'
		elif not check_password_hash(user['pwd'], request.form['password']):    #判断密码是否正确
			error = 'Invalid password'
		else:     
			session['user_id'] = user['user_name']
			return redirect(url_for('reader'))    #跳转到读者登陆后的页面
	return render_template('reader_login.html', error = error)   

#读者注册
@app.route('/register', methods=['GET', 'POST'])
def register():
	error = None
	if request.method == 'POST':
		if not request.form['username']:      #用户名为空时则提示
			error = 'You have to enter a username'
		elif not request.form['password']:     #提示填写密码
			error = 'You have to enter a password'
		elif request.form['password'] != request.form['password2']:     #提示两次输入的密码不同
			error = 'The two passwords do not match'
		elif get_user_id(request.form['username']) is not None:    #提示用户名已被注册
			error = 'The username is already taken'
		else:
			db = get_db()
			db.execute('''insert into users (user_name, pwd, college, num, email) \
				values (?, ?, ?, ?, ?) ''', [request.form['username'], generate_password_hash(
				request.form['password']), request.form['college'], request.form['number'],
								 request.form['email']])
			db.commit()     #将至册信息保存数据库
			return redirect(url_for('reader_login'))    #跳转到用户登陆后界面
	return render_template('register.html', error = error)

#注销登录
@app.route('/logout')
def logout():
	session.pop('user_id', None)     
	return redirect(url_for('index'))      #跳转到主页
# 添加简单的安全性检查
def manager_judge():
	if not session['user_id']:         #若管理员名称输入错误,则返回登陆页面并提示重新登陆
		error = 'Invalid manager, please login'
		return render_template('manager_login.html', error = error)

def reader_judge():       #用户名输入错误则提示
	if not session['user_id']:       
		error = 'Invalid reader, please login'
		return render_template('reader_login.html', error = error)

def user_judge():
	if not session['user_id']:
		error = 'Invalid user'
		return render_template('manager_userinfo.html', error = error)

#显示图书管理界面,显示数据库图书信息
@app.route('/manager/books')
def manager_books():
	manager_judge()
	return render_template('manager_books.html',        #
			books = query_db('select * from books', []))        #返回到图书管理界面并列出所有图书信息

#显示管理员登录后界面
@app.route('/manager')
def manager():
	manager_judge()     #判断登陆信息,若正确则跳转页面
	return render_template('manager.html')

#显示读者登录后界面
@app.route('/reader')
def reader():
	reader_judge()     #判断登陆信息,若正确则跳转页面
	return render_template('reader.html')

#显示用户管理界面,显示数据库用户信息
@app.route('/manager/users')
def manager_users():
	manager_judge()
	users = query_db('''select * from users''', [])
	return render_template('manager_users.html', users = users)

#用户信息修改
@app.route('/manager/user/modify/<id>', methods=['GET', 'POST'])
def manger_user_modify(id):
	user_judge()     #验证用户信息
	error = None
	user = query_db('''select * from users where user_id = ?''', [id], one=True)    #显示用户个人信息
	if request.method == 'POST':
		if not request.form['username']:
			error = 'You have to input your name'
		elif not request.form['password']:                      #如果密码填写为空,则不修改密码
			db = get_db()
			db.execute('''update users set user_name=?, college=?, num=? \
				, email=? where user_id=? ''', [request.form['username'],
				request.form['college'], request.form['number'],
				request.form['email'], id])
			db.commit()
			return redirect(url_for('manager_user', id = id))
		else:
			db = get_db()                 #这里填写了密码所以修改了密码
			db.execute('''update users set user_name=?, pwd=?, college=?, num=? \
				, email=? where user_id=? ''', [request.form['username'],
					generate_password_hash(request.form['password']),
				request.form['college'], request.form['number'],
				request.form['email'], id])
			db.commit()
			return redirect(url_for('manager_user', id = id))
	return render_template('manager_user_modify.html', user=user, error = error)

#管理员注销用户
@app.route('/manager/user/deleter/<id>', methods=['GET', 'POST'])
def manger_user_delete(id):
	manager_judge()
	db = get_db()
	db.execute('''delete from users where user_id=? ''', [id])      #删除所填入的id的用户信息
	db.commit()
	return redirect(url_for('manager_users'))         #跳转到管理用户界面

#管理员添加书籍
@app.route('/manager/books/add', methods=['GET', 'POST'])
def manager_books_add():
	manager_judge()
	error = None
	if request.method == 'POST':
		
		#若管理员输入的信息有缺少则提示输入相应的信息
		if not request.form['id']:                
			error = 'You have to input the book ISBN'
		elif not request.form['name']:
			error = 'You have to input the book name'
		elif not request.form['author']:
			error = 'You have to input the book author'
		elif not request.form['company']:
			error = 'You have to input the publish company'
		elif not request.form['date']:
			error = 'You have to input the publish date'
		else:           #正确输入信息,则对信息进行保存
			db = get_db()
			db.execute('''insert into books (book_id, book_name, author, publish_com,
				publish_date) values (?, ?, ?, ?, ?) ''', [request.form['id'],
					request.form['name'], request.form['author'], request.form['company'],
				request.form['date']])
			db.commit()
			return redirect(url_for('manager_books'))
	return render_template('manager_books_add.html', error = error)

#管理员删除书籍
@app.route('/manager/books/delete', methods=['GET', 'POST'])
def manager_books_delete():
	manager_judge()
	error = None
	if request.method == 'POST':
		if not request.form['id']:
			error = 'You have to input the book name'
		else:
			book = query_db('''select * from books where book_id = ?''',       #检索相应id的书籍
				[request.form['id']], one=True)
			if book is None:               #若书籍不存在则报错
				error = 'Invalid book id'
			else:
				db = get_db()
				db.execute('''delete from books where book_id=? ''', [request.form['id']])      #若存在此书籍,此语句删除本书
				db.commit()
				return redirect(url_for('manager_books'))
	return render_template('manager_books_delete.html', error = error)


@app.route('/manager/book/<id>', methods=['GET', 'POST'])
def manager_book(id):
	manager_judge()
	book = query_db('''select * from books where book_id = ?''', [id], one=True)
	reader = query_db('''select * from borrows where book_id = ?''', [id], one=True)
	name = query_db('''select user_name from borrows where book_id = ?''', [id], one=True)     #通过输入的书籍id,检索到书籍信息,借阅信息以及借阅者姓名

	current_time = time.strftime('%Y-%m-%d',time.localtime(time.time()))
	if request.method == 'POST':        #管理员在系统中将书籍归还操作
		db = get_db()
		db.execute('''update histroys set status = ?, date_return = ?  where book_id=?
			and user_name=? and status=? ''',
			   ['returned', current_time, id, name[0], 'not return'])
		db.execute('''delete from borrows where book_id = ? ''' , [id])    #将此书从借阅表中删除
		db.commit()
		return redirect(url_for('manager_book', id = id))
	return render_template('manager_book.html', book = book, reader = reader)        #显示网页并将书籍信息及读者显示出来

@app.route('/manager/user/<id>', methods=['GET', 'POST'])
def manager_user(id):
	manager_judge()
	user = query_db('''select * from users where user_id = ?''', [id], one=True)   #通过id查看用户
	books = None
	return render_template('manager_userinfo.html', user = user, books = books)        #显示信息

#管理员修改图书信息
@app.route('/manager/modify/<id>', methods=['GET', 'POST'])
def manager_modify(id):
	manager_judge()
	error = None
	book = query_db('''select * from books where book_id = ?''', [id], one=True)     #通过id检索书籍
	if request.method == 'POST':           #提示填入相应信息
		if not request.form['name']:
			error = 'You have to input the book name'
		elif not request.form['author']:
			error = 'You have to input the book author'
		elif not request.form['company']:
			error = 'You have to input the publish company'
		elif not request.form['date']:
			error = 'You have to input the publish date'
		else:
			db = get_db()
			
			#修改信息
			db.execute('''update books set book_name=?, author=?, publish_com=?, publish_date=? where book_id=? ''', [request.form['name'], request.form['author'], request.form['company'], request.form['date'], id])
			db.commit()
			return redirect(url_for('manager_book', id = id))
	return render_template('manager_modify.html', book = book, error = error)


#个人主页用户信息
@app.route('/reader/info', methods=['GET', 'POST'])
def reader_info():
	reader_judge()
	user = query_db('''select * from users where user_name=? ''', [g.user], one = True)       #查询用户信息
	return render_template('reader_info.html', user = user)       #返回到学生信息网页

#读者信息修改
@app.route('/reader/modify', methods=['GET', 'POST'])
def reader_modify():
	reader_judge()
	error = None
	user = query_db('''select * from users where user_name = ?''', [g.user], one=True)      #将查询到的个人信息存在列表中
	id = user[0]           #取出id信息
	if request.method == 'POST':
		if not request.form['username']:
			error = 'You have to input your name'
		elif not request.form['password']:              #未填入密码则不修改密码
			db = get_db()
			db.execute('''update users set user_name=?, college=?, num=? \
				, email=? where user_id=? ''', [request.form['username'],
				request.form['college'], request.form['number'],
				request.form['email'], id])
			db.commit()
			return redirect(url_for('reader_info'))
		else:                                                       #填入密码则修改密码
			db = get_db()
			db.execute('''update users set user_name=?, pwd=?, college=?, num=? \
				, email=? where user_id=? ''', [request.form['username'],
					generate_password_hash(request.form['password']),
				request.form['college'], request.form['number'],
				request.form['email'], id])
			db.commit()
			return redirect(url_for('reader_info'))              #跳转到修改后的读者信息网页
	return render_template('reader_modify.html', user=user, error = error)        


#用户查询书籍
@app.route('/reader/query', methods=['GET', 'POST'])
def reader_query():
	reader_judge()
	error = None
	books = None
	if request.method == 'POST':
		if request.form['item'] == 'name':       #选择以书名的方式进行查询
			if not request.form['query']:
				error = 'You have to input the book name'
			else:
				books = query_db('''select * from books where book_name = ?''',
						[request.form['query']])
				if not books:
					error = 'Invalid book name'
		else:                                    #以作者方式进行查询
			if not request.form['query']:
				error = 'You have to input the book author'
			else:
				books = query_db('''select * from books where author = ?''',
						[request.form['query']])
				if not books:
					error = 'Invalid book author'
	return render_template('reader_query.html', books = books, error = error)

#读者查询书籍并进行借阅
@app.route('/reader/book/<id>', methods=['GET', 'POST'])
def reader_book(id):
	reader_judge()
	error = None
	  #通过id检索到借阅信息,书籍信息
	book = query_db('''select * from books where book_id = ?''', [id], one=True)
	reader = query_db('''select * from borrows where book_id = ?''', [id], one=True)
	count  = query_db('''select count(book_id) from borrows where user_name = ? ''',              #计算某用户所借阅书籍数量
			  [g.user], one = True)

	current_time = time.strftime('%Y-%m-%d',time.localtime(time.time()))
	return_time = time.strftime('%Y-%m-%d',time.localtime(time.time() + 2600000))
	#以秒为单位,最后还书期限为30天(2600000s),格式%Y-%m-%d(2016-13-2if request.method == 'POST':
		if reader:                 #此处表示本书已有人借阅
			error = 'The book has already borrowed.'
		else:
			if count[0] == 3:            #所借阅数达到三本,则提示不能借阅
				error = 'You can\'t borrow more than three books.'
			else:
				db = get_db()
				db.execute('''insert into borrows (user_name, book_id, date_borrow, \
					date_return) values (?, ?, ?, ?) ''', [g.user, id,
										   current_time, return_time])             #将读者信息加入到借阅表中
				db.execute('''insert into histroys (user_name, book_id, date_borrow, \
					status) values (?, ?, ?, ?) ''', [g.user, id,
										   current_time, 'not return'])              #将读者信息加入到历史纪录表中
				db.commit()
				return redirect(url_for('reader_book', id = id))
	return render_template('reader_book.html', book = book, reader = reader, error = error)

#查看阅读记录
@app.route('/reader/histroy', methods=['GET', 'POST'])
def reader_histroy():
	reader_judge()
	histroys = query_db('''select * from histroys, books where histroys.book_id = books.book_id and histroys.user_name=? ''', [g.user], one = False)            #查询历史纪录

	return render_template('reader_histroy.html', histroys = histroys)

if __name__ == '__main__':
	init_db()
	app.run(debug=True)

附:全部代码已经上传至GitHub