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.rhkb.cn/news/236634.html

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

相关文章

云卷云舒:AI for DB、DB for AI

云卷云舒&#xff1a;算力网络云原生&#xff08;下&#xff09;&#xff1a;云数据库发展的新篇章-CSDN博客https://blog.csdn.net/bishenghua/article/details/135050556 随着数据库和AI技术的分支同向演进&#xff0c;AI 和数据库间的关联越发紧密了。 大模型的演进发展&a…

MySQL面试题 | 04.精选MySQL面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

py的函数讲解

前言:本章节我们来讲函数&#xff0c;主播略微感觉到有点小难&#xff0c;友友们需要认真看 目录 一.初始函数 1.1关于函数 1.2举例 1.3小结 二.函数的基础语法 2.1关于函数的语法 2.2举例 2.3小结 三.函数的参数 3.1关于函数的参数 3.2举例 3.3小结 四.函数的返回…

Java8常用新特性

目录 简介 1.默认方法 2..Lambda表达式 3.Stream API 4.方法引用 5.Optional类 简介 Java 8是Java编程语言的一个重要版本&#xff0c;引入了许多令人兴奋和强大的新特性。这些特性使得Java程序更加现代化、灵活和高效。让我们一起来探索一些Java 8的常用新特性吧&#…

1.1 计算机网络在信息时代的作用

1.1 计算机网络在信息时代的作用 网络&#xff08;Network&#xff09;由若干结点&#xff08;Node&#xff09;和连接这些结点的链路&#xff08;Link&#xff09;所组成。网络中的结点可以是计算机、集线器、交换机或者路由器等。 图1-1 多个网络还可以通过路由器互连起来&a…

SpringMVC文件上传(CommonsMultipartResolver)

以上传一个图片为例 添加依赖 <!--文件上传--> <dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</version> </dependency> 配置文件上传解析器 <…

windows下全免费手动搭建php8+mysql8开发环境及可视化工具安装

最近PHP项目少了&#xff0c;一直在研究UE5和Golang&#xff0c;但是考虑到政府、国企未来几年国产化的要求&#xff0c;可能又要重拾PHP。于是近日把用了N年的框架重新更新至适合PHP8.2以上的版本&#xff0c;同时也乘着新装机&#xff0c;再次搭建php和mysql开发环境。本文留…

《产业结构调整指导目录(2024年本)》发布,模糊测试首次纳入

近日&#xff0c;第6次委务会议通过了新版的《产业结构调整指导目录&#xff08;2024年本&#xff09;》&#xff0c;该目录自2024年2月1日起正式实施。 与之前的版本相比&#xff0c;本次目录在行业设置上进行了全面升级&#xff0c;新增了“网络安全”这一重要行业大类&#…

Qt QLineEdit文本框控件

文章目录 1 属性和方法1.1 占位字符串1.2 对齐方式1.3 回显模式1.4 读写控制1.5 格式控制1.6 信号和槽 2 实例2. 布局2.2 代码实现 QLineEdit 是Qt 中的文本框&#xff0c;准确地说是单行文本框&#xff0c;通常用于接受用户的输入。 比如用户输入用户名、密码等&#xff0c;都…

高光谱分类论文解读分享之基于多模态融合Transformer的遥感图像分类方法

IEEE TGRS 2023&#xff1a;基于多模态融合Transformer的遥感图像分类方法 题目 Multimodal Fusion Transformer for Remote Sensing Image Classification 作者 Swalpa Kumar Roy , Student Member, IEEE, Ankur Deria , Danfeng Hong , Senior Member, IEEE, Behnood Ras…

Word·VBA实现邮件合并

目录 制作邮件合并模板VBA实现邮件合并举例 之前写过的一篇使用《python实现word邮件合并》&#xff0c;本文为vba实现方法 制作邮件合并模板 域名可以使用中文&#xff0c;最终完成的word模板&#xff0c;wps操作步骤类似 VBA实现邮件合并 在Excel启用宏的工作表运行以下代…

Linux中断 -- 中断应答、嵌套、

接上文&#xff0c;本文继续介绍Linux软件部分逻辑。 参考内核版本&#xff1a;kernel-4.19 目录 1.中断信号在各级中断控制器中的应答 2.supports_deactivate_key意义 3.中断嵌套 1.中断信号在各级中断控制器中的应答 本章主要从内核软件层面来看各中断控制器对中断信号处…

【python,机器学习,nlp】RNN循环神经网络

RNN(Recurrent Neural Network)&#xff0c;中文称作循环神经网络&#xff0c;它一般以序列数据为输入&#xff0c;通过网络内部的结构设计有效捕捉序列之间的关系特征&#xff0c;一般也是以序列形式进行输出。 因为RNN结构能够很好利用序列之间的关系&#xff0c;因此针对自…

面试算法119:最长连续序列

题目 输入一个无序的整数数组&#xff0c;请计算最长的连续数值序列的长度。例如&#xff0c;输入数组[10&#xff0c;5&#xff0c;9&#xff0c;2&#xff0c;4&#xff0c;3]&#xff0c;则最长的连续数值序列是[2&#xff0c;3&#xff0c;4&#xff0c;5]&#xff0c;因此…

【信息安全】hydra爆破工具的使用方法

hydra简介 hydra又名九头蛇&#xff0c;与burp常规的爆破模块不同&#xff0c;hydra爆破的范围更加广泛&#xff0c;可以爆破远程桌面连接&#xff0c;数据库这类的密码。他在kali系统中自带。 参数说明 -l 指定用户名 -L 指定用户名字典文件 -p 指定密码 -P 指…

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;

x-cmd pkg | czg - git commit 智能生成工具

目录 简介首次用户功能特点竞品和相关作品进一步探索 简介 czg 源于 commitizen/cz-cli 交互插件中 cz-git 的延伸项目&#xff0c;重新使用 TypeScript 编写的零依赖独立的 Node.js 命令行工具。旨在使用交互友好的方式&#xff0c;辅助用户生成规范的 git commit message 约…

如何解决NAND系统性能问题?-- NAND接口分类

三、NAND接口 NAND闪存接口是连接主机控制器与NAND存储芯片的通信桥梁&#xff0c;负责命令、地址和数据的传输。典型的NAND闪存接口包括一组I/O线&#xff08;通常为8条或更多&#xff09;用于数据传输&#xff0c;以及若干控制信号线。 基本接口信号&#xff1a; Chip Enable…

如何一键添加引号和英文逗号,然后可以放入SQL中使用 → WHERE USER_NAME IN (‘张三‘,‘李四‘,‘王五‘)

如何一键添加引号和英文逗号&#xff0c;然后可以放入SQL中使用 → WHERE USER_NAME IN&#xff08;张三,李四,王五&#xff09; 一、背景二、解决方法三、一键添加引号和英文逗号的教程 一、背景 在日常开发中&#xff0c;当处理VARCHAR或VARCHAR2类型的字段时&#xff0c;很…

【自控实验】3. 带有饱和非线性环节控制系统相平面分析

本科课程实验报告&#xff0c;有太多公式和图片了&#xff0c;干脆直接转成图片了 仅分享和记录&#xff0c;不保证全对 实验内容&#xff1a; 有无非线性环节的相轨迹对比&#xff0c;并求超调量。 在输入单位阶跃信号Xsr时&#xff0c;用示波器观察和记录系统输入饱和非线…