【完结】Django完成读者浏览书籍,图书详情页,借阅管理【已开源,附源码地址】

发布时间:2024年01月12日

前情回顾:

使用Django框架实现简单的图书借阅系统——完成图书信息管理

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

文章来源:https://blog.csdn.net/weixin_46999174/article/details/135546030
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。