前情回顾:
使用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()# 登录----- 展示-----HTMLuser_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"><iclass="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"><ahref="/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 diamnonumyeirmod 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"><iclass="lnr lnr-sync"></i>compare</a><a href="#" data-toggle="tooltip" title="Wishlist"><iclass="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渲染的值// 存储值到localStoragelocalStorage.setItem('user_id', {{user_id}});});
</script></body></html>
其中我们后端已经传了用户的ID,可以在js中直接取到值,一会这个值,需要从展示页面传递到详情页,后端之间可以用session传值,涉及到页面之间的传值可以用localStorage来传递,展示页面存储用户ID, 详情页取出用户ID,确保加入书架的时候有用户ID。
<script>// 当文档加载完成后执行$(document).ready(function() {//直接从获取Django渲染的值// 存储值到localStoragelocalStorage.setItem('user_id', {{user_id}});});
</script>
效果如下:支持两种展示方式
并且点击标题或者图片可以跳转到详情页。
2.完成图书详情页功能
2.1从后端获取图书详情信息
在图书展示页面,点击图片或者标题,将ID传递给后端,后端根据ID查询图书信息,返回给详情页面。
def display_book_by_id(request, id):# 根据ID查询bookbook = 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渲染的值// 存储值到localStoragevar 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}}, // 替换为实际的书籍IDuser_id: storedValue};// 获取 CSRF tokenvar 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_iduser_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渲染的值// 存储值到localStoragevar 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}}, // 替换为实际的书籍IDuser_id: storedValue};// 获取 CSRF tokenvar 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.returnedborrow_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 图书借阅系统