文章目录
一、效果展示
1、图书展示界面
2、图书删除功能
3、图书添加功能
4、图书编辑功能
解决了上次图书管理系统的删除序号重排问题
,也全部采用了系统自建主键!优化了界面
项目不足之处:
由于多表操作,因此作者和出版社只能在那几个当中选择,都是限制死了的,没有写出添加出版社和作者的web接口!
二、项目目录展示
大致流程:
1、先把项目所用数据库准备好,改settings、\_\_init__文件把数据库连接好
!
2、然后设置url和视图函数映射关系,视图函数通过操作数据库,返回模板语法渲染好的页面,或者临时重定向到其他url对应的视图函数
(我这里临时重定向的全是主页,因为数据修改完,就跳转到主页展示修改后的效果嘛)!
3、无论是模板中的html,还是视图函数都不要采用硬编码url,都应该使用name反向解析!
三、项目源码
1、models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=30)
price = models.IntegerField()
pub_date = models.DateField()
authors = models.ManyToManyField(to="Authors") # 多对多
publish = models.ForeignKey(to="Publisher", on_delete=models.CASCADE) # 一对多,只有外键才有级联删除这一说。多对多是另外开一张表,不存在
def __str__(self):
return self.name
class Authors(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
ad = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE)
def __str__(self):
return self.name
class AuthorDetail(models.Model):
email = models.EmailField()
tel_phone = models.IntegerField()
class Publisher(models.Model):
name = models.CharField(max_length=30)
email = models.EmailField()
def __str__(self):
return self.name
这里面的AuthorDetail表
,只是为了练习作者与作者详细之间的OneToOneField
关系!对图书管理系统并没有实际意义!
2、urls.py
from django.contrib import admin
from django.urls import path, re_path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.book_view, name='book_view'),
path('books/add', views.book_add, name='book_add'),
re_path('books/del/(?P<del_book_id>[0-9]+)/', views.book_del, name='book_del'),
re_path('books/edit/(?P<edit_book_id>[0-9]+)/', views.book_edit, name='book_edit')
]
3、views.py
from django.shortcuts import render
from app01.models import Book, Publisher, Authors
from django.shortcuts import redirect, reverse
# Create your views here.
def book_view(request):
book_list = Book.objects.all()
return render(request, "index.html", {'book_list': book_list})
def book_add(request):
if request.method == 'GET':
publisher_list = Publisher.objects.all()
author_list = Authors.objects.all()
return render(request, 'add.html', {'publisher_list': publisher_list, 'author_list': author_list})
else:
name = request.POST.get('name')
price = request.POST.get('price')
pub_date = request.POST.get('pub_date')
publisher_id = request.POST.get('publisher_id')
authors_id = request.POST.getlist('authors_id[]') # 这里得到的是一个author列表
book = Book.objects.create(name=name, price=price, pub_date=pub_date, publish_id=publisher_id)
book.authors.add(*authors_id) # *号:列表打散
return redirect(reverse('book_view'))
def book_del(request, del_book_id):
Book.objects.filter(pk=del_book_id).delete()
return redirect(reverse('book_view'))
def book_edit(request, edit_book_id):
book_obj = Book.objects.filter(pk=edit_book_id).first()
if request.method == 'GET':
publisher_list = Publisher.objects.all()
author_list = Authors.objects.all()
return render(request, 'edit.html', {'book_obj': book_obj, 'publisher_list': publisher_list, 'author_list': author_list})
else:
name = request.POST.get('name')
price = request.POST.get('price')
pub_date = request.POST.get('pub_date')
publisher_id = request.POST.get('publisher_id')
authors_id = request.POST.getlist('authors_id[]')
Book.objects.update(name=name, price=price, pub_date=pub_date, publish_id=publisher_id)
book_obj.authors.set(*authors_id)
return redirect(reverse('book_view'))
4、模板
(1)index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>图书管理系统</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.table_area {
width: 800px;
position: absolute;
top: 150px;
left: 250px;
}
.add_btn {
font-size: 18px;
font-family: "Kaiti SC";
font-weight: bolder;
}
</style>
</head>
<body>
<div class="table_area">
<table class="table 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_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ book_obj.name }}</td>
<td>{{ book_obj.price }}</td>
<td>{{ book_obj.pub_date|date:'Y-m-d' }}</td>
<td>{{ book_obj.publish.name }}</td>
<td>
{% for author_obj in book_obj.authors.all %} <!--book_obj.authors.all得到的是一个作者对象的queryset-->
{% if forloop.last %}
<!--
有人会问这里不是对象吗?为什么打印对象?不应该是author_obj.name吗?
我在model中写了双下方法str的
-->
{{ author_obj }}
{% else %}
{{ author_obj }},
{% endif %}
{% endfor %}
</td>
<td>
<a href="{% url 'book_edit' book_obj.pk %}" class="btn btn-warning btn-xs">编辑</a>
<a href="{% url 'book_del' book_obj.pk %}" class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% if forloop.last and forloop.counter > 0 %}
<tr>
<td colspan="7">
<a href="{% url 'book_add' %}" class="btn btn-info btn-xs form-control add_btn">添加书籍</a>
</td>
</tr>
{% endif %}
{% empty %}
<tr align="center">
<td colspan="7">
暂未上架任何书籍... <br>
<span>请点击:<a href="{% url 'book_add' %}" class="btn btn-info btn-xs">添加书籍</a></span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
</html>
(2)add.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>图书管理系统</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
.form-area {
width: 600px;
position: absolute;
top: 130px;
left: 300px;
}
h3 {
position: relative;
left: 270px;
margin-bottom: 20px;
font-family: "Kaiti SC";
font-weight: bold;
}
.center-block {
position: relative;
left: 50px;
}
.author_add {
position: relative;
top: 20px;
}
#inputauthor {
height: 75px;
}
</style>
</head>
<body>
<div class="form-area">
{% block form_title %}
<h3>书籍添加信息表</h3>
{% endblock form_title %}
{% block form_head %}
<form class="form-horizontal" action="{% url 'book_add' %}" method="post">
{% endblock form_head %}
{% csrf_token %}
<div class="form-group">
<label for="inputname" class="col-sm-2 control-label">书名</label>
<div class="col-sm-10">
{% block inputname %}
<input type="text" class="form-control" id="inputname" placeholder="请输入书籍名称" name="name">
{% endblock inputname %}
</div>
</div>
<div class="form-group">
<label for="inputprice" class="col-sm-2 control-label">价格</label>
<div class="col-sm-10">
{% block inputprice %}
<input type="text" class="form-control" id="inputprice" placeholder="请输入价格" name="price">
{% endblock inputprice %}
</div>
</div>
<div class="form-group">
<label for="input_pub_date" class="col-sm-2 control-label">出版时间</label>
<div class="col-sm-10">
{% block input_pub_date %}
<input type="date" class="form-control" id="input_pub_date" name="pub_date">
{% endblock input_pub_date %}
</div>
</div>
<div class="form-group">
<label for="inputpublisher" class="col-sm-2 control-label">出版社</label>
<div class="col-sm-10">
{% block inputpublisher %}
<select name="publisher_id" id="inputpublisher" class="form-control">
{% for publish_obj in publisher_list %}
<option value="{{ publish_obj.pk }}">{{ publish_obj }}</option>
{% endfor %}
</select>
{% endblock inputpublisher %}
</div>
</div>
<div class="form-group">
<label for="inputauthor" class="col-sm-2 control-label author_add">作者</label>
<div class="col-sm-10">
{% block inputauthor %}
<select name="authors_id[]" id="inputauthor" class="form-control" multiple>
{% for author_obj in author_list %}
<option value="{{ author_obj.pk }}">{{ author_obj }}</option>
{% endfor %}
</select>
{% endblock inputauthor %}
</div>
</div>
{% block submit %}
<input type="submit" class="btn btn-success center-block" value="提交">
{% endblock submit %}
{% block form-tail %}
</form>
{% endblock form-tail %}
</div>
</body>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在bootstrap前边) -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
</html>
(3)edit.html
由于本页面和add.html及其相似,因此这里采用了模板继承
!
{% extends 'add.html' %}
{% block form_title %}
<h3>书籍信息编辑表</h3>
{% endblock form_title %}
{% block form_head %}
<form class="form-horizontal" action="{% url 'book_edit' book_obj.pk %}" method="post">
{% endblock form_head %}
{% block inputname %}
<input type="text" class="form-control" id="inputname" name="name" value="{{ book_obj.name }}">
{% endblock inputname %}
{% block inputprice %}
<input type="text" class="form-control" id="inputprice" name="price" value="{{ book_obj.price }}">
{% endblock inputprice %}
{% block input_pub_date %}
<input type="date" class="form-control" id="input_pub_date" name="pub_date" value="{{ book_obj.pub_date|date:'Y-m-d' }}">
{% endblock input_pub_date %}
{% block inputpublisher %}
<select name="publisher_id" id="inputpublisher" class="form-control">
{% for publish_obj in publisher_list %}
{% if book_obj.publish == publish_obj %}
<option value="{{ publish_obj.pk }}" selected>{{ publish_obj }}</option>
{% else %}
<option value="{{ publish_obj.pk }}">{{ publish_obj }}</option>
{% endif %}
{% endfor %}
</select>
{% endblock inputpublisher %}
{% block inputauthor %}
<select name="authors_id[]" id="inputauthor" multiple class="form-control">
{% for author_obj in author_list %}
{% if author_obj in book_obj.authors.all %}
<option value="{{ author_obj.pk }}" selected>{{ author_obj }}</option>
{% else %}
<option value="{{ author_obj.pk }}">{{ author_obj }}</option>
{% endif %}
{% endfor %}
</select>
{% endblock inputauthor %}
{% block submit %}
<input type="submit" class="btn btn-success center-block" value="提交修改">
{% endblock submit %}
{% block form-tail %}
</form>>
{% endblock form-tail %}
四、项目心得总结
1、注意事项
注意publish和publish_id的区别
,authors并不是一个字段,而是用来供我们操纵关系表的一个接口!
2、select多选框的实现方法
name后一定要加[]
,不然接受到的就是一个值,而不是一个多选的列表!
也不能再用get了,需要用getlist
!获得的列表就可以直接*号打散传值!