框架第七课---图书管理系统详解

整体代码思路

:主要就是图书列表信息展示页视图函数代码与html代码的如何编写,以及图书添加页与图书编辑页的视图函数代码与html代码的编写
------------------------------------------

图书列表信息展示页:

首先我们考虑的是,想要在该页面上展示哪些信息给用户看,所以视图函数只要将书表里面的所有对象查出来,render到对应的图书展示页的html页面上就行了

主要是图书展示页的html页面怎么写,显然用table表格标签展示书籍的信息是最方便的,先写好定义好表格标签的表头字段(编号、书名、价格、出版日期、出版社、作者、操作),然后利用模板语法拿到后端传来的queryset对象进行for循环,拿到每一个书籍对象,每一次for循环,都让对象去分别点与上面表头对应的字段属性,拿到对应的信息展示出来,这样for循环完,页面上就展示了所有的书籍对象对应的信息了.
注意:通过书籍对象点一对一的publish外键字段拿到出版社对象,再通过出版社对象点name拿到出版社的名字的。
注意:通过书籍对象点多对多的authors虚拟外键字段,拿到的可不是作者对象!!!是这玩意app01.Author.None,  书籍对象.authors.all() 拿到到是包含对应作者对象的Queryset,
注意:还要for循环才能拿到对应的一个一个的作者对象,有了作者对象才能通过点name拿到对应的作者姓名。
也就是说想通过一个书籍对象,拿到该书对应的说有的作者姓名,要先用book_obj.authors.all() 拿到Queryset然后for循环Queryset拿到里面的书对应的所有作者对象,最后再通过作者对象点name才能拿到该书对应作者的姓名
<td>{{ book_obj.publish_time|date:'Y-m-d' }}</td>
<td class="btn btn-info">{{ book_obj.publish.name }}</td>
<td ><!--注意多对多的这张表是一个虚拟表,通过书对象点虚拟外键字段authors只会跳到Author作者表,除非后面是add set remove clear 这4个关键字才会去操作虚拟表-->
   {% for author_obj in book_obj.authors.all %}
       <span style="margin-right: 5px" class="btn btn-success">{{ author_obj.name }}</span>
   {% endfor %}
</td>

-------------------------------------------

.

图书添加页思路:

通过在图书列表信息展示页的添加一个a标签按钮,让点击该按钮后,跳转到图书添加页路由对应的视图函数去,html页面只需要用一个form表单,然后按书表里面的字段,在html页面里面写好对应的input标签,让用户去输入对应的书所需要的各种数据。
注意:书籍表里面有一个出版社的外键字段,对应的是出版社表里面的id,也就是说我们先要获取的是出版社对象的id,但是用户又不知道每个出版社对象的id是多少,所以在html页面可以这样玩
<p>出版社名称:
    <!--展示系统中已有的出版社信息供选择-->
    <select name="publish_id" id="" >
        {% for publish_obj in publish_queryset %}
           <option value="{{ publish_obj.id }}">{{ publish_obj.name }}</option>
        {% endfor %}
    </select>
</p>

弄一个select选择标签,写好name对应的信息,在select标签里面来个for循环,将从后端传过来的publish_queryset 给for循环出一个一个的出版社对象,然后在for循环的内部再定义一个option标签,这样当for循环结束,就出现了对应数量的option标签了,每一个option标签的value对应的是出版社对象的id,但是展示给用户看的确是出版社对象的名称。
这样就实现了,当用户在点了对应出版社名称的option标签,提交post请求后,后端通过
request.POST.get('publish_id')就能拿到对应的option标签对应的value对应的值了,也就是出版社对象的id了!!!  展示给 用户看的是对象的name对应的值,实际提交给后端的数据,确实提交的是对象的id对应的值,value对应的是什么,提交给后端的数据就是什么!!!

书籍表里面对应的authers多对多虚拟字段,因为一本书对应的作者可能会有多个,所以select选择标签里面要有一个 multiple  这样用户就可以选择多个option标签了!!!套路和上面的获取书籍 对象对应出版社id套路一样,展示给用户看的是作者对象的姓名,但是该option标签对应的value对应的确实作者的id,传给后端后,按select标签里面的name对应的值作为键用get拿到的就是一个列表,该列表包含用户多选的每个option标签里面value对应值
------------
后端就比较简单:拿到post请求里面的各种用户提交的数据,判断一下书名与价格不能为空,再判断一下书名是否已存在,没问题就往数据库的书籍表里面添加数据了。
book_obj = models.Book.objects.create(title=title,price=price,)
然后再通过书对象利用add方法操作多对多的虚拟表,真好后端拿到了用户多选的包含多个作者id的列表,直接add括号里,前面加个星号打散,一次性全部添加
到第三张虚拟表里面去!!!
book_obj.authors.add(*author_id_list)
最后再重定向到书籍列表详情页去

