1.搭建环境
1.1创建库
Navicat 可视化 或 者命令行.
创建library库并设置编码格式 utf8.
create database library character set utf8;
show variables like 'character_set_database';
show create database library;

1.2 创建Django项目

1.3 路径&中间键问题
library目录下的setttings.py
'DIRS': [BASE_DIR, 'templates'],
启动程序报错:
UnicodeDecodeError:
'utf-8' codec can't decode byte 0xd2 in position 0: invalid continuation byte
电脑主机名是中文,修改电脑主机的名字.
详情:https://blog.csdn.net/shilei123456789666/article/details/79116219

1.4 连接MySQL数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1',
'POST': 3306,
'USER': 'root',
'PASSWORD': '123',
'NAME': 'library',
'CHARSET': 'UTF8'
}
}
import pymysql
pymysql.install_as_MySQLdb()

1.5 创建表
1. 表数据
表数据 | | | | |
---|
book (书籍表) | | | | | id | title | price | publish_date | publish_id | 1 | Python | 100.01 | 2021/1/1 | 1 | 2 | MySQL | 200.02 | 2021/2/2 | 2 | 3 | Linux | 300.03 | 2021/3/3 | 3 | 4 | HTML | 400.04 | 2021/4/4 | 1 | | | | | | | | | | | publish(出版社表) | | | | | id | name | email | | | 1 | 北京出版社 | 110@qq.com | | | 2 | 上海出版社 | 120@qq.com | | | 3 | 深圳出版社 | 130@qq.com | | | | | | | | | | | | | book_author(虚拟表) | | | | | id | book_id | author_id | | | 1 | 1 | 1 | | | 2 | 2 | 2 | | | 3 | 3 | 3 | | | 4 | 4 | 1 | | | 5 | 4 | 2 | | | | | | | | | | | | | author(作者表) | | | | | id | name | age | author_id | | 1 | kid | 18 | 1 | | 2 | qq | 19 | 2 | | 3 | qz | 18 | 3 | | | | | | | authordetail(作者详情表) | | | | | id | phone | addr | | | 1 | 110 | 北京 | | | 2 | 120 | 上海 | | | 3 | 130 | 深圳 | | | | | | | |
2. 基础表
先在models.py 中建立基础表
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name='书名')
price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格')
publish_date = models.DateField(verbose_name='出版时间')
class Publish(models.Model):
name = models.CharField(max_length=32, verbose_name='出版社名字')
email = models.EmailField(verbose_name='出版社邮箱')
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name='作者姓名')
age = models.IntegerField(verbose_name='作者年龄')
class Authordetail(models.Model):
phone = models.IntegerField(verbose_name='作者手机')
addr = models.CharField(max_length=32, verbose_name='作者地址')
3. 外键字段
添加外键字端 (自动加后缀_id)
1. 出版社 一对多 书籍表 外键字段建立在多的一方书 籍表中 名为 publish
2. 作者表 多对多 书籍表 虚拟字段建立在查询频率高的一方 籍表中 名为 author
3. 作者表 一对一 作者详情表 外键字端建立在查询频率高的一方 作者表中 名为 authordetail
书籍表中:
ForeignKey(to='Publish') 一对多
ManyToManyField(to='Author') 多对多
作者表中:
OneToOneField(to='Authordetail') 一对一
to='表名' 表是class创建的表,表名首字符大写的要注意.
自动绑定表中主键字段.
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name='书名')
price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格')
publish_date = models.DateField(verbose_name='出版时间')
publish = models.ForeignKey(to='Publish', verbose_name='外键绑定出版社')
author = models.ManyToManyField(to='Author', verbose_name='虚拟字段创建第三张表')
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name='作者姓名')
age = models.IntegerField(verbose_name='作者年龄')
authordetail = models.OneToOneField(to='Authordetail', verbose_name='外键绑定作者详情表')
4. 完整代码
app01应用下 models.py 完整的代码
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name='书名')
price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格')
publish_date = models.DateField(verbose_name='出版时间')
publish = models.ForeignKey(to='Publish', verbose_name='外键绑定出版社')
author = models.ManyToManyField(to='Author', verbose_name='虚拟字段创建第三张表')
def __str__(self):
return '%s %s %s %s %s %s' % (self.id, self.title, self.price, self.publish_date, self.publish, self.author)
class Publish(models.Model):
name = models.CharField(max_length=32, verbose_name='出版社名字')
email = models.EmailField(verbose_name='出版社邮箱')
def __str__(self):
return '%s %s %s' % (self.id, self.name, self.email)
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name='作者姓名')
age = models.IntegerField(verbose_name='作者年龄')
authordetail = models.OneToOneField(to='Authordetail', verbose_name='外键绑定作者详情表')
def __str__(self):
return '%s %s %s %s' % (self.id, self.name, self.age, self.authordetail)
class Authordetail(models.Model):
phone = models.IntegerField(verbose_name='作者手机')
addr = models.CharField(max_length=32, verbose_name='作者地址')
def __str__(self):
return '%s %s %s' % (self.id, self.phone, self.addr)
5. 数据库迁移
# 在终端执行数据库迁移命令
python manage.py makemigrations
python manage.py migrate


