Django框架完成读者浏览书籍,图书详情页,借阅管理

前情回顾:

使用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我们的静态资源在这个文件夹才可以,具体操作步骤如下:

  1. 首先在项目目录新建一个static文件夹
  2. 修改settings.py 告知Django static文件夹地址
STATIC_URL = '/static/'
# 静态文件的额外目录
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),# 如果需要,添加更多目录
]
  1. 在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 &copy; 2019.Company name All rights reserved.<a target="_blank"href="http://sc.chinaz.com/moban/">&#x7F51;&#x9875;&#x6A21;&#x677F;</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">&times;</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 图书借阅系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/344464.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高压消防泵:科技与安全性的完美结合

在现代社会&#xff0c;随着科技的不断发展&#xff0c;各种高科技设备层出不穷&#xff0c;为我们的生活带来了极大的便利。在森林火灾扑救领域&#xff0c;恒峰智慧科技研发的高压消防泵作为一种高效、节能、绿色、环保的优质设备&#xff0c;将科技与安全性完美地结合在一起…

蓝桥杯练习题(五)

&#x1f4d1;前言 本文主要是【算法】——蓝桥杯练习题&#xff08;五&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 …

【计算机组成原理】IEEE 754 标准定义的浮点数表示格式

IEEE 754 IEEE 754是一种由美国电气和电子工程师协会&#xff08;IEEE&#xff09;制定的标准&#xff0c;用于定义浮点数的表示和运算。这个标准定义了浮点数的格式、舍入规则、特殊值的处理以及算术操作的执行方式。 IEEE 754浮点数标准主要定义了两种浮点数格式&#xff1…

Windows11 安装MySQL8.0操作

一、从MySQL官网下载MySQL安装包 官网地址&#xff1a; www.mysql.com &#xff08;1&#xff09;首先 选择 DOWNLOADS 下载界面 &#xff08;2&#xff09;其次选择 MySQL 客户端 下载 &#xff08;3&#xff09;选择windows安装MySQL &#xff08;4&#xff09;选择MySQL类型…

Jenkins 问题

从gitlab 仓库拉去代码到Jenkins本地报错 ERROR: Couldn’t find any revision to build. Verify the repository and branch configuration for this job. 问题原因&#xff1a; 创建条目》配置的时候&#xff0c;gitlab仓库不存在master分支 修复后&#xff1a;

分裂联邦学习论文-混合联邦分裂学习GAN驱动的预测性多目标优化

论文标题&#xff1a;《Predictive GAN-Powered Multi-Objective Optimization for Hybrid Federated Split Learning》 期刊&#xff1a;IEEE Transactions on Communications, 2023 一、论文介绍 背景&#xff1a;联邦学习作为一种多设备协同训练的边缘智能算法&#xff0…

使用nginx+HTML2canvas将任意html网页转为png图片自定义张数

文章目录 概述网页的转换html2canvas的使用导入导入HTML2canvas库函数定义 nginx部署编写控制截图网页代码iframe 网页控制代码 测试说明 概述 本文简述如何使用nginxhtml2canvas将任意网页html转为png图片 网页的转换 如果是本地网页&#xff0c;直接进行nginx反向代理就行…

30天精通Nodejs--第十七天:express-路由配置

目录 引言基础路由配置路由参数与查询参数路由前缀与子路由路由重定向结语 引言 上篇文章我们简单介绍了express的基础用法&#xff0c;包括express的安装、创建路由及项目启动&#xff0c;对express有了一个基础的了解&#xff0c;这篇开始我们将详细介绍express的一些高级用…

【开源】基于JAVA语言的民宿预定管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用例设计2.2 功能设计2.2.1 租客角色2.2.2 房主角色2.2.3 系统管理员角色 三、系统展示四、核心代码4.1 查询民宿4.2 新增民宿4.3 新增民宿评价4.4 查询留言4.5 新增民宿订单 五、免责说明 一、摘要 1.1 项目介绍 基于…

python MySQL学习

免费 MySQL Community Server 社区版本 免费 但是MySQL 不提供官方技术支持 MySQL Cluster 集群版 开源免费 可将几个 MySQL Server 封装乘一个Server 收费 MySQL Enterprise Edition 商业版 该版本是收费的 可以试用30天 官方提供技术支持 MySQL Cluster CGE 高级集群版…

Unable to start embedded Tomcat Nacos启动报错

Nacos报错解决 报错信息&#xff1a;Unable to start embedded Tomcat 无法加载内置的tomcat。 无需重新配置JDK&#xff0c;轻松解决 Windows 系统为例 startup.cmd 操作步骤如下&#xff1a; 在nacos解压后的文件中&#xff0c;进入bin目录下如图1所示&#xff1a; 在红框中…

IDEA—初始化配置

注&#xff1a;以下红框圈的部分&#xff0c;均为已设置好的 外观与行为 编辑器 高级设置 按两次 shift 弹出提示问题解决