.
.

图书编辑页思路:

数据编辑页的代码的核心实际上在书籍列表详情页的编辑按钮上

该编辑按钮设置的很巧妙,在表格标签的表身标签里面,的for循环里面,这样每for循环一个数据对象出来,通过对象点的方式生成各种td标签的同时,又多生成了一个td标签,该标签里面放了一个编辑按钮的a标签,但是这个a标签的href的跳转路由非常有意思,href="{% url 'book_edit_view' book_obj.pk %} "  这个地方用的反向解析将别名'book_edit_view'解析为book_edit/  然后再加上for循环出的该对象的主键值,一起拼成一个新路由,当a标签跳转到该新路由后,新路由还是一样,先到路由层进行路由匹配,当匹配书籍编辑视图函数的时候,path('book_edit/<int:book_pk>', views.book_edit_func, name='book_edit_view'),
路由层这样写的意思就是,只要你前面路由前面是book_edit/我就认为该路由已经匹配上视图函数了,book_edit/后面的路由会被转换器捕捉到,先转为int类型,然后以关键字参数book_pk=什么 的形式 和request一起传给视图函数。这样在视图函数里面就可以拿到行参book_pk对应的值了也就是要编辑的书籍对象的主键值,这样在后端就可以通过该主键值,找到对应的书籍对象了

然后render到书籍编辑页的html页面同时将要编辑的书籍对象也传过去,

图书编辑页html页面代码整体和书籍添加页代码相似,只是因为现在有了待编辑书籍对象,所以可以给每个input框标签加个默认值,value=该待编辑书籍对象原来的值,
select选择框标签稍微烦点,想让原来书籍对象选择的数据有默认选中的效果,代码如下,多了一行判断
<select name="publish_id" id="">
  {% for publish_obj in publish_queryset %}
     {% if  publish_obj == edit_book_obj.publish %}
        <option value="{{publish_obj.id}}"selected>{{publish_obj.name}}</option>
    {% else %}
        <option value="{{ publish_obj.id }}">{{ publish_obj.name }}</option>
     {% endif %}
  {% endfor %}
</select>

for循环出的所有的出版社对象,与根据待编辑的书籍对象正向查询对应的出版社对象比对,如果相同则给该option标签添加默认选中的属性selected,如果不同就正常展示,这样原来书籍对象所对应的出版社对应option标签就会有默认选中的效果了!!!
-------------------
同理如果for循环出每一个作者对象,在通过待编辑书籍对象拿到的作者对象所对应Queryset列表里面时,给该作者对象加个默认选中的效果!!否则就不加默认选中的效果!!!

<select name="author_id_list" id="" multiple >
   {% for author_obj in author_queryset %}
     {% if author_obj in edit_book_obj.authors.all %}
         <option value="{{author_obj.id}}"selected>{{author_obj.name}}</option>
     {% else %}
         <option value="{{ author_obj.id }}">{{ author_obj.name }}</option>
     {% endif %}
   {% endfor %}
</select>

书籍对象点多对多的虚拟外键字段authors时,必须还要再点all(),此处因为有模板语法所以才未加括号,才能拿到书籍对象对应的Queryset[作者对象1,作者对象2,]
<!--成员运算判断判断,循环的作者对象是否在待编辑的书籍作者对象对像的Queryset列表中-->
-------------------------------
html页面所有数据都编辑好了后,提交post请求,发给后端,后端拿到对应的数据,再往书籍表里面更新就行了
models.Book.objects.filter(pk=book_pk).update(XXX)
然后别忘了也更新一下,虚拟外键字段对应的第三张表
edit_book_obj.authors.set(author_id_list)

set方法支持在括号里面放可迭代对象,所以编辑后的author_id_list不需要再加*星号打散

.
.

删除图书的思路:

不需要,单独开始一个页面,图书列表信息展示页的html代码里面,删除按钮也和上面的编辑按钮一样,拼出一个新路由跳转,让路由后面的转换器捕获到多出的路由,传给删除的视图函数,后端拿到对应的要删除书籍对象的主键值,先拿到要删除的书籍对象,然后通过该待删除的书籍对象清楚掉第三张表中与作者的关系,最后再将该待删除的书籍对象删掉!!!