1.6 静态文件配置
0. 项目目录下创建 static目录
1. static目录下创建 js目录
2. 复制jQuery文件到 js目录中
3. 复制bootstrap-3.3.7-dist到static目录下
4. settings.py 配置文件中开放静态文件的路径
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]

1.7 启动程序
启动Django程序.

1.8 测试环境
app01 应用tests.py测试文件
from django.test import TestCase
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "library.settings")
import django
django.setup()
from app01 import models
1.9 录数据
不想写代码就手动录数据.
models.Book.objects.create(title='')
models.Authordetail.objects.create(phone=110, addr='北京')
models.Authordetail.objects.create(phone=120, addr='上海')
models.Authordetail.objects.create(phone=130, addr='深圳')

models.Author.objects.create(name='kid', age=18, authordetail_id=1)
models.Author.objects.create(name='qq', age=19, authordetail_id=2)
models.Author.objects.create(name='qz', age=20, authordetail_id=3)


models.Publish.objects.create(name='北京出版社', email='110@qq.com')
models.Publish.objects.create(name='上海出版社', email='120@qq.com')
models.Publish.objects.create(name='深圳出版社', email='130@qq.com')

import datetime
date = datetime.date(2021, 1, 1)
models.Book.objects.create(title='Python', price=100.01, publish_date=date, publish_id=1)
date = datetime.date(2021, 2, 2)
models.Book.objects.create(title='MySQL', price=200.02, publish_date=date, publish_id=2)
date = datetime.date(2021, 3, 3)
models.Book.objects.create(title='Linux', price=300.03, publish_date=date, publish_id=3)
date = datetime.date(2022, 2, 18)
models.Book.objects.create(title='HTML', price=400.04, publish_date=date, publish_id=1)

book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.add(1)
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.author.add(2)
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.author.add(3)
book_obj = models.Book.objects.filter(pk=4).first()
book_obj.author.add(1, 2)

2.主页程序
0. 在工程目录的总路由中配置路由
1. 在视图层中写视图函数
2. 主页面
2.1 路由层
127.0.0.1:8000 对应home主页
'^$' 匹配路径为空
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^$', views.home)
]
2.2 视图层
主页视图函数返回主页面.
from django.shortcuts import render, HttpResponse, redirect
def home(request):
return render(request, 'home.html')
2.3 home主页
1.导入框架划分区域
0. 在项目目录中templates目录下创建home.html页面
1. 导入jQuery与bootstrap文件
2. 这个页码是一个模板页面.在页面中划分三个区域,在继承的时候用于替换.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书管理系统</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
{% block css %}
{% endblock %}
</head>
<body>
{% block html %}
{% endblock %}
{% block js %}
{% endblock %}
</body>
</html>
2. 导航栏
<div>
<div>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<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="#">图书馆</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<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="#">Python</a></li>
<li><a href="#">MySQL</a></li>
<li><a href="#">Linux</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="#">收藏本页面</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>
</ul>
</li>
</ul>
</div>
</div>
</nav>
</div>
</div>


3.栅格布局
栅格布局3-9分
<div>
<div class="row">
<div class="col-md-3">.col-md-3</div>
<div class="col-md-9">.col-md-9</div>
</div>
</div>

