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()
    # 登录----- 展示-----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我们的静态资源在这个文件夹才可以,具体操作步骤如下:

  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"><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 &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 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 图书借阅系统

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT上位机开发(文本编辑器的界面开发)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 文本编辑器是编程开发中经常使用到的一个软件&#xff0c;比如说notepad就是其中一种。这里说编写一个文本编辑器&#xff0c;并不是说真的要写一个…

linux 内存

linux内存分类 按用途分 stack heap(brk,sbrk , mmap), 文件映射&#xff0c; bss&#xff0c; data , text, 还有page cache&#xff0c; slab&#xff08;kmalloc连续&#xff09;, vmalloc等内核深处的。 属性 进程OOM 对于进程来说&#xff0c;堆泄漏在死亡时是没问题 但…

【Java SE语法篇】7.面向对象——类和对象

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ 文章目录 1. 面向对象程序设计概述1.1 类1.2 对象1.3 类之间的…

UE5 实现RPG游戏操作控制

在UE5以后&#xff0c;epic抛弃了之前的那一套操作输入系统&#xff0c;使用了一套新的增强输入作为替代&#xff0c;目的主要是解决经常切换操作时的问题&#xff08;操作人物上车以后&#xff0c;可以直接切换成操作汽车的一套输入&#xff09;接下来&#xff0c;将实现如何使…

用React给XXL-JOB开发一个新皮肤(三):实现登录页和Layout骨架

目录 一. 简述二. 接口服务调整 2.1. 登录接口2.2. 登出接口2.3. 修改密码接口2.4. 修改配置文件 三. 前端HTTP 请求四. 登录页面 4.1. 搭建登录页面4.2. 对接登录接口 五. Layout 骨架 5.1. 搭建骨架5.2. Header5.3. 修改密码5.4. 退出登录 六. 其他 一. 简述 上一篇文章我…

Android代码混淆

Android之代码混淆 代码混淆的作用设置混淆1. 在模块目录下的 build.gradle 文件中配置以下代码2. 在 proguard-rules.pro 文件中添加混淆规则 通用混淆规则常用匹配符常用命令注意事项如何查看是否已混淆 代码混淆的作用 1.令 APK 难以被逆向工程&#xff0c;即很大程度上增加…

Nightingale 夜莺监控系统 - 监控篇(2)

Author&#xff1a;rab 官方文档&#xff1a;https://flashcat.cloud/docs/content/flashcat-monitor/categraf/3-configuration/ 目录 前言一、Categraf 配置文件二、Input 插件配置文件2.1 插件说明2.2 通用配置2.2.1 配置采集频率 interval2.2.2 配置采集实例 instances2.2…

Spring Boot - Application Events 的发布顺序_ContextRefreshedListener

文章目录 Pre概述Code源码分析 Pre Spring Boot - Application Events 的发布顺序_ApplicationEnvironmentPreparedEvent 概述 Spring Boot 的广播机制是基于观察者模式实现的&#xff0c;它允许在 Spring 应用程序中发布和监听事件。这种机制的主要目的是为了实现解耦&#…

AI语音识别模块--whisper模块

1.下载 ffmpeg&#xff0c;挑一个自己电脑系统的版本&#xff0c;下载&#xff0c;如我win64&#xff1a; 地址&#xff1a; Releases BtbN/FFmpeg-Builds GitHub 下载压缩包zip&#xff0c;到本地 解压安装&#xff0c;其实无需安装&#xff0c;只需把对应的目录下的bin&…

2024年第1周,第一期技术动态

大家好&#xff0c;才是真的好。 今天周五&#xff0c;我们继续介绍与Domino相关产品新闻&#xff0c;以及互联网或其他IT行业动态等。 一、Notes/Domino V9和V10技术支持结束和假消息 今年2024年6月1号&#xff0c;HCL将结束IBM Notes/Domino 9.0.x和10.0.x产品的技术支持声…

制作 CentOS Stream9 的U盘系统启动盘

一、简述 注:请勿用于商用&#xff0c;如有版权纠纷&#xff0c;于博主无任何关系。&#xff08;仅用于学习研究使用&#xff09; 由于CentOs Linux 7和CentOs Stream8终止日期是2024年&#xff0c;需要将系统升级到最新版本的CentOs Stream9&#xff0c;下面是刻录系统盘的操…

用js做个转盘

样式 <style>.wheel {position: relative;width: 400px;height: 400px;border: 1px solid black;border-radius: 50%;overflow: hidden;margin: auto;}.slice {position: absolute;left: 0;top: 0;width: 0;height: 0;border: 200px solid red;/* border-width: 100px 10…

Linux/SwagShop

Enumeration nmap 仍然一样&#xff0c;先使用nmap探索目标开放端口情况 看到开启了22端口和80端口&#xff0c;还是一样的&#xff0c;先从80端口开始探索&#xff0c;从nmap给出的结果&#xff0c;我们可以看到有一个域名&#xff0c;因此在/etc/hosts中添加域名到IP的映射…

ODBC 在指定的DSN中,驱动程序和应用程序之间的体系结构不匹配

常规办法就是64位或32位匹配&#xff0c;如果解决不了&#xff0c;往下看。 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓解决方案↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 解压AccessDatabaseEngine_X64.exe&#xf…

【C++】C++11中的常见语法(下)

C11 一、可变参数模板1. 递归函数方式展开参数包2. 逗号表达式展开参数包3. STL容器中的 empalce 相关接口函数 二、lambda 表达式1. C98 中的一个例子2. 使用 lambda 表达式3. lambda 表达式语法&#xff08;1&#xff09;lambda 表达式各部分说明&#xff08;2&#xff09;捕…

池化、线性、激活函数层

一、池化层 池化运算是深度学习中常用的一种操作&#xff0c;它可以对输入的特征图进行降采样&#xff0c;从而减少特征图的尺寸和参数数量。 池化运算的主要目的是通过“收集”和“总结”输入特征图的信息来提取出主要特征&#xff0c;并且减少对细节的敏感性。在池化运算中…

基于SSM的电脑测评系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的电脑测评系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

Python教父推荐:《Python基础教程》(第3版) 中文PDF电子版限免

《Python基础教程 第3版》包括Python程序设计的方方面面&#xff1a;首先&#xff0c;从Python的安装开始&#xff0c;随后介绍了Python的基础知识和基本概念&#xff0c;包括列表、元组、字符串、字典以及各种语句&#xff1b;然后循序渐进地介绍了一些相对高-级的主题&#x…

旅游数据可视化大屏:一屏掌控,畅游数据之海

随着旅游业的蓬勃发展&#xff0c;如何有效地管理和分析旅游数据成为行业关注的焦点。旅游数据可视化大屏作为一种新兴的技术手段&#xff0c;为旅游业带来了前所未有的机遇和挑战。 旅游数据可视化大屏集成了丰富的数据资源&#xff0c;通过直观的图表、图像和交互界面&#x…

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

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