结束,玛德好累!!!

.
.
.
image
.
image
.
image
.
image
.
image
.
.

模型层代码

from django.db import models

# Create your models here.

class Book(models.Model):
    """图书表"""
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32, verbose_name='书名')
    price = models.DecimalField(max_digits=9, decimal_places=3, verbose_name='价格')
    publish_time = models.DateTimeField(auto_now_add=True)

    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)

    authors = models.ManyToManyField(to='Author')  # 多对多虚拟字段不需要级联

    def __str__(self):
        return f'图书对象<*>>>{self.title}'


class Publish(models.Model):
    """出版社表"""
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32, verbose_name='出版社名称')
    address = models.CharField(max_length=64, verbose_name='地址')

    def __str__(self):
        return f'出版社对象<*>>>{self.name}'


class Author(models.Model):
    """作者表"""
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32, verbose_name='作者姓名')
    age = models.IntegerField(verbose_name='年龄')
    author_detail = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE)

    def __str__(self):
        return f'作者对象<*>>>{self.name}'

class AuthorDetail(models.Model):
    """作者详情表"""
    id = models.AutoField(primary_key=True)
    phone = models.BigIntegerField(verbose_name='电话号码')
    address = models.CharField(max_length=64, verbose_name='作者地址')

    def __str__(self):
        return f'作者详情表对象<*>>>{self.address}'

.