4.列表分组
栅格左边部分存放一个列表分组.
<div class="col-md-3">
<div class="list-group">
<a href="#" class="list-group-item active">首页</a>
<a href="#" class="list-group-item">图书列表</a>
<a href="#" class="list-group-item">出版社列表</a>
<a href="#" class="list-group-item">作者列表</a>
<a href="#" class="list-group-item">更多</a>
</div>
</div>


5.标题面板
栅格右边部门放一个面板.
面板分面板标题和面板内容.
将面板内容作为替换区域.
<div class="col-md-9">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">图书管理系统</h3>
</div>
<div class="panel-body">
{% block html %}
{% endblock %}
</div>
</div>
</div>


6.面板内容
面板中分两部分,
{% bloak html%}
上面放一个轮转图
下面放一个三个缩略图.
{% endbloak %}
轮转图
1. https://s2.loli.net/2022/03/10/CNJFHvDlquibBda.jpg
2. https://s2.loli.net/2022/03/10/AWzJVDgPKlc8OZt.jpg
3. https://s2.loli.net/2022/03/10/IZlAELwBqPFjspU.jpg
缩略图
1. https://s2.loli.net/2022/03/10/I4ziahsHbWCAkJU.jpg
2. https://s2.loli.net/2022/03/10/fFm9Lu2hkQRoJNg.jpg
3. https://s2.loli.net/2022/03/10/8ojETnzqRkLyG6h.jpg
<div>
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carousel-example-generic" data-slide-to="0"
class="active"></li>
<li data-target="#carousel-example-generic" data-slide-to="1"></li>
<li data-target="#carousel-example-generic" data-slide-to="2"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item active">
<img src="https://s2.loli.net/2022/03/10/CNJFHvDlquibBda.jpg" alt="...">
</div>
<div class="item">
<img src="https://s2.loli.net/2022/03/10/AWzJVDgPKlc8OZt.jpg" alt="...">
</div>
<div class="item">
<img src="https://s2.loli.net/2022/03/10/IZlAELwBqPFjspU.jpg" alt="...">
</div>
</div>
<a class="left carousel-control" href="#carousel-example-generic" role="button"
data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#carousel-example-generic" role="button"
data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
<div>
<div class="row">
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://s2.loli.net/2022/03/10/I4ziahsHbWCAkJU.jpg" alt="...">
<div class="caption">
<h3>Python</h3>
<p>由荷兰数学和计算机科学研究学会的吉多·范罗苏姆 于1990
年代初设计,作为一门叫做ABC语言的替代品。Python提供了高效的高级数据结构,还能简单有效地面向对象编程...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a
href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://s2.loli.net/2022/03/10/fFm9Lu2hkQRoJNg.jpg" alt="...">
<div class="caption">
<h3>MySQL</h3>
<p>是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database
Management System:关系数据库管理系统)应用软件之一...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a
href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://s2.loli.net/2022/03/10/8ojETnzqRkLyG6h.jpg" alt="...">
<div class="caption">
<h3>Linux</h3>
<p>
全称GNU/Linux,是一套免费使用和自由传播的类UNIX操作系统,它主要受到Minix和Unix思想的启发,是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a
href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
</div>
</div>


为栅格设置一个占据全部视点的属性.
container-fluid值 设置用于 100% 宽度,占据全部视点的容器。
<div class="container-fluid">


7. 图片





