框架第七课---图书管理系统详解
整体代码思路
:主要就是图书列表信息展示页视图函数代码与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代码里面,删除按钮也和上面的编辑按钮一样,拼出一个新路由跳转,让路由后面的转换器捕获到多出的路由,传给删除的视图函数,后端拿到对应的要删除书籍对象的主键值,先拿到要删除的书籍对象,然后通过该待删除的书籍对象清楚掉第三张表中与作者的关系,最后再将该待删除的书籍对象删掉!!!
结束,玛德好累!!!
.
.
.
.
.
.
.
.
.
模型层代码
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">«</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">»</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')
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库