前情回顾:
使用Django框架实现简单的图书借阅系统——完成图书信息管理
文章目录
- 1.完成展示图书信息功能
- 1.1django 静态资源管理问题
- 1.2编写图书展示模板HTML
- 2.完成图书详情页功能
- 2.1从后端获取图书详情信息
- 2.2详情页面展示图书数据
- 3.完成借阅管理功能
- 3.1管理员管理借阅数据
- 3.1.1完成用户功能,上传借阅信息
- 3.1.2完成展示借阅数据功能
- 3.1.3完成归还图书功能
- 3.1.4完成删除借阅记录功能
- 项目源码地址
1.完成展示图书信息功能
向读者展示所有图书数据,本质上和图书管理一样,向数据库查询图书数据,返回给前端,如果是前后端分离项目,可以合成一个API,但是这次项目没有用到前后端,所以要另外提供一个函数,返回给读者图书数据
def display_all_books(request):
# 查询所有图书
books = Book.objects.all()
# 登录----- 展示-----HTML
user_id = request.session.get('user_id')
username = request.session.get('username')
return render(request, 'reader/library_main.html', {'books': books, 'user_id': user_id, 'user_name': username})
与管理员稍有不同,展示读者页面的数据 ,不仅有图书数据,还有session,因为一会做借阅功能需要用户的ID,所以可以将用户的信息存放到session 传递给下一个页面
1.1django 静态资源管理问题
展示页面,用了 不少CSS和JS,如果说直接写在HTML页面,那显得太臃肿, 所以集成在外部css文件和JS文件,但是Django对这些静态资源支持的不是很好,如果我们想引用css文件不能直接引用,需要专门创建一个新的文件夹,并且告诉Django我们的静态资源在这个文件夹才可以,具体操作步骤如下:
- 首先在项目目录新建一个static文件夹
- 修改settings.py 告知Django static文件夹地址
STATIC_URL = '/static/'
# 静态文件的额外目录
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
# 如果需要,添加更多目录
]
- 在HTML文件中,确保在需要使用静态文件的地方包含{% load static %}标签。
{% load static %}
<link rel="stylesheet" href="{% static 'myapp/css/style.css' %}">
1.2编写图书展示模板HTML
解决完静态资源文件问题,就可以编写HTML文件,这里用到了大量的css和js ,还用到了部分JQuery,在文章末尾会附上开源地址,大家可以去gitee下载源代码
{% load static %}
<!DOCTYPE html>
<html class="no-js" lang="zxx">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="meta description">
<title></title>
<meta name="referrer" content="no-referrer">
<!--=== Favicon ===-->
{# 更改css 地址 {% static 'css/your_stylesheet.css' %}#}
<link rel="shortcut icon" href="{% static 'assets/img/favicon.ico' %}" type="image/x-icon"/>
<!-- Google fonts include -->
<link href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i,700,900%7CYesteryear"
rel="stylesheet">
<!-- All Vendor & plugins CSS include -->
<link href="{% static 'assets/css/vendor.css' %}" rel="stylesheet">
<!-- Main Style CSS {% static 'assets/css/style.css' %} -->
<link href="{% static 'assets/css/style.css' %}" rel="stylesheet">
</head>
<body>
<!-- Start Header Area -->
<header class="header-area">
<!-- main menu area end -->
<!-- mini cart area start -->
<div class="col-lg-3">
<div class="header-configure-wrapper">
<div class="header-configure-area">
<ul class="nav justify-content-end">
<li class="user-hover">
<a href="#">
<i class="lnr lnr-user"></i>
</a>
<ul class="dropdown-list">
<li>
{% if user_name %}
<a href="#" id="local_user_id">用户ID:{{ user_id}}</a>
<a href="#" id="user_name">当前用户:{{ user_name }}</a>
{% else %}
<a href="../login" >请登录</a>
{% endif %}
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<!-- mini cart area end -->
</header>
<!-- end Header Area -->
<!-- off-canvas menu start -->
<aside class="off-canvas-wrapper">
<div class="off-canvas-overlay"></div>
<div class="off-canvas-inner-content">
<div class="btn-close-off-canvas">
<i class="lnr lnr-cross"></i>
</div>
</div>
</div>
</aside>
<!-- off-canvas menu end -->
<!-- main wrapper start -->
<main>
<!-- breadcrumb area start -->
<div class="breadcrumb-area common-bg">
<div class="container">
<div class="row">
<div class="col-12">
<div class="breadcrumb-wrap">
<nav aria-label="breadcrumb">
<h1 id="web_title">弄墨小轩</h1>
</nav>
</div>
</div>
</div>
</div>
</div>
<!-- breadcrumb area end -->
<!-- page main wrapper start -->
<div class="shop-main-wrapper section-space pb-0">
<div class="container">
<div class="row">
<!-- shop main wrapper start -->
<div class="col-lg-9 order-1 order-lg-2">
<div class="shop-product-wrapper">
<!-- shop product top wrap start -->
<div class="shop-top-bar">
<div class="row align-items-center">
<div class="col-lg-7 col-md-6 order-2 order-md-1">
<div class="top-bar-left">
<div class="product-view-mode">
<a class="active" href="#" data-target="grid-view" data-toggle="tooltip"
title="Grid View"><i class="fa fa-th"></i></a>
<a href="#" data-target="list-view" data-toggle="tooltip" title="List View"><i
class="fa fa-list"></i></a>
</div>
</div>
</div>
</div>
</div>
<!-- shop product top wrap start -->
<!-- product item list wrapper start -->
<div class="shop-product-wrap grid-view row mbn-40" id="shopContainer">
{% for book in books %}
<!-- for 循环 解决-->
<div class="col-md-4 col-sm-6">
<!-- product grid start -->
<div class="product-item">
<figure class="product-thumb">
<a href="/reader/{{ book.id }}/display">
<img class="pri-img" src={{ book.image_link }} alt="product">
</a>
</figure>
<div class="product-caption">
<p class="product-name">
<a href="/reader/{{ book.id }}/display">{{ book.title }}</a>
</p>
<div class="price-box">
<span class="price-regular">{{ book.author }}</span>
</div>
</div>
</div>
<!-- product grid end -->
<!-- product list item begin -->
<div class="product-list-item">
<figure class="product-thumb">
<a href="/reader/{{ book.id }}/display">
<img class="pri-img" src={{ book.image_link }} alt="product">
</a>
</figure>
<div class="product-content-list">
<h5 class="product-name"><a
href="/reader/{{ book.id }}/display">{{ book.title }}</a>
</h5>
<div class="price-box">
<span class="price-regular">{{ book.title }}</span>
</div>
<p> 简介:{{ book.details }} </p>
<div class="button-group-list">
<a class="btn-big" href="/reader/{{ book.id }}/display"
data-toggle="tooltip"
title="Add to Cart">
<i class="lnr lnr-cart"></i>添加到书架
</a>
</div>
</div>
</div>
<!-- product list item end -->
</div>
{% endfor %}
</div>
<!-- product item list wrapper end -->
<!-- start pagination area -->
<div class="paginatoin-area text-center">
<input type="hidden" id="currentPage">
<input type="hidden" id="pageSize">
<!-- 绑定按钮事件 -->
<ul class="pagination-box" id="paginate">
</ul>
</div>
<!-- end pagination area -->
</div>
</div>
<!-- shop main wrapper end -->
</div>
</div>
</div>
<!-- page main wrapper end -->
</main>
<!-- main wrapper end -->
<!-- Start Footer Area Wrapper -->
<footer class="footer-wrapper">
<!-- footer widget area start -->
<!-- footer widget area end -->
<!-- footer bottom area start -->
<div class="footer-bottom-area">
<div class="container">
<div class="row align-items-center">
<div class="col-md-6 order-2 order-md-1">
<div class="copyright-text">
<p>Copyright © 2019.Company name All rights reserved.<a target="_blank"
href="http://sc.chinaz.com/moban/">网页模板</a>
</p>
</div>
</div>
<div class="col-md-6 order-1 order-md-2">
<div class="footer-social-link">
<a href="#"><i class="fa fa-twitter"></i></a>
<a href="#"><i class="fa fa-facebook"></i></a>
<a href="#"><i class="fa fa-linkedin"></i></a>
<a href="#"><i class="fa fa-instagram"></i></a>
</div>
</div>
</div>
</div>
</div>
<!-- footer bottom area end -->
</footer>
<!-- End Footer Area Wrapper -->
<!-- Quick view modal start -->
<div class="modal" id="quick_view">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<!-- product details inner end -->
<div class="product-details-inner">
<div class="row">
<div class="col-lg-5 col-md-5">
<div class="product-large-slider">
<div class="pro-large-img">
<img src="assets/img/product/product-details-img1.jpg" alt="product-details"/>
</div>
<div class="pro-large-img">
<img src="assets/img/product/product-details-img2.jpg" alt="product-details"/>
</div>
<div class="pro-large-img">
<img src="assets/img/product/product-details-img3.jpg" alt="product-details"/>
</div>
<div class="pro-large-img">
<img src="assets/img/product/product-details-img4.jpg" alt="product-details"/>
</div>
</div>
<div class="pro-nav slick-row-10 slick-arrow-style">
<div class="pro-nav-thumb">
<img src="assets/img/product/product-details-img1.jpg" alt="product-details"/>
</div>
<div class="pro-nav-thumb">
<img src="assets/img/product/product-details-img2.jpg" alt="product-details"/>
</div>
<div class="pro-nav-thumb">
<img src="assets/img/product/product-details-img3.jpg" alt="product-details"/>
</div>
<div class="pro-nav-thumb">
<img src="{% static 'assets/img/product/product-details-img4.jpg" alt="product-details' %}"/>
</div>
</div>
</div>
<div class="col-lg-7 col-md-7">
<div class="product-details-des quick-details">
<h3 class="product-name">Orchid flower white stick</h3>
<div class="ratings d-flex">
<span><i class="lnr lnr-star"></i></span>
<span><i class="lnr lnr-star"></i></span>
<span><i class="lnr lnr-star"></i></span>
<span><i class="lnr lnr-star"></i></span>
<span><i class="lnr lnr-star"></i></span>
<div class="pro-review">
<span>1 Reviews</span>
</div>
</div>
<div class="price-box">
<span class="price-regular">$70.00</span>
<span class="price-old"><del>$90.00</del></span>
</div>
<h5 class="offer-text"><strong>Hurry up</strong>! offer ends in:</h5>
<div class="product-countdown" data-countdown="2019/08/25"></div>
<div class="availability">
<i class="fa fa-check-circle"></i>
<span>200 in stock</span>
</div>
<p class="pro-desc">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat.</p>
<div class="quantity-cart-box d-flex align-items-center">
<h5>qty:</h5>
<div class="quantity">
<div class="pro-qty"><input type="text" value="1"></div>
</div>
<div class="action_link">
<a class="btn btn-cart2" href="#">Add to cart</a>
</div>
</div>
<div class="useful-links">
<a href="#" data-toggle="tooltip" title="Compare"><i
class="lnr lnr-sync"></i>compare</a>
<a href="#" data-toggle="tooltip" title="Wishlist"><i
class="lnr lnr-heart"></i>wishlist</a>
</div>
<div class="like-icon">
<a class="facebook" href="#"><i class="fa fa-facebook"></i>like</a>
<a class="twitter" href="#"><i class="fa fa-twitter"></i>tweet</a>
<a class="pinterest" href="#"><i class="fa fa-pinterest"></i>save</a>
<a class="google" href="#"><i class="fa fa-google-plus"></i>share</a>
</div>
</div>
</div>
</div>
</div> <!-- product details inner end -->
</div>
</div>
</div>
</div>
<!-- Quick view modal end -->
<!-- offcanvas search form start -->
<div class="offcanvas-search-wrapper">
<div class="offcanvas-search-inner">
<div class="offcanvas-close">
<i class="lnr lnr-cross"></i>
</div>
<div class="container">
<div class="offcanvas-search-box">
<form class="d-flex bdr-bottom w-100">
<input type="text" placeholder="输入鲜花名字" id="search_input">
<button class="search-btn"><i class="lnr lnr-magnifier"></i>search</button>
</form>
</div>
</div>
</div>
</div>
<!-- Scroll to top start -->
<div class="scroll-top not-visible">
<i class="fa fa-angle-up"></i>
</div>
<!-- Scroll to Top End -->
<!-- All vendor & plugins & active js include here -->
<!--All Vendor Js -->
<script src="{% static 'assets/js/vendor.js' %}"></script>
<!-- Active Js -->
<script src="{% static 'assets/js/active.js' %}"></script>
<script src="{% static 'assets/js/jquery.min.js ' %}"></script>
<script>
// 当文档加载完成后执行
$(document).ready(function() {
//直接从获取Django渲染的值
// 存储值到localStorage
localStorage.setItem('user_id', {{user_id}});
});
</script>
</body>
</html>
其中我们后端已经传了用户的ID,可以在js中直接取到值,一会这个值,需要从展示页面传递到详情页,后端之间可以用session传值,涉及到页面之间的传值可以用localStorage来传递,展示页面存储用户ID, 详情页取出用户ID,确保加入书架的时候有用户ID。
<script>
// 当文档加载完成后执行
$(document).ready(function() {
//直接从获取Django渲染的值
// 存储值到localStorage
localStorage.setItem('user_id', {{user_id}});
});
</script>
效果如下:支持两种展示方式
并且点击标题或者图片可以跳转到详情页。
2.完成图书详情页功能
2.1从后端获取图书详情信息
在图书展示页面,点击图片或者标题,将ID传递给后端,后端根据ID查询图书信息,返回给详情页面。
def display_book_by_id(request, id):
# 根据ID查询book
book = Book.objects.filter(id=id).first()
return render(request, 'reader/book.html', {'book': book})
2.2详情页面展示图书数据
{% load static %}
<Html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="meta description">
<title></title>
<!--=== Favicon ===-->
<link rel="shortcut icon" href="assets/img/favicon.ico" type="image/x-icon"/>
<!-- Google fonts include -->
<link href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i,700,900%7CYesteryear"
rel="stylesheet">
<!-- All Vendor & plugins CSS include -->
<link href="{% static 'assets/css/vendor.css' %}" rel="stylesheet">
<!-- Main Style CSS -->
<link href="{% static 'assets/css/style.css' %}" rel="stylesheet">
<!--[if lt IE 9]>
<script src="/oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="/oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!-- Start Header Area -->
<header class="header-area">
<!-- main header start -->
<div class="main-header d-none d-lg-block">
<!-- header middle area start -->
<div class="header-main-area sticky">
<div class="container">
<div class="row align-items-center position-relative">
<!-- start logo area -->
<div class="col-lg-3">
<div class="logo">
<a href="index.jsp">
<img src="assets/img/logo/headset.png" alt="">
</a>
</div>
</div>
<!-- main menu area start -->
<div class="col-lg-6 position-static">
<div class="main-menu-area">
<div class="main-menu">
<!-- main menu navbar start -->
<nav class="desktop-menu">
<ul>
<!-- 跳转到首页 -->
<li><a href="/display_book">弄轩小墨</a></li>
</ul>
</nav>
<!-- main menu navbar end -->
</div>
</div>
</div>
<!-- main menu area end -->
<!-- mini cart area start -->
<div class="col-lg-3">
<div class="header-configure-wrapper">
<div class="header-configure-area">
<ul class="nav justify-content-end">
<li class="user-hover">
<a href="#">
<i class="lnr lnr-user"></i>
</a>
<ul class="dropdown-list">
<li><label id="user_id_display"></label></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<!-- mini cart area end -->
</div>
</div>
</div>
<!-- header middle area end -->
</div>
<!-- main header start -->
</header>
<!-- end Header Area -->
<!-- off-canvas menu start -->
<aside class="off-canvas-wrapper">
<div class="off-canvas-overlay"></div>
<div class="off-canvas-inner-content">
<div class="btn-close-off-canvas">
<i class="lnr lnr-cross"></i>
</div>
<div class="off-canvas-inner">
<!-- search box start -->
<div class="search-box-offcanvas">
<form>
<input type="text" placeholder="Search Here...">
<button class="search-btn"><i class="lnr lnr-magnifier"></i></button>
</form>
</div>
<!-- search box end -->
<!-- mobile menu start -->
<div class="mobile-navigation">
<!-- mobile menu navigation start -->
<nav>
<ul class="mobile-menu">
<li><a href="index.jsp">Home</a></li>
<li><a href="library_main.html">Shop</a></li>
<li><a href="product-details.jsp">Product Details</a></li>
</ul>
</nav>
<!-- mobile menu navigation end -->
</div>
<!-- mobile menu end -->
<div class="mobile-settings">
<ul class="nav">
<li>
<div class="dropdown mobile-top-dropdown">
<a href="#" class="dropdown-toggle" id="currency" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
Currency
<i class="fa fa-angle-down"></i>
</a>
<div class="dropdown-menu" aria-labelledby="currency">
<a class="dropdown-item" href="#">$ USD</a>
<a class="dropdown-item" href="#">$ EURO</a>
</div>
</div>
</li>
<li>
<div class="dropdown mobile-top-dropdown">
<a href="#" class="dropdown-toggle" id="myaccount" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
My Account
<i class="fa fa-angle-down"></i>
</a>
<div class="dropdown-menu" aria-labelledby="myaccount">
<a class="dropdown-item" href="#">my account</a>
<a class="dropdown-item" href="#"> login</a>
<a class="dropdown-item" href="#">register</a>
</div>
</div>
</li>
</ul>
</div>
<!-- offcanvas widget area start -->
<div class="offcanvas-widget-area">
<div class="off-canvas-contact-widget">
<ul>
<li><i class="fa fa-mobile"></i>
<a href="#">0123456789</a>
</li>
<li><i class="fa fa-envelope-o"></i>
<a href="#">info@yourdomain.com</a>
</li>
</ul>
</div>
<div class="off-canvas-social-widget">
<a href="#"><i class="fa fa-facebook"></i></a>
<a href="#"><i class="fa fa-twitter"></i></a>
<a href="#"><i class="fa fa-pinterest-p"></i></a>
<a href="#"><i class="fa fa-linkedin"></i></a>
<a href="#"><i class="fa fa-youtube-play"></i></a>
</div>
</div>
<!-- offcanvas widget area end -->
</div>
</div>
</aside>
<!-- off-canvas menu end -->
<!-- main wrapper start -->
<main id="app">
<!-- breadcrumb area start -->
<div class="breadcrumb-area common-bg">
<div class="container">
<div class="row">
<div class="col-12">
<div class="breadcrumb-wrap">
<nav aria-label="breadcrumb">
<h1></h1>
<ul class="breadcrumb">
<li class="breadcrumb-item"><a href="/display_book/"><i class="fa fa-home"></i></a></li>
<li class="breadcrumb-item active" aria-current="page">{{ book.title }}</li>
</ul>
</nav>
</div>
</div>
</div>
</div>
</div>
<!-- breadcrumb area end -->
<!-- page main wrapper start -->
<div class="shop-main-wrapper section-space">
<div class="container">
<div class="row">
<!-- product details wrapper start -->
<div class="col-lg-12 order-1 order-lg-2">
<!-- product details inner end -->
<div class="product-details-inner">
<div class="row">
<div class="col-lg-5">
<div class="product-large-slider">
<div class="pro-large-img img-zoom">
<img src="{{ book.image_link }}" alt="product-details"/>
</div>
</div>
</div>
<div class="col-lg-7">
<div class="product-details-des">
<h3 class="product-name">{{ book.title }}</h3>
<input id="id" type="hidden" value={{ book.id }}>
<div class="ratings d-flex">
<span><i class="lnr lnr-star"></i></span>
<span><i class="lnr lnr-star"></i></span>
<span><i class="lnr lnr-star"></i></span>
<span><i class="lnr lnr-star"></i></span>
<span><i class="lnr lnr-star"></i></span>
</div>
<div class="price-box">
<span class="price-regular">{{ book.author }}</span>
</div>
<p class="pro-desc">简介:{{ book.details }}</p>
<div class="quantity-cart-box d-flex align-items-center">
<div class="action_link">
{# 请求后台方法#}
<a class="btn btn-cart2">加入到书架</a>
{% csrf_token %}
</div>
</div>
</div>
</div>
</div>
</div>
<!-- product details inner end -->
</div>
<!-- product details wrapper end -->
</div>
</div>
</div>
<!-- page main wrapper end -->
</main>
<!-- main wrapper end -->
<!-- Scroll to top start -->
<div class="scroll-top not-visible">
<i class="fa fa-angle-up"></i>
</div>
<!-- Scroll to Top End -->
<!-- All vendor & plugins & active js include here -->
<!--All Vendor Js -->
<script src="{% static 'assets/js/vendor.js' %}"></script>
<!-- Active Js -->
<script src="{% static 'assets/js/active.js' %}"></script>
<script src="{% static 'assets/js/jquery.min.js' %}"></script>
<script>
// 当文档加载完成后执行
$(document).ready(function () {
//直接从获取Django渲染的值
// 存储值到localStorage
var storedValue = localStorage.getItem('user_id');
// 检查值是否存在
if (storedValue !== null) {
$('#user_id_display').text('User ID: ' + storedValue);
}
$(".btn-cart2").on("click", function () {
// 在这里执行点击事件触发的操作
//判断是否有ID值 没有的话跳转到登录页面
if (storedValue == null) {
alert("请先登录")
window.location.href = "/login";
} else {
// 构建要发送的数据
var data = {
bookId: {{book.id}}, // 替换为实际的书籍ID
user_id: storedValue
};
// 获取 CSRF token
var csrfToken = document.querySelector('input[name="csrfmiddlewaretoken"]').value;
console.log('CSRF Token:', csrfToken);
console.log('data Token:', JSON.stringify(data));
// 发起POST请求
fetch('/borrow_book/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken, // 添加 CSRF token
},
body: JSON.stringify(data),
})
.then(response => {
// 处理响应
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); // 如果服务器返回JSON,解析响应
})
.then(data => {
// 处理返回的数据
alert('添加成功')
})
.catch(error => {
// 处理错误
console.error('There has been a problem with your fetch operation:', error);
});
}
});
});
</script>
</body>
</Html>
敲黑板,这里有一个重点,留到借阅管理讲
详情页效果:
3.完成借阅管理功能
3.1管理员管理借阅数据
首先需要创建借阅管理模型
class BorrowRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='borrow_records')
book_id = models.IntegerField()
returned = models.BooleanField(default=False)
borrow_time = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.user.username} borrowed book with ID {self.book_id} on {self.borrow_time}"
class Meta:
ordering = ['-borrow_time']
这里添加了四个字段:用户ID,并且作为借阅表的外键,绑定用户表的ID,实际开发一般不用外键,这里简单探讨Django的模型功能。图书ID,是否归还字段,借阅时间,由Django自动插入当前时间。
创建好模型,交给Django创建数据表即可。在终端中输入迁移命令
python manage.py migrate
python manage.py makemigrations bookModel # 让 Django 知道我们在我们的模型有一些变更
python manage.py migrate bookModel # 创建表结构
3.1.1完成用户功能,上传借阅信息
def borrow_book(request):
if request.method == 'POST':
try:
# 从请求的 body 中获取 JSON 数据
data = json.loads(request.body.decode('utf-8'))
print(data)
# 获取 user_id 和 book_id
user_id = data.get('user_id')
book_id = data.get('bookId')
# 确保 user_id 和 book_id 非空
if user_id is not None and book_id is not None:
# 获取用户和图书对象
user = get_object_or_404(User, id=user_id)
# 假设 Book 模型表示图书,你可以根据实际情况修改
# book = get_object_or_404(Book, id=book_id)
# 创建借阅记录
BorrowRecord.objects.create(user=user, book_id=book_id)
# 返回成功的 JSON 响应
return JsonResponse({'status': 'success'})
else:
# 返回错误的 JSON 响应,表示缺少必要的数据
return JsonResponse({'status': 'error', 'message': '缺少用户ID或者图书ID'}, status=400)
except json.JSONDecodeError:
# 返回错误的 JSON 响应,表示无法解析 JSON 数据
return JsonResponse({'status': 'error', 'message': '无效的JSon数据'}, status=400)
else:
# 返回错误的 JSON 响应,表示不支持的请求方法
return JsonResponse({'status': 'error', 'message': 'Method not allowed'}, status=405)
重点:我们是在详情页面,点击加入书架的时候,完成信息的上传。一般思路使用Form表单进行POST请求,这里使用的JQuery的fetch 来完成POST请求
<script>
// 当文档加载完成后执行
$(document).ready(function () {
//直接从获取Django渲染的值
// 存储值到localStorage
var storedValue = localStorage.getItem('user_id');
// 检查值是否存在
if (storedValue !== null) {
$('#user_id_display').text('User ID: ' + storedValue);
}
$(".btn-cart2").on("click", function () {
// 在这里执行点击事件触发的操作
//判断是否有ID值 没有的话跳转到登录页面
if (storedValue == null) {
alert("请先登录")
window.location.href = "/login";
} else {
// 构建要发送的数据
var data = {
bookId: {{book.id}}, // 替换为实际的书籍ID
user_id: storedValue
};
// 获取 CSRF token
var csrfToken = document.querySelector('input[name="csrfmiddlewaretoken"]').value;
console.log('CSRF Token:', csrfToken);
console.log('data Token:', JSON.stringify(data));
// 发起POST请求
fetch('/borrow_book/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken, // 添加 CSRF token
},
body: JSON.stringify(data),
})
.then(response => {
// 处理响应
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json(); // 如果服务器返回JSON,解析响应
})
.then(data => {
// 处理返回的数据
alert('添加成功')
})
.catch(error => {
// 处理错误
console.error('There has been a problem with your fetch operation:', error);
});
}
});
});
</script>
上传之前,先判断有没有用户ID。之前在展示页面已经存储了用户ID,在详情页面取出ID即可,如果发现没有ID,则跳转到登录页面,让用户完成登录之后,再上传数据。
另外POST请求一定要有csrfToken ,在HTML页面加入 {% csrf_token %}
之后,Django会给我们生成csrfToken。利用JQuery提取Token的值,完成POST请求。
3.1.2完成展示借阅数据功能
与用户管理,图书管理,套路一样,这里不过多阐述
def get_all_records(request):
# 查询所有记录
records = BorrowRecord.objects.all()
return render(request, 'borrow_list.html', {'records': records})
页面进行展示
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>管理菜单</title>
<style>
/* 菜单样式 */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.sidebar {
width: 250px;
background-color: #333;
height: 100%;
position: fixed;
left: 0;
top: 0;
overflow-x: hidden;
{#padding-top: 20px;#}
}
.sidebar a {
padding: 10px 16px;
margin: 20px;
text-decoration: none;
font-size: 22px;
color: #85f112;
display: block;
transition: 0.3s;
}
.sidebar a:hover {
background-color: #0edcac;
color: black;
}
.content {
margin-left: 250px;
padding: 20px;
}
.header {
background-color: #f1f1f1;
padding: 10px;
text-align: center;
}
{# 美化表格#}
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
</style>
</head>
<body>
<div class="sidebar">
<div class="header">
<h2>管理菜单</h2>
</div>
<a href="../user_list/">用户管理</a>
<a href="../book_list/">图书管理</a>
<a href="../borrow_list/">借阅管理</a>
<a href="../migrations_list/">迁移记录</a>
</div>
<div class="content">
<!-- 这里是你的主要内容 -->
<h2>用户列表</h2>
<table>
<tr>
<th>编号</th>
<th>图书ID</th>
<th>用户ID</th>
<th>是否归还</th>
<th>借阅时间</th>
<th>操作</th>
<!-- 这里可以根据需要显示其他字段 -->
</tr>
{% for record in records %}
<tr>
<td>{{ record.id }}</td>
<td>{{ record.book_id }}</td>
<td>{{ record.user_id }}</td>
<td> {% if record.returned == 0 %}
未归还
{% elif record.returned == 1 %}
归还
{% else %}
Unknown
{% endif %}</td>
<td>{{ record.borrow_time }}</td>
<td>
<a href="/book/{{ record.id }}/returned/">归还</a> | <a href="/delete_record/{{ record.id }}/">删除</a>
</td>
<!-- 这里可以根据需要显示其他字段 -->
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
效果如图:
3.1.3完成归还图书功能
这里也可以做成读者功能,这里简化了功能,只做了管理员功能,感兴趣的伙伴,可以下载源码,进行二次开发
def update_borrow_record(request, record_id):
borrow_record = get_object_or_404(BorrowRecord, id=record_id)
# 取反
borrow_record.returned = not borrow_record.returned
borrow_record.save()
return redirect('/borrow_list')
3.1.4完成删除借阅记录功能
def delete_book(request, id):
try:
print(id)
record = BorrowRecord.objects.filter(id=id).first()
print(record)
record.delete()
return redirect('/borrow_list')
# 重定向到用借阅页面
except BorrowRecord.DoesNotExist:
return HttpResponse('记录不存在')
最后附上开源地址
项目源码地址
链接: Django 图书借阅系统