[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dbt7Y7lj-1647080624466)(https://s2.loli.net/2022/03/10/IZlAELwBqPFjspU.jpg)]
8. 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书管理系统</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
{% block css %}
{% endblock %}
</head>
<body>
<div>
<div>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<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="#">图书馆</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<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="#">Python</a></li>
<li><a href="#">MySQL</a></li>
<li><a href="#">Linux</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="#">收藏本页面</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>
</ul>
</li>
</ul>
</div>
</div>
</nav>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-md-3">
<div class="list-group">
<a href="#" class="list-group-item active">首页</a>
<a href="#" class="list-group-item">图书列表</a>
<a href="#" class="list-group-item">出版社列表</a>
<a href="#" class="list-group-item">作者列表</a>
<a href="#" class="list-group-item">更多</a>
</div>
</div>
<div class="col-md-9">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">图书管理系统</h3>
</div>
<div class="panel-body">
{% block html %}
<div>
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carousel-example-generic" data-slide-to="0"
class="active"></li>
<li data-target="#carousel-example-generic" data-slide-to="1"></li>
<li data-target="#carousel-example-generic" data-slide-to="2"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item active">
<img src="https://s2.loli.net/2022/03/10/CNJFHvDlquibBda.jpg" alt="...">
</div>
<div class="item">
<img src="https://s2.loli.net/2022/03/10/AWzJVDgPKlc8OZt.jpg" alt="...">
</div>
<div class="item">
<img src="https://s2.loli.net/2022/03/10/IZlAELwBqPFjspU.jpg" alt="...">
</div>
</div>
<a class="left carousel-control" href="#carousel-example-generic" role="button"
data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#carousel-example-generic" role="button"
data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
<div>
<div class="row">
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://s2.loli.net/2022/03/10/I4ziahsHbWCAkJU.jpg" alt="...">
<div class="caption">
<h3>Python</h3>
<p>由荷兰数学和计算机科学研究学会的吉多·范罗苏姆 于1990
年代初设计,作为一门叫做ABC语言的替代品。Python提供了高效的高级数据结构,还能简单有效地面向对象编程...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a
href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://s2.loli.net/2022/03/10/fFm9Lu2hkQRoJNg.jpg" alt="...">
<div class="caption">
<h3>MySQL</h3>
<p>是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database
Management System:关系数据库管理系统)应用软件之一...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a
href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://s2.loli.net/2022/03/10/8ojETnzqRkLyG6h.jpg" alt="...">
<div class="caption">
<h3>Linux</h3>
<p>
全称GNU/Linux,是一套免费使用和自由传播的类UNIX操作系统,它主要受到Minix和Unix思想的启发,是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a
href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
</div>
</div>
</div>
</div>
</div>
</div>
{% block js %}
{% endblock %}
</body>
</html>
3. 图书列表程序
3.1 路由层
0. 127.0.0.1:8000/book/list 对应 book_list 书籍列表页面
1. '^book/list/' 匹配路径
2. 为路由起一个别名
url(r'^book_list/', views.book_list, name='book_list')
3.2 视图层
视图函数中
先读取数据库中的书籍数据
再与图书列表页面一同返回.
from app01 import models
def book_list(request):
queryset = models.Book.objects.all()
return render(request, 'book_list.html', locals())
3.3 图书列表页面
0. 在项目目录中templates目录下创建book_list.html页面,并清空文件内容.
1. 继承模板home主页.
2. 模板语法获取前端传递的数据.
3. 表单中展示数据.
1. 继承模板
{% extends 'home.html' %}
{% block html %}
{% endblock %}
2. 表单标题
序号 | 编号 | 书名 | 作者 | 出版社 | 出版日期 | 价格 | 操作 |
---|
1 | 书id号 | 唯一 | 可能有多个 | 唯一 | 唯一 | 唯一 | 编辑 删除 |
判断字段的信息是唯一的还是有多个.
3. 表单数据
1.序号
方式一: forloop.counter 获取值.
方式二
在后端统计图书的数量,做成一个迭代器.
想着后端next(),后端不支持,()的语法,就封装成一个类.
1.序列化就生成一个迭代器
2.调用方法返回next()取出的值
3.前端对象.方法取值.
class BookNum(object):
def __init__(self, num):
self.iter = [i for i in range(num)].__iter__()
def get_number(self):
return next(self.iter)

