Using mysql and php to implement the Leasing Luxury Database system
界面效果
模板源自Appseed 的 Datta Able Django
GitHub地址:https://github.com/Misaka-9982-coder/Django_db_crud
如果喜欢这个项目的话,欢迎为我的GitHub仓库点个star,你的支持是对我最大的鼓励~
如何运行
setting.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '数据库名称',
'USER': '用户名',
'PASSWORD': '密码',
'HOST': 'localhost',
'PORT': '3306',
}
}
在命令行中输入以下命令
# 安装 mysql 驱动
sudo pip3 install pymysql
# 安装 simpleui
sudo pip3 install django-simpleui
lab4.sql
Django
$ pip install virtualenv
$
$ # Virtualenv modules installation (Unix based systems)
$ virtualenv env
$ source env/bin/activate
$
$ # Virtualenv modules installation (Windows based systems)
$ # virtualenv env
$ # .\env\Scripts\activate
$
$ pip3 install -r requirements.txt
$
$ # Create tables
$ python manage.py makemigrations
$ python manage.py migrate
$
$ # Start the application (development mode)
$ python manage.py runserver # default port 8000
$
$ # Start the app - custom port
$ # python manage.py runserver 0.0.0.0:<your_port>
$
$ # Access the web app in browser: http://127.0.0.1:8000/
数据表设计
designer ( id, name, price)
bag ( id, designer_id, type, color, already_rented )
customer ( id, phone#, address, name, email, card#, gender)
lease ( id, bag_id, customer_id, start_date, back_date, insure_or_not )
ER图 如下:
Navicat 模型图如下:
需求及功能 :
1. 通过设计师名字 检索出该设计师设计过多少包
2. 查询每个客户每个客户所有手袋的租赁时间。
3. 编写一个程序来计算和列出每个顾客的消费金额。放映这个包租出去的天数
4. 添加出租信息的表和包表,租用日期是当前时间
5. 包被退回的时候,显示出租的总时长和总金额,包可以再次被出租
6. 为所有异常设计并显示适当的消息
存储过程设计
--返回所有表的表名
show_all_tables()
--传入表名,返回指定表的数据
show_table(tableName)
--传入表名,返回指定表的表头字段
show_columns_from_table(tableName)
--获取所有客户id
get_customers_id()
--获取所有设计师名字
get_designers_name()
--传入设计师名字,获取指定设计师设计的背包
bag_by_designer(designer)
--按照客户租赁所有包包的总天数排序显示客户
best_customers()
--传入用户id,根据用户id计算用户每个租赁交易应支付金额
report_customer_amount(customer_id)
--传入用户id,根据用户id计算用户所有租赁交易应支付总额
report_customer_totalCost(customer_id)
--传入用户id,包包id,是否支付保险,租用天数,添加一笔租赁交易
add_rentals(customerId, bagId, optionalInsurance, daysOfRent)
--传入包包类型,颜色,设计者,添加一个可以租赁的包包
add_bag(bagType, bagColor, bagDesigner)
--传入设计师的名字, 每个包包的价格, 添加一个设计师
add_designer(dname, price)
--传入客户姓氏,名字, 地址,电话号码,邮箱地址,信用卡号码,性别
add_customer(lname,fname, addr, pnum ,email, cnum, gender)
.....
详见 lab4.sql 文件
触发器设计
returnBag
-- 退回包包的时候,该包包的状态应该恢复可以租借
-- 在触发器中设置 totalDays 记录总租借日期 , bill 记录总的账单金额
-- 退回包包的时候 通过调用select @totalDays, @bill 来获取这两个值
功能设计
1. 通过设计师名字 检索出该设计师设计过多少包
在数据库中设置好存储过程
/*
存储过程
创建显示每个设计师设计了多少包
传入参数 designer 为该设计师名字
*/
delimiter //
create procedure bag_by_designer(in designer varchar(30))
begin
select
btype as 'Name',
color as 'Color',
d.name as 'Manufacturer'
from bag as b
left join designer as d
on b.did = d.did
where d.name = designer;
end //
delimiter;
urls.py
path('bag_views', views.bag_views, name="bags_views"),
views.pybag_views
def bag_views(request):
# 记录信息, 返回前端
msg = None
success = True
if request.method == "GET":
# 获取设计师 姓名
name = request.GET.get('designer_name')
cur = connection.cursor()
# 获取所有设计师姓名
cur.callproc('get_designers_name')
data = cur.fetchall()
# 将所有设计师姓名存进元组
names = []
for da in data:
names.append(da[0])
if name is not None:
# 该姓名存在
if name in names:
success = True
else:
success = False
if success:
# 执行存储过程,获取该设计师所有的包包
cur2 = connection.cursor()
cur2.callproc('bag_by_designer', (name,))
objss = cur2.fetchall()
msg = name + "'s bags are all here"
else:
msg = "Designer " + name + " doesn't exits"
return render(request, 'home/bag_views.html', locals())
创建如下前端页面:
输入设计师 Coach 的名字,得如下结果:
异常测试:
输入客户 id 查询每个客户每个客户所有手袋的租赁时间。
在数据库中设置好存储过程
/*
存储过程
创建 按照所有交易总租赁奢侈包总天数排序 显示客户
*/
delimiter //
create procedure best_customers()
begin
select
last_name as 'Last Name',
first_name as 'First Name',
address as 'Address',
phone as 'Telephone',
ifnull(sum(datediff( date_returned, date_rented)), 0)
as 'Total Length of Rentals'
from customer as c
left join rentals as r
on c.cid = r.cid
group by c.cid
order by `Total Length of Rentals` desc;
end //
delimiter;
urls.py
path('best_customer', views.best_customer, name="best_customer"),
views.pybest_customer
def best_customer(request):
# 调用存储过程,返回前端
cur = connection.cursor()
cur.callproc("best_customers")
datas = cur.fetchall()
return render(request, 'home/best_customer.html', locals())
创建如下前端页面
编写一个程序来计算和列出每个顾客的消费金额。放映这个包租出去的天数
在数据库中设置好存储过程
/*
存储过程
按照用户 id 计算 用户每个租赁交易应支付 账单金额 从大到小排序
传入参数为用户 id
*/
delimiter //
create procedure report_customer_amount(in customer_id int(32))
begin
select
c.last_name as 'Last Name',
c.first_name as 'First Name',
d.name as 'Manufacturer',
b.btype as 'Name',
datediff( r.date_returned, r.date_rented) as 'totalDays',
(d.price + r.optional_insurance)
* datediff( r.date_returned, r.date_rented) as 'Cost'
from rentals as r
left join customer as c
on r.cid = c.cid
left join bag as b
on r.bid = b.bid
left join designer as d
on d.did = b.did
where r.cid = customer_id
order by Cost desc;
end //
delimiter;
-- call report_customer_amount(17);
/*
存储过程
按照用户 id 计算 用户所有租赁交易应支付 账单金额
传入参数为用户 id
*/
delimiter //
create procedure report_customer_totalCost(in customer_id int(32))
begin
select
c.last_name as 'Last Name',
c.first_name as 'First Name',
sum((d.price + r.optional_insurance)
* datediff( r.date_returned, r.date_rented)) as totalCost
from rentals as r
left join customer as c
on r.cid = c.cid
left join bag as b
on r.bid = b.bid
left join designer as d
on d.did = b.did
where r.cid = customer_id;
end //
delimiter;
urls.py
path('customers_amount', views.customers_amount, name="customers_amount"),
views.pycustomers_amount
@login_required(login_url="/login/")
def customers_amount(request):
msg = None
success = True
if request.method == "GET":
# 获取前端输入的用户 id
customer_id = request.GET.get('customer_id')
if customer_id is not None:
# 输入的 id 为 str 类, 应该强制类型转换
id = int(customer_id)
# 执行存储过程, 获取所有的 用户 id
cur = connection.cursor()
cur.callproc('get_customers_id')
data = cur.fetchall()
cur.close()
# 将所有用户 id 存进元组
ids = []
for da in data:
ids.append(da[0])
if id is not None:
if id in ids:
# 这个用户 id 存在
success = True
else:
success = False
if success:
cur2 = connection.cursor()
cur3 = connection.cursor()
# 获取该用户所有租赁信息
cur2.callproc('report_customer_amount', (id,))
# 获取该用户所有租赁账单总金额
cur3.callproc('report_customer_totalCost', (id,))
amounts = cur2.fetchall()
totalCosts = cur3.fetchall()
cur2.close()
cur3.close()
cost = totalCosts[0][2]
msg = "The customer whose id is " + customer_id + "'s bill"
else:
msg = "The customer whose id is " + customer_id + " doesn't exits"
return render(request, 'home/customers_amount.html', locals())
创建如下前端页面:
输入客户id,得如下结果
异常情况测试
添加包
存储过程
/*
存储过程
新建一个奢侈品背包
传入参数为 包的类型, 包的颜色, 包的设计者
*/
delimiter //
create procedure add_bag(bagType varchar(30), bagColor varchar(10), bagDesigner varchar(30))
begin
insert into bag( btype, color, did)
values ( bagType, bagColor, (select did
from designer
where name = bagDesigner));
end //
delimiter;
urls.py
path('add_bag', views.add_bag, name="add_bag"),
views.pyadd_bag
@login_required(login_url="/login/")
def add_bag(request):
msg = None
flag = True
success = True
if request.method == "POST":
# 获取前端输入的包包 信息
bname = request.POST.get('bag_name')
bcolor = request.POST.get('bag_color')
dname = request.POST.get('designer_name')
bprice = request.POST.get('price_per_day')
try:
# 将价格转为 浮点数
dprice = float(bprice)
except:
msg = "please enter a current number"
success = False
if success:
# 获取所有设计师名字
cur = connection.cursor()
cur.callproc('get_designers_name')
data = cur.fetchall()
cur.close()
d_names = []
for i in data:
d_names.append(i[0])
cur = connection.cursor()
if dname in d_names:
# 该设计师 存在
cur.callproc('get_designer_price', (dname,),)
data = cur.fetchall()
price = data[0][0]
# 价格不公道
if dprice != price:
msg = "The price is not equal to this designer's price"
flag = False
else:
# 设计师不存在, 添加一个设计师
cur.callproc('add_designer', (dname, dprice),)
cur.close()
if flag:
# 添加包包
cur = connection.cursor()
cur.callproc("add_bag", (bname, bcolor, dname))
cur.close()
msg = 'Success - please <a href="/">return</a>.'
return render(request, 'home/add_bag.html', locals())
创建如下前端页面
添加包包
添加成功
在包包表格中可以看到如下信息
添加出租信息的表,租用日期是当前时间
包被退回的时候,显示出租的总时长和总金额,包可以再次被出租
存储过程
/*
存储过程
创建租赁交易记录
传入参数为用户 id, 奢侈品 id, 是否支付保险, 租赁天数
*/
delimiter //
create procedure add_rentals(customerId int(32), bagId int(32), optionalInsurance tinyint(1), daysOfRent int(10))
begin
insert into rentals(cid, bid, date_rented, date_returned, optional_insurance)
values (customerId, bagId, curdate(), curdate() + daysOfRent, optionalInsurance);
update bag set already_rented = 1 where bid = bagId;
end //
delimiter;
urls.py
path('rent_bag', views.rent_bag, name="rent_bag"),
path('mybag', views.mybag, name="mybag"),
views.pyrent_bagmybag
@login_required(login_url="/login/")
def rent_bag(request):
msg = None
success = True
flag = True
# bag 属性名
data = Bag._meta.fields
columns = [data[i].name for i in range(len(data))]
# 获取所有包
objs = Bag.objects.all()
# 当前 user id
uid = request.user.id
# 获取 uid 对应的 customer 表信息
customer = Customer.objects.filter(uid = uid).first()
if customer is None:
# 当前用户 没有补充个人信息
flag = False
msg = 'Please improve your personal information - <a href="/customer_register"> Profile </a>'
success = False
if flag:
# 获取 cid
cid = customer.cid
if request.method == "POST":
# 获取前端返回的 信息
bagid = request.POST.get("bag_id")
days = request.POST.get("days")
insurance = request.POST.get("insurance")
cur = connection.cursor()
try:
# 添加租赁信息
cur.callproc('add_rentals', (cid, bagid, insurance, days),)
msg = "Rent bag: " + bagid + " Success"
except:
# 存储过程执行可能会遇到些问题,为解决
msg = "Please enter how many days you want to rent"
success = False
return render(request, 'home/rent_bag.html', locals())
@login_required(login_url="/login/")
def mybag(request):
msg = None
success = True
# 获取 已经租出去的 包包
bags = Bag.objects.filter(already_rented = 1)
bids = []
for bag in bags:
bids.append(bag.bid)
# uid
uid = request.user.id
# 当前 user 的 customer 信息
customer = Customer.objects.filter(uid = uid).first()
cid = customer.cid
if customer is None:
# 当前用户未补充个人信息
msg = 'Please improve your personal information - <a href="/customer_register"> Profile </a>'
return render(request, 'home/page-404.html', locals())
else:
# 获取 被租出的包的信息
rentals = Rentals.objects.filter(bid__in=bids)
# 按照 归还日期从大到小排序
rents = list(rentals.filter(cid = cid).order_by("-date_returned"))
ids = []
bids = []
# 对租赁账单信息去重, 只保留归还日期最新的
for rent in rents:
if rent.bid.bid not in bids:
bids.append(rent.bid.bid)
ids.append(rent.bid)
if request.method == "POST":
# 获取要归还的包包的 bid
bid = request.POST.get("bag_id")
# 获取对应账单的信息
rids = list(rentals.filter(cid = cid, bid = bid).order_by("-date_returned"))
rid = rids[0].rid
cur = connection.cursor()
# ids 元组中存在的 归还的 bid 删去
for id in ids:
print(id)
if id.bid == int(bid):
ids.remove(id)
cur.callproc("turnBack", (rid,),)
# 获取触发器返回的信息
data = cur.fetchall()
cur.close()
days = data[0][0]
bill = data[0][1]
msg = data
msg = "The bag id : " + str(bid) + ", total days you rent it : " + str(days) + ", the bill you should pay : $" + str(bill)
return render(request, 'home/mybag.html', locals())
触发器
/*
触发器
创建会话变量 totalDays,bill
totalDays 记录总的租赁天数
bill 记录租赁期间应付账单金额
update 语句更新包的租赁状态
退回包包后可以通过执行 select 语句获取会话变量的值
*/
delimiter //
create trigger returnBag after update on rentals for each row
begin
declare pricePerday double(10,2);
set @totalDays = 0;
set @bill = 0.00;
if new.date_returned then
select
price into pricePerday
from bag as b, designer d
where b.bid = new.bid
and b.did = d.did;
select
datediff(new.date_returned, new.date_rented) into @totalDays;
select
(pricePerday + new.optional_insurance) * @totalDays into @bill;
end if;
update bag set already_rented = false where bid = new.bid;
end //
delimiter;
租包
成功
租赁账单信息
个人已租包包信息
退回,且退回成功
其余功能模块不再赘述~