homePage.html主页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
{#    <script src="jQuery3.6.js"></script>#}
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
{#    <link href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">#}
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
{#    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>#}
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>

    <style>
        #d1 {height: 300px}
        .jumbotron {color: peru}
        #p1 {color: palevioletred}
        #small1 {color: peru ; margin-left:20px}
        #exit2,#exit3,#exit4 {color: palevioletred}
        #span1 {margin-right: 20px}
    </style>

    {% block css %}

    {% endblock %}
</head>

<body>
    <!--导航条-->
    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
                <div class="navbar-header">
                  <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                        <span class="sr-only">Toggle navigation</span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                  </button>
                  <a class="navbar-brand" href="#">BMS</a>
                </div>

            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                  <ul class="nav navbar-nav">
                        <li class="active"><a href="#">图书<span class="sr-only">(current)</span></a></li>
                        <li><a href="#">作者</a></li>
                        <li class="dropdown">
                          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></a>
                          <ul class="dropdown-menu">
                            <li><a href="#">快点行动</a></li>
                            <li><a href="#">等不了了</a></li>
                            <li><a href="#">快点我</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">更多美女</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">快速赚钱法</a></li>
                          </ul>
                        </li>
                  </ul>
                  <form class="navbar-form navbar-left">
                        <div class="form-group">
                          <input type="text" class="form-control" placeholder="书名">
                        </div>
                        <button type="submit" class="btn btn-default">查询</button>
                  </form>
                  <ul class="nav navbar-nav navbar-right">
                        <li><a href="#">teng</a></li>
                        <li class="dropdown">
                          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作<span class="caret"></span></a>
                          <ul class="dropdown-menu">
                            <li><a href="#">账号退出</a></li>
                            <li><a href="#">修改密码</a></li>
                            <li><a href="#">投诉建议</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">联系管理员</a></li>
                          </ul>
                        </li>
                  </ul>
            </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>

    <!--左边栏-->
    <div class="container-fluid">
        <div class="row">

            <div class="col-md-2">
                <div class="list-group" >
                      <a href="{% url 'home_view' %}" class="list-group-item active text-center" id="exit1">首页展示</a>
                      <a href="{% url 'book_list_view' %}" class="list-group-item text-center" id="exit2">图书列表</a>
                      <a href="{% url 'book_list_view' %}" class="list-group-item text-center" id="exit3">出版社列表</a>
                      <a href="{% url 'book_list_view' %}" class="list-group-item text-center" id="exit4">作者列表</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                    <a href="#" class="list-group-item text-center">跟多详情</a>
                </div>
            </div>

    <!--右边栏-->
            <div class="col-md-10">
                <!--面板-->
                    <div class="panel panel-primary">
                          <div class="panel-heading">
                            <h3 class="panel-title"><span class="glyphicon glyphicon-th-list" id="span1"></span>图书管理系统</h3>
                          </div>

                          <div class="panel-body">

                              {% block content %}
                                        <!--页头-->
                                    <div class="page-header">
                                      <h1>图书管理系统 <small id="small1">更多精彩等你来查</small></h1>
                                    </div>

                                   <!--巨幕-->
                                    <div class="jumbotron" id="d1">
                                      <h1>全球最大的网上图书管理系统</h1>
                                      <p id="p1">友情连接</p>
                                      <p><a class="btn btn-primary btn-lg" href="#" role="button">点击精彩</a>

                                          <button type="button" class="btn btn-primary btn-lg" aria-label="Left Align">
                                              <span class="glyphicon glyphicon-lock " aria-hidden="true"></span>
                                          </button>

                                      </p>
                                    </div>

                                  <!--"右下图片区"-->
                                    <div class="row">
                                            <div class="col-xs-6 col-md-3">
                                            <a href="#" class="thumbnail">
                                                <sapn class="glyphicon glyphicon-heart"></sapn> <sapn class="glyphicon glyphicon-heart"></sapn>  <sapn class="glyphicon glyphicon-heart"></sapn>
                                              <img src="xxx" alt="...">

                                            </a>
                                          </div>
                                            <div class="col-xs-6 col-md-3">
                                                <a href="#" class="thumbnail">
                                                    <sapn class="glyphicon glyphicon-heart"></sapn> <sapn class="glyphicon glyphicon-heart"></sapn>  <sapn class="glyphicon glyphicon-heart"></sapn>
                                                  <img src="xxx" alt="...">
                                                </a>
                                              </div>
                                            <div class="col-xs-6 col-md-3">
                                                <a href="#" class="thumbnail">
                                                    <sapn class="glyphicon glyphicon-heart"></sapn> <sapn class="glyphicon glyphicon-heart"></sapn>  <sapn class="glyphicon glyphicon-heart"></sapn>
                                                  <img src="xxx" alt="...">
                                                </a>
                                              </div>
                                            <div class="col-xs-6 col-md-3">
                                                <a href="#" class="thumbnail">
                                                    <sapn class="glyphicon glyphicon-heart"></sapn> <sapn class="glyphicon glyphicon-heart"></sapn>  <sapn class="glyphicon glyphicon-heart"></sapn>
                                                  <img src="xxx" alt="...">
                                                </a>
                                              </div>
                                    </div>  <!--"内部的row"-->
                              {% endblock %}

                          </div>   <!--"panel-body"-->
                    </div>  <!--"panel panel-primary"-->
            </div>   <!--"col-md-10"-->

        </div> <!--"row"-->

    </div> <!--"container-fluid"-->

{% block js %}

{% endblock %}

</body>
</html>

.

bookListPage.html页面代码

{% extends 'homePage.html' %}     <!--继承母板-->

<!--css区-->
{% block css %}

{% endblock %}


<!--内容区-->
{% block content %}
    <h2 class="text-center">图书展示页</h2>
    <a href="{% url 'book_add_view' %}" class="btn btn-warning">图书添加</a>
    <table class="table table-striped table-hover">
        <thead>
            <tr>
                <th>编号</th>
                <th>书名</th>
                <th>价格</th>
                <th>出版日期</th>
                <th>出版社</th>
                <th>作者</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>
            {% for book_obj in book_queryset %} <!--QuerySet[书对象,书对象]-->
                <tr>
                    <td>{{ forloop.counter }}</td> <!--可以展示主键值也可以展示从一开始的有序数列-->
                    <td>{{ book_obj.title }}</td>
                    <td>{{ book_obj.price }}</td>
                    <td>{{ book_obj.publish_time|date:'Y-m-d' }}</td>
                    <td class="btn btn-info">{{ book_obj.publish.name }}</td>
                    <td ><!--注意多对多的这张表是一个虚拟表,通过书对象点虚拟外键字段authors只会跳到Author作者表,不会往虚拟表上添加!!-->
                        {% for author_obj in book_obj.authors.all %}  <!--QuerySet[作者对象,作者对象]-->
                            <span style="margin-right: 5px" class="btn btn-success">{{ author_obj.name }}</span>
{#                            {% if forloop.last %}#}
{#                                {{ author_obj.name }}#}
{#                            {% else %}#}
{#                                {{ author_obj.name }} /#}
{#                            {% endif %}   <!--for循环出的是最后一个不加分隔符,其他的末尾加个分隔符!!-->#}
                        {% endfor %}
                    </td>
                    <td>
                        <!--用模板语法将别名'book_edit_view'反向解析出路由book_edit/ 再加上for循环出的每一个书籍对象的主键值,一起拼出新的路由-->
                        <!--a标签的作用是跳转到这个新的路由网址上去,跳转到新的路由网址上去后,首先还是要先到路由层匹配视图函数-->
                        <!--当匹配上后,将request与book_pk=从网址上匹配到的动态的路由结果,再传递给视图函数!!-->
                        <a href="{% url 'book_edit_view' book_obj.pk %}" class="btn btn-primary btn-xs">编辑</a>

                        <a href="{% url 'book_delete_view' book_obj.pk  %}" class="btn btn-danger btn-xs delBtn">删除</a>
                    </td>
                </tr>
            {% endfor %}

        </tbody>
    </table>

    <!--分页!!-->
    <nav aria-label="Page navigation" class="text-center">
              <ul class="pagination">   <!--这个是属性是让列表标签浮动起来,让原来竖排变成横排!!-->
                <li>
                  <a href="#" aria-label="Previous">
                    <span aria-hidden="true">&laquo;</span>
                  </a>
                </li>
                <li><a href="#">1</a></li>
                <li><a href="#">2</a></li>
                <li><a href="#">3</a></li>
                <li><a href="#">4</a></li>
                <li><a href="#">5</a></li>
                  <li><a href="#">6</a></li>
                  <li><a href="#">7</a></li>
                  <li><a href="#">8</a></li>
                  <li><a href="#">9</a></li>
                  <li><a href="#">10</a></li>
                <li>
                  <a href="#" aria-label="Next">
                    <span aria-hidden="true">&raquo;</span>
                  </a>
                </li>
              </ul>
    </nav>
{% endblock %}



<!--js区-->
<!--给删除按钮添加一个删除点击确认事件!!-->
{% block js %}
    <script>
        $('.delBtn').click(function () {
            let res = confirm('你确定要删除吗?')
            if (!res){
                return false
            }
        })
    </script>
{% endblock %}

.

bookAddPage.html页面代码

<!--书籍添加页-->

{% extends 'homePage.html' %}     <!--继承母板-->

<!--css区-->
{% block css %}

{% endblock %}


<!--内容区-->
{% block content %}
    <div class="row">
        <div class="col-md-6">
            <h2 class="text-center">图书添加页</h2>
                <form action="" method="post" >
                    <p> 书名:
                        <input type="text" name="title" class="form-control">
                    </p>
                    <p> 价格:
                        <input type="text" name="price" class="form-control">
                    </p>
                    <p> 出版日期:
                        <input type="date" name="publish_time" class="form-control">
                    </p>

                    <p> 出版社名称:
                        <!--展示系统中已有的出版社信息供选中-->
                        <select name="publish_id" id="" class="form-control">
                            {% for publish_obj in publish_queryset %}  <!--queryset [数据对象,数据对象]-->
                                <!--展示给用户看的是出版社对应的名字,但是传给后端的出版社对应的id-->
                                <!--因为该页面的用户输入的数据是朝当前页面提交post请求的,是要把数据传给书籍添加的视图函数用的-->
                                <!--视图函数拿到这些数据最后的目的是,往数据库的书籍表里面添加的,所以此处返给后端出版社id更方便-->
                                <!--后端直接拿到主键值去做添加,如果将出版社名字传到后端,后端还要查出版社的主键值是什么就更麻烦了-->
                                <option value="{{ publish_obj.id }}">{{ publish_obj.name }}</option>
                            {% endfor %}
                        </select>
                    </p>

                    <p> 作者名称list:
                        <select name="author_id_list" id="" multiple class="form-control">   <!--一个图书可以有多个作者,加个multiple可以多选-->
                            {% for author_obj in author_queryset %}  <!--queryset [数据对象,数据对象]-->
                                <option value="{{ author_obj.id }}">{{ author_obj.name }}</option>
                                <!--用户选作者其实选的是作者的id,因为后端绑定关系的时候,要么传主键值要么传作者对象-->
                                <!--作者对象数据太大了,所有主键值传过去比较合适,既能节省网络,速度也更快-->
                            {% endfor %}
                        </select>
                    </p>
                    <input type="submit" value="书籍的添加" class="btn btn-block btn-success">
                </form>
        </div> <!--"col-md-6"-->

        <div class="col-md-6">
            <img style="max-width:100%" src="https://file.moyublog.com/d/file/2021-02-14/c7e482715ac8cd045c3964b147231ee8.jpg" alt="..." class="img-rounded">
        </div>

    </div> <!--"row"-->

{% endblock %}



<!--js区-->
{% block js %}

{% endblock %}

.

bookEditPage.html页面代码

<!--书籍编辑页-->

{% extends 'homePage.html' %}     <!--继承母板-->

<!--css区-->
{% block css %}

{% endblock %}



<!--内容区-->
{% block content %}
        <div class="row">
        <div class="col-md-6">
            <h2 class="text-center">图书编辑页</h2>
                <form action="" method="post" >
                    <p> 书名:
                        <input type="text" name="title" class="form-control" value="{{ edit_book_obj.title }}">
                    </p>
                    <p> 价格:
                        <input type="text" name="price" class="form-control" value="{{ edit_book_obj.price }}">
                    </p>
                    <p> 出版日期:
                        <input type="date" name="publish_time" class="form-control" value="{{ edit_book_obj.publish_time|date:'Y-m-d' }}">
                    </p>

                    <p> 出版社名称:
                        <!--展示系统中已有的出版社信息供选中-->
                        <select name="publish_id" id="" class="form-control">
                            {% for publish_obj in publish_queryset %}  <!--queryset [数据对象,数据对象]-->
                                <!--根据待编辑的书籍对象查询对应的出版社对象,与系统所有的出版社对象比对,如果相同则添加默认选中的属性selected-->
                                {% if edit_book_obj.publish == publish_obj %}
                                    <option value="{{ publish_obj.id }}" selected>{{ publish_obj.name }}</option>
                                {% else %}
                                    <option value="{{ publish_obj.id }}">{{ publish_obj.name }}</option>
                                {% endif %}
                            {% endfor %}
                        </select>
                    </p>

                    <p> 作者名称list:
                        <select name="author_id_list" id="" multiple class="form-control">   <!--一个图书可以有多个作者,加个multiple可以多选-->
                            {% for author_obj in author_queryset %}  <!--author_queryset是,author表里面所有的作者对象都放在queryset表里面-->
                                <!--成员运算判断判断,for循环出的没一个作者对象是否在待编辑的书籍作者对象列表中(就是原来该书籍对象所含有的作者)-->
                                {% if author_obj in edit_book_obj.authors.all %}
                                    <option value="{{ author_obj.id }}" selected>{{ author_obj.name }}</option>
                                {% else %}
                                    <option value="{{ author_obj.id }}">{{ author_obj.name }}</option>
                                {% endif %}
                            {% endfor %}
                        </select>
                    </p>
                    <input type="submit" value="书籍的编辑" class="btn btn-block btn-danger">
                </form>
        </div> <!--"col-md-6"-->

        <div class="col-md-6">
            <img style="max-width:100%" src="https://file.moyublog.com/d/file/2021-02-14/c7e482715ac8cd045c3964b147231ee8.jpg" alt="..." class="img-rounded">
        </div>


    </div> <!--"row"-->

{% endblock %}


<!--js区-->
{% block js %}

{% endblock %}

.

总路由页面代码urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    # 路由分发
    path('app01/', include('app01.urls'))

]

.

应用下的分路由页面代码urls.py

from django.contrib import admin
from django.urls import path

from app01 import views

urlpatterns = [
    # 首页展示
    path('home/', views.home_func, name='home_view'),
    # 想写功能就要先开接口!!
    # 图书列表展示页
    path('book_list/', views.book_list_func, name='book_list_view'),
    # 图书数据的添加页
    path('book_add/', views.book_add_func, name='book_add_view'),
    # 图书数据编辑页
    # 路由里面由于有动态参数,并且用的转换器,所以一定匹配上视图函数,就会传两个参数给函数了book_edit_func(request,book_pk='')
    path('book_edit/<int:book_pk>', views.book_edit_func, name='book_edit_view'),
    # 图书删除页
    path('book_delete/<int:book_pk>', views.book_delete_func, name='book_delete_view')
]

.
.

视图函数下的页面代码views.py

from django.shortcuts import render, HttpResponse, redirect, reverse

# Create your views here.
from app01 import models

---------------------------------------------------
def home_func(request):
    # 首页
    return render(request, 'homePage.html')

---------------------------------------------------
def book_list_func(request):
    # 1. 获取数据库里面的数据展示到页面上去,肯定要通过ORM来与数据库连接,所有要导入models文件
    # 导入models文件,才能用到里面所有的表名,能拿到表名,就能通过点objects,再点其他的方法
    # 就能够对数据库里的该表里面的数据进行增删改查!!!
    book_queryset = models.Book.objects.all()
    # 2. 返回html页面并在页面上展示图书数据
    return render(request, 'bookListPage.html', locals())

---------------------------------------------------
def book_add_func(request):
    # 3. 获取页面上用户输入的值
    if request.method == 'POST':
        title = request.POST.get('title')  # 注意get括号里面一定要和input标签里的name对应的值一样
        price = request.POST.get('price')
        publish_time = request.POST.get('publish_time')
        publish_id = request.POST.get('publish_id')  # 获取值列表里面最后一个数据
        author_id_list = request.POST.getlist('author_id_list')  # 获取完整的列表数据
        # 注意这个地方要用get就只拿到了前端传过来的最后一个值了!!!
        # 4. 再来点对获取到的数据的小判断
        if len(title) == 0 or len(price) == 0:
            return HttpResponse('书名与价格不能为空!')
        # 5.筛选书名是否已存在!
        res = models.Book.objects.filter(title=title)
        if res:
            return HttpResponse('书名已存在!')
        # 6. 没有问题后往数据库里面书籍表添加数据!!
        book_obj = models.Book.objects.create(title=title,
                                              price=price,
                                              publish_time=publish_time,
                                              publish_id=publish_id)
        # 7. 书籍与作者的多对多的第三张关系表添加数据!!
        book_obj.authors.add(*author_id_list)
        # 8. 重定向到书籍展示页
        return redirect(reverse('book_list_view'))

    # 2. 分析可得html页面需要全部的出版社数据与全部的作者数据!!
    publish_queryset = models.Publish.objects.all()
    author_queryset = models.Author.objects.all()
    # 1. 返回一个可以让用户输入书籍相关数据的html页面!!
    # 该页面上有一个form表单,让前端用户输入数据,一定按钮,数据发送到后端,后端校验一下,没有问题,往数据库表里面添加!!!
    return render(request, 'bookAddPage.html', locals())

---------------------------------------------------
def book_edit_func(request, book_pk):
    # 思路根据用户想要编辑的这条数据的主键值,拿到这条完整的数据,然后想办法把数据 展示到页面上
    # 让用户看到数据原来什么样子,然后让用户编辑好了,再点提交,后端再将数据更新到数据库里
    # 1. 根据传到视图函数的数据主键值查询数据对象
    edit_book_obj = models.Book.objects.filter(pk=book_pk).first()   # 千万别忘了first()

    # 4. 拿到用户编辑后发送post请求后的数据
    if request.method == 'POST':
        title = request.POST.get('title')  # 注意get括号里面一定要和input标签里的name对应的值一样
        price = request.POST.get('price')
        publish_time = request.POST.get('publish_time')
        publish_id = request.POST.get('publish_id')  # 获取值列表里面最后一个数据
        author_id_list = request.POST.getlist('author_id_list')  # 获取完整的列表数据
        # 5. 更新数据库表里面的信息!!
        models.Book.objects.filter(pk=book_pk).update(title=title,
                                                      price=price,
                                                      publish_time=publish_time,
                                                      publish_id=publish_id)
        # 6. 书籍与作者的多对多的第三张关系表数据更新!!!
        edit_book_obj.authors.set(author_id_list)  # set方法括号里面放可迭代对象会自动打散
        return redirect(reverse('book_list_view'))

    # 3. 分析可得编辑页面也需要所有的出版社和作者信息!!!直接复制上面视图函数的代码!!
    publish_queryset = models.Publish.objects.all()
    author_queryset = models.Author.objects.all()
    # 2. 传递给html页面,并展示给用户看
    return render(request, 'bookEditPage.html', locals())

---------------------------------------------------
def book_delete_func(request, book_pk):
    # 1. 先拿到书籍表要删除的书籍对象!!!
    delete_book_obj = models.Book.objects.filter(pk=book_pk).first()
    # 2. 再删除数据对象第3张表里面的与作者的对应关系
    delete_book_obj.authors.clear()
    # 3. 最后再删除该书籍对象!!!
    models.Book.objects.filter(pk=book_pk).delete()
    return redirect('book_list_view')
posted @   tengyifan  阅读(102)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示