queryset = models.Book.objects.all()
for obj in queryset:
print(obj.pk)
print(obj.title)
for author_obj in obj.author.all():
print(author_obj.name)
print(obj.publish.name)
print(obj.publish_date)
print(obj.price)
print(''.center(30, '='))
1
Python
kid
北京出版社
2021-01-01
100.01
==============================
2
MySQL
qq
上海出版社
2021-02-02
200.02
==============================
3
Linux
qz
深圳出版社
2021-03-03
300.03
==============================
4
HTML
kid
qq
北京出版社
2022-02-18
400.04
==============================
4. 创建表单
{% for author_obj in obj.author.all %}
{% if forloop.last %}
{{ author_obj.name }}
{% else%}
{{ author_obj.name }},
{% endif %}
{% endfor %}
{% extends 'home.html' %}
{% block html %}
<div>
<h1 class="text-center">书籍列表</h1>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>序号</th>
<th>编号</th>
<th>书名</th>
<th>作者</th>
<th>出版社</th>
<th>出版时间</th>
<th>价格</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr>
<td>{{ forloop.counter}}</td>
<td>{{ obj.pk }}</td>
<td>{{ obj.title }}</td>
<td>
{% for author_obj in obj.author.all %}
{% if forloop.last %}
{{ author_obj.name }}
{% else%}
{{ author_obj.name }},
{% endif %}
{% endfor %}
</td>
<td>{{ obj.publish.name }}</td>
<td>{{ obj.publish_date|date:'Y-m-d' }}</td>
<td>{{ obj.price }}</td>
<td>
<a href="">编辑</a>
<a href="">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
5. 模板中绑定地址

<a href="{% url 'book_list' %}" class="list-group-item">图书列表</a>
4.添加书籍页面
4.1 路由层
0. 127.0.0.1:8000/book_add 对应 book_add 添加书籍页面
1. '^book/add/' 匹配路径
2. 为路由起一个别名
url(r'^book_add/', views.book_add, name='book_add')
4.2 视图层
视图函数中
0. 先读取数据库中的作者表和出版社表的数据.
1. 再与添加图书页面一同返回.
图书表中需要的信息
id(自增不用管)
title(书名) input标签 name='title'
price(价格) input name='price'
publish_date(出版时间) input type='date' name='publish_date'
外键 publish_id 需要 出版社的id select name='publish' option value='id编码' 展示文字信息
虚拟字段 author_id 需要 作者的id
添加书籍表 直接使用已经存在的作者 和 已经存在的出版社.
def book_add(request):
publish_queryeset = models.Publish.objects.all()
author_queryeset = models.Author.objects.all()
return render(request, 'book_add.html', locals())
4.3 前端页面
1. 继承模板
0. 在项目目录中templates目录下创建book_add.html页面,并清空文件内容.
1. 继承模板home主页.
2. 模板语法获取前端传递的数据.
3. 写一个form表单 提交方式POST 在form表单中设置输入框
{% extends 'book_list.html' %}
{% block html %}
{% endblock %}
2. form表单
{% extends 'book_list.html' %}
{% block html %}
<div>
<h1 class="text-center">添加书籍</h1>
<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_date" class="form-control">
</p>
<p>出版社:
<select name="publish_id" id="" class="form-control">
<option selected disabled hidden></option>
{% for publish_obj in publish_queryset %}
<option value="{{ publish_obj.pk }}" >{{ publish_obj.name }}</option>
{% endfor %}
</select>
</p>
<p>作者:
<select name="author_id" id="" multiple="multiple" class="form-control">
{% for author_obj in author_queryset %}
<option value="{{ author_obj.pk }}">{{ author_obj.name }}</option>
{% endfor %}
</select>
</p>
<p>
<input type="submit" value="添加" class="btn btn-primary form-control">
</p>
</form>
</div>
{% endblock %}



3. 模板中绑定地址
<a href="{% url 'book_add' %}" class="list-group-item">添加书籍</a>

4. 写入数据库
0. 获取POST请求中的数据.
1. 获取书籍对象
2. 往书籍表中写数据
直接create 写的数据
id(自增不用管) title(书名) price(价格) publish_date(出版时间) 外键 publish_id
第三张虚拟表使用.add()写入数据
author_id
def book_add(request):
publish_queryset = models.Publish.objects.all()
author_queryset = models.Author.objects.all()
if request.method == 'POST':
post_obj = request.POST
title = post_obj.get('title')
price = post_obj.get('price')
publish_date = post_obj.get('publish_date')
publish_id = post_obj.get('publish_id')
author_id = post_obj.getlist('author_id')
book_obj = models.Book.objects.create(title=title, price=price, publish_date=publish_date, publish_id=publish_id)
book_obj.author.add(*author_id)
return redirect('book_list')
return render(request, 'book_add.html', locals())
5. 添加书籍


5. 编辑数据页面
在图书列表中点击修改进入到编辑页面,提交的get请求携带书籍数据的id.
后端通过书籍id获取对应的数据,再交给前端,编辑页面中展示需要修改的信息.
5.1 编辑绑定地址
book_list 中的编辑 绑定地址
提交的get请求携带书籍数据的id.
<a href="{% url 'book_edit' obj.pk %}" class="btn btn-primary">编辑</a>

5.2 路由层
0. 127.0.0.1:8000/book_edit/数字 对应 book_edit 添加书籍页面
1. '^book_edit/(?P<edit_id>\d+)/' 匹配路径
2. 在路由中设置有名分组获取GET请求携带的数据.
* 通过url访问的时候需要在后面加上一个数字, 数字是书籍的主键id,不推荐直接访问.
url(r'^book_edit/(?P<edit_id>\d+)/', views.book_edit, name='book_edit')
5.3 视图层
def book_edit(request, edit_id):
book_obj = models.Book.objects.filter(pk=edit_id).first()
publish_queryset = models.Publish.objects.all()
author_queryset = models.Author.objects.all()
return render(request, 'book_edit.html', locals())
5.3 前端页面
0. 表单的提交方式为post
1. 前端页面中 时间需要 |date:'Y-d-m' 冒号后面也不能有空格.
2. 为input设置 required="required" 必须填写信息,不能为空
```html
<!--0. 继承模板-->
{% extends 'home.html' %}
{% block html %}
<div>
<!--1. 表单-->
<h1 class="text-center">编辑书籍</h1>
<form action="" method="post">
<p>书名:
<input type="text" name="title" required="required" class="form-control" value="{{ book_obj.title }}">
</p>
<p>价格:
<input type="text" name="price" required="required" class="form-control" value="{{ book_obj.price }}">
</p>
<p>出版时间:
<input type="date" name="publish_date" required="required" class="form-control"
value="{{ book_obj.publish_date|date:'Y-m-d' }}">
</p>
<p>出版社:
<select name="publish_id" id="" required="required" class="form-control">
{% for publish_obj in publish_queryset %}
{% if publish_obj.pk == book_obj.publish_id %}
<option value="{{ publish_obj.pk }}" selected="selected">{{ publish_obj.name }}</option>
{% else %}
<option value="{{ publish_obj.pk }}">{{ publish_obj.name }}</option>
{% endif %}
{% endfor %}
</select>
</p>
<p>作者:
<select name="author_id" id="" multiple="multiple" required="required" class="form-control">
{% for author_obj in author_queryset %}
{% if author_obj in book_obj.author.all%}
<option value="{{ author_obj.pk }}" selected="selected">{{ author_obj.name }}</option>
{% else %}
<option value="{{ author_obj.pk }}">{{ author_obj.name }}</option>
{% endif %}
{% endfor %}
</select>
</p>
<p>
<input type="submit" value="确定修改" class="btn btn-primary form-control">
</p>
</form>
</div>
{% endblock %}
 


5.4 问题
以前遇到的一个别人写的bug:
0. 图书列表中提交的数据是 a标签 编辑 url 的设置为 {% url 'book_edit' book.pk %}
1. 点击编辑后 跳转到book_edit的地址,后面携带的字符串的 book.pk
2. 路由匹配中正则只能匹配的是字符串类型数据, 有名分组获取到 book.pk 传给后端
3. 视图函数中使用 filter(pk = '字符串类型的 book.pk') 去数据库中匹配到数据 ORM 能转换为同一类型
4. 获取数据后locals() 传给前端,可以使用模板语法拿到.
5. 设置默认出版社的时候 {% if publish_obj.pk == edit_id %} 这样写就出错了

5.5 修改数据
获取POST请求携带的数据,更新到数据库中.
修改一对多和普通表的数据:
queryset对象.update()
修改第三张虚拟表:
queryset对象.first() --> 数据对象
数据对象.author.set([可迭代对象])
def book_edit(request, edit_id):
if request.method == 'POST':
post_obj = request.POST
title = post_obj.get('title')
price = post_obj.get('price')
publish_date = post_obj.get('publish_date')
publish_id = post_obj.get('publish_id')
author_id = post_obj.getlist('author_id')
print(title, price, publish_date, publish_id, author_id, edit_id)
book_obj = models.Book.objects.filter(pk=edit_id)
book_obj.update(title=title, price=price, publish_date=publish_date, publish_id=publish_id)
book_obj.first().author.set(author_id)
return redirect('book_list')
book_obj = models.Book.objects.filter(pk=edit_id).first()
publish_queryset = models.Publish.objects.all()
author_queryset = models.Author.objects.all()
return render(request, 'book_edit.html', locals())

6. 删除数据
0. book_list中绑定删除键的页面跳转 携带书籍的主键
1. 路由中有有名分组获取删除之间的id并传给后端
2. 视图函数直接获取书籍列表对象然后通过获取的之间id删除该图书.
3. 删除数据后跳转到图书列表中
<a href="{% url 'book_delete' book_obj.pk %}" class="btn btn-danger btn-sm">删除</a>
url(r'^book_delete/(?P<del_id>\d+)/', views.book_delete, name='book_delete'),
def book_delete(request, del_id):
models.Book.objects.filter(pk=del_id).delete()
return redirect('book_list')
7. 前端修改页面
home.html主页 83 84 行删除
写一个js替换body的背景颜色.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图书管理系统</title>
{% load static %}
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
<style>
.body_color {
background-color: #d4ff00;
}
{% block css %}
{% endblock %}
</style>
</head>
<body id="body">
<div>
<div>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<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="#">图书馆</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<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="#">Python</a></li>
<li><a href="#">MySQL</a></li>
<li><a href="#">Linux</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="#">收藏本页面</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 id="green"><a>护眼模式</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-md-3">
<div class="list-group">
<a href="http://127.0.0.1:8000/" class="list-group-item list-group-item-success">首页</a>
<a href="{% url 'book_list' %}" class="list-group-item list-group-item-info">图书列表</a>
<a href="{% url 'book_add' %}" class="list-group-item list-group-item-warning">添加书籍</a>
</div>
</div>
<div class="col-md-9">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">图书管理系统</h3>
</div>
<div class="panel-body">
{% block html %}
<div>
<div id="carousel-example-generic" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carousel-example-generic" data-slide-to="0"
class="active"></li>
<li data-target="#carousel-example-generic" data-slide-to="1"></li>
<li data-target="#carousel-example-generic" data-slide-to="2"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="item active">
<img src="https://s2.loli.net/2022/03/10/CNJFHvDlquibBda.jpg" alt="...">
</div>
<div class="item">
<img src="https://s2.loli.net/2022/03/10/AWzJVDgPKlc8OZt.jpg" alt="...">
</div>
<div class="item">
<img src="https://s2.loli.net/2022/03/10/IZlAELwBqPFjspU.jpg" alt="...">
</div>
</div>
<a class="left carousel-control" href="#carousel-example-generic" role="button"
data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#carousel-example-generic" role="button"
data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
<div>
<div class="row">
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://s2.loli.net/2022/03/10/I4ziahsHbWCAkJU.jpg" alt="...">
<div class="caption">
<h3>Python</h3>
<p>由荷兰数学和计算机科学研究学会的吉多·范罗苏姆 于1990
年代初设计,作为一门叫做ABC语言的替代品。Python提供了高效的高级数据结构,还能简单有效地面向对象编程...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a
href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://s2.loli.net/2022/03/10/fFm9Lu2hkQRoJNg.jpg" alt="...">
<div class="caption">
<h3>MySQL</h3>
<p>是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 RDBMS(Relational Database
Management System:关系数据库管理系统)应用软件之一...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a
href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://s2.loli.net/2022/03/10/8ojETnzqRkLyG6h.jpg" alt="...">
<div class="caption">
<h3>Linux</h3>
<p>
全称GNU/Linux,是一套免费使用和自由传播的类UNIX操作系统,它主要受到Minix和Unix思想的启发,是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a
href="#" class="btn btn-default" role="button">Button</a></p>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
</div>
</div>
</div>
</div>
</div>
</div>
<script>
var liEle = document.getElementById('green')
liEle.onclick = function(){
var bodyEle = document.getElementById('body')
bodyEle.classList.toggle('body_color')
}
{% block js %}
{% endblock %}
</script>
</body>
</html>
|