1. 搭建环境 1.1 创建数据库 Django本身不会自动创建数据库服务器或数据库实例, 这一步需要手动完成. 可以使用Navicat可视化工具或者命令行创建'library'数据库, 编码格式为utf8_mp4. # 连接数据库 mysql -h localhost -P 3306 -u root -p123456 # 创建library数据库并设置编码 create database library character set utf8mb4; # 查看MySQL的编码(utf8mb4) show variables like 'character_set_database'; # 查看library数据库的编码(utf8mb4) show create database library;
1.2 创建Django项目 使用Pychamr工具创建Django项目. 项目名称: MyDjango . 应用名称: library .
1.3 连接MySQL数据库 编辑Django的settings.py配置文件, 使用MySQL数据库, 配置信息如下: # 数据库配置 DATABASES = { 'default': { # 使用mysql数据库 'ENGINE': 'django.db.backends.mysql', # ip地址 'HOST': '127.0.0.1', # 端口号 'POST': 3306, # 登入用户 'USER': 'root', # 登入密码 'PASSWORD': '123456', # 连接的库 'NAME': 'library', # 设置编码 'CHARSET': 'utf8mb4' } }
1.4 创建表模型 * 1. 作者表(主表)一对一作者详情表(次表), 外键建立在作者详情表中名为author. * 2. 出版社(一)一对多书籍表(多), 外键字段建立在多的一方书籍表中名为publish. * 3. 作者表多对多书籍表, 外键字段建立在查询频率高的一方书籍表中名为author. 1.4.1 作者表 作者表拥有id, name, age三个字段. # library/models.py from django.db import models # 作者表模型 class Author(models.Model): # id字段(自动添加) name = models.CharField(max_length=12, verbose_name='作者名称') age = models.IntegerField(verbose_name='作者年龄') def __str__(self): return f'{self.name}'
1.4.2 作者详情表 作者详情表拥有id, phone, addr, author_id四个字段. # 作者详情表模型 class AuthorDetail(models.Model): # id字段(自动添加) phone = models.CharField(max_length=11, verbose_name='手机号码') addr = models.CharField(max_length=32, verbose_name='作者住址') # 外键字段(一对一关联作者表实例, 并设置级联删除) author = models.OneToOneField(to='Author', on_delete=models.CASCADE, related_name='author_detail', verbose_name='作者名称') def __str__(self): return f'{self.id}'
1.4.3 出版社表 出版社表拥有id, name, email, 三个字段. # 出版社表模型 class Publish(models.Model): # id字段(自动添加) name = models.CharField(max_length=12, verbose_name='出版社名称') addr = models.CharField(max_length=32, verbose_name='出版社地址') email = models.EmailField(verbose_name='出版社邮箱') def __str__(self): return f'{self.name}'
1.4.4 书籍表模型 书籍表表拥有id, title, price, publication_date, publish, author六个字段. # 书籍表模型 class Book(models.Model): # id字段(自动添加) title = models.CharField(max_length=32, verbose_name='书籍名称') price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='书籍价格') publication_date = models.DateField(auto_now_add=True, verbose_name='书籍发布日期') # 外键字段 # 一对多出版社 publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE, verbose_name='出版社名称') # 多对多作者表 author = models.ManyToManyField(to=Author, verbose_name='作者列表') def __str__(self): return f'{self.title}'
书籍作者关联表会自动创建有id. book_id, author_id三个字段. 1.4.5 完整代码 from django.db import models # 作者表模型 class Author(models.Model): # id字段(自动添加) name = models.CharField(max_length=12, verbose_name='作者名称') age = models.IntegerField(verbose_name='作者年龄') def __str__(self): return f'{self.name}' # 作者详情表模型 class AuthorDetail(models.Model): # id字段(自动添加) phone = models.CharField(max_length=11, verbose_name='手机号码') addr = models.CharField(max_length=32, verbose_name='作者住址') # 外键字段(一对一关联作者表实例, 并设置级联删除) author = models.OneToOneField(to='Author', on_delete=models.CASCADE, related_name='author_detail', verbose_name='作者名称') def __str__(self): return f'{self.id}' # 出版社表模型 class Publish(models.Model): # id字段(自动添加) name = models.CharField(max_length=12, verbose_name='出版社名称') addr = models.CharField(max_length=32, verbose_name='出版社地址') email = models.EmailField(verbose_name='出版社邮箱') def __str__(self): return f'{self.name}' # 书籍表模型 class Book(models.Model): # id字段(自动添加) title = models.CharField(max_length=32, verbose_name='书籍名称') price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='书籍价格') publication_date = models.DateField(auto_now_add=True, verbose_name='书籍发布日期') # 外键字段 # 一对多出版社 publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE, verbose_name='出版社名称') # 多对多作者表 author = models.ManyToManyField(to=Author, verbose_name='作者列表') def __str__(self): return f'{self.title}' 1.4.6 数据库迁移 # 在终端执行数据库迁移命令 PS D:\MyDjango> python manage.py makemigrations Migrations for 'library': library\migrations\0001_initial.py - Create model Author - Create model Publish - Create model Book - Create model AuthorDetail # 不知道为什么这里没有添加外键的提示??? PS D:\MyDjango> python manage.py migrate ...
使用Navicat工具查询创建的表格.
逆向数据库到模型.
1.5 创建表记录 在Django ORM中, 执行数据库操作时, 通常不会直接返回一个'成功'的消息, 而是通过返回的结果或是否抛出异常来判断操作是否成功. 1.5.1 作者表记录 import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MyDjango.settings") import django django.setup() from library.models import Author # 创建作者列表 author_list = [ Author(name='aa', age=18), Author(name='bb', age=19), Author(name='cc', age=20), ] # 批量创建作者实例 res = Author.objects.bulk_create(author_list) print(res)
1.5.2 作者详情表记录 idphoneaddrauthor_id1111北京12222上海23333深圳3
import os if __name__ == "__main__": os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MyDjango.settings') import django django.setup() from library.models import AuthorDetail # 创建作者详情列表, 这里外键字段直接使用id值. author_detail_list = [ AuthorDetail(phone='111', addr='北京', author_id=1), AuthorDetail(phone='222', addr='上海', author_id=2), AuthorDetail(phone='333', addr='深圳', author_id=3), ] # 批量创建作者详细实例 res = AuthorDetail.objects.bulk_create(author_detail_list) print(res)
在Django中, bulk_create方法用于批量创建对象, 这样可以减少数据库操作次数, 提高性能. 但是, 使用bulk_create方法创建对象时, 这些对象在Python层面的实例并不会立即获得数据库中的ID. 这是因为bulk_create方法并不会立即对这些对象进行数据库查询以获取它们的ID. 1.5.3 出版社表记录 idnameaddremail1北京出版社北京bj@qq.com2上海出版社上海sh@qq.com3深圳出版社深圳sz@qq.com
import os if __name__ == "__main__": os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MyDjango.settings') import django django.setup() from library.models import Publish # 创建出版社实例列表 publish_list = [ Publish(name='北京出版社', addr='北京', email='bj@qq.com'), Publish(name='上海出版社', addr='上海', email='sh@qq.com'), Publish(name='深圳出版社', addr='深圳', email='sz@qq.com'), ] # 批量创建出版社实例 res = Publish.objects.bulk_create(publish_list) print(res)
1.5.4 书籍表记录 idtitlepricepublication_datepublish_idauthor_id1Python100.01自动生成1[1]2MySQL200.02自动生成2[2]3Linux300.03自动生成3[3]4HTML400.04自动生成1[1 ,2]
import os if __name__ == "__main__": os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MyDjango.settings') import django django.setup() from library.models import Book # 创建书籍实例列表 book_list = [ Book(title='Python', price=100.01, publish_id=1), Book(title='MySQL', price=200.02, publish_id=2), Book(title='Linux', price=300.03, publish_id=3), Book(title='HTML', price=400.04, publish_id=1) ] # 批量创建书籍实例 res = Book.objects.bulk_create(book_list) print(res)
这里的对象不能使用外键, 例如: book1 = Book(title='Python', price=100.01, publish_id=1) book1.author.set([1]) # 视图在创建对象后使用外键设置多对多关联表的信息, 然后报错: ValueError: "" needs to have a value for field "id" before this many-to-many relationship can be used. ValueError: "" 需要先为字段 "id" 提供值, 然后才能使用此多对多关系. 这是因为Django的多对多关系是通过一个额外的表来实现的, 这个表需要存储关联的两个对象的主键. 如果一个对象还没有保存到数据库, 它就没有主键, 因此无法建立多对多关系. 1.5.5 书籍作者关联表 idbook_idauthor_id111222333441542
在Django中, 当使用ManyToManyField字段时, Django会自动创建一个中间表来管理多对多关系. 然而, 这个中间表并没有直接暴露为一个模型, 因此不能像操作其他模型那样直接操作它. 如果需要访问或修改中间表的数据, 应该通过ManyToManyField提供的API来进行, 比如使用: add(), remove(), set()和clear()等方法. 这些方法会自动处理中间表的数据, 而不需要直接操作它. # 这种方式需要多次查询数据库 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) 使用in查询来一次性获取多本书, 然后遍历这些书并为它们添加作者. 这样可以减少数据库查询的次数, 从而提高效率. import os if __name__ == "__main__": os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MyDjango.settings') import django django.setup() from library.models import Book # 执行一次查询 books = Book.objects.filter(pk__in=[1, 2, 3, 4]) for book in books: if book.pk == 1: res = book.author.add(1) # 第一本书添加ID为1的作者 print(res) elif book.pk == 2: res = book.author.add(2) # 第二本书添加ID为2的作者 print(res) elif book.pk == 3: res = book.author.add(3) # 第三本书添加ID为3的作者 print(res) elif book.pk == 4: res = book.author.add(1, 2) # 第四本书添加ID为1, 2的作者 print(res)
1.6 静态文件配置 项目中需要使用到jQuery(3.7.1)框架与bootstrap(3.3.7)框架. jQuery文件下载地址: https://code.jquery.com/jquery-3.7.1.min.js , 将代码复制到本地文件. bootstrap框架下载地址: https://v3.bootcss.com/getting-started/#download . 静态文件配置步骤: * 1. 项目目录下创建static目录. * 2. settings.py配置文件中开放静态文件的路径. STATIC_URL = '/static/' # 静态文件目录 STATICFILES_DIRS = [ BASE_DIR / 'static' ]
* 3. static目录下创建js目录, 复制jQuery文件到js目录中. * 4. 复制bootstrap到static目录下.
2. 主页 * 1. 在项目配置目录的路由文件中设置路由分发. * 2. 在应用的目录下创建子路由文件. * 3. 编写路由与视图函数的对应关系. * 4. 在视图层中写视图函数处理请求. * 5. 编写视图函数放回的主页面. 2.1 路由层 在项目配置目录的路由文件中设置路由分发. # MyDjango/MyDjango/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), # 设置子路由 path('', include(('library.urls', 'library'), namespace='library')) ]
在应用的目录下创建子路由文件并编写路由与视图函数的对应关系, 主页面使用根目录(/), 也就是: http://127.0.0.1:8000/ . # library/urls.py from django.urls import path from library.views import home urlpatterns = [ # 主页面 path('', home, name='library') ]
2.2 视图层 主页面视图返回一个home主页面. # library/view.py from django.shortcuts import render # 主页面视图 def home(request): return render(request, 'home.html', locals())
2.3 模板层 2.3.1 模板页面 1. 在templates目录下创建base模板页面. 2. 在页面中导入jQuery与bootstrap文件. 3. 在页面中划分css, html, js三个块, 用于模板继承. 4. 在templates目录下创建home页面并继承base模板页面. 图书管理系统 {% load static %} {% block css %} {% endblock %} {% block html %} {% endblock %} {% block js %} {% endblock %}
{% extends "base.html" %}
2.3.2 导航栏 在base模板页面中添加一个导航条, 代码如下(这里只是为了装饰页面, 大部分功能没有实现):
启动项目, 访问: http://127.0.0.1:8000/ , 目前的主页面效果如下:
2.3.3 页面内容 * 1. 页面内容使用栅格布局3-9分. * 2. 栅格左边部分存放一个功能选项侧边栏并存放多个功能选项, 还实现点击列表项时使其高亮显示. * 3. 栅格右边部分放一个功能展示面板, 面板含有面板标题和面板内容两个区域, 将面板内容作为可替换区域.
{% block panel_title %} {% endblock %} {% block panel_body %} {% endblock %}
这段代码的主要作用是在网页上创建一个带有响应式布局的侧边栏或导航栏, 用于引导用户访问网站的不同部分或功能. 其中包含了五个链接选项: '首页', '图书列表', '出版社列表', '作者列表'和'更多'. 而内容展示区则通过面板来展示链接选项的内容. 启动项目, 访问: http://127.0.0.1:8000/ , 目前的主页面效果如下:
为列表项添加模板标签, 根据请求的URL来决定哪个列表项应该被高亮(active类为激活状态有高亮效果, disabled为禁用状态不可选中).
启动项目, 访问主页: 127.0.0.1:8000 , 查看高亮效果:
列表项的a标签通过反向解析生成url, 必须先在路由层创建好路由, 模板层中才能使用, 否则会报错. 还没有填写url地址的列表项还不能点击. 2.3.4 主页面板 主页面面板是访问主页面默认展示的信息. 在home页面中继承base.html页面, 并重新定义css, panel_title, panel_body三个块的内容. 在css块中自定义一个响应式类, 确保图片在不同屏幕尺寸下保持良好的布局和显示. 在panel_title块中定义面板的名称. 在panel_body块中展示一个一个轮转图和三张缩略图. 轮转图的三张图片连接: 1. https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fs2.loli.net%2F2022%2F03%2F10%2FCNJFHvDlquibBda.jpg&pos_id=img-S9SIts4y-1722648817610) 2. https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fs2.loli.net%2F2022%2F03%2F10%2FAWzJVDgPKlc8OZt.jpg&pos_id=img-ZCuvdZg2-1722648821936) 3. https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fs2.loli.net%2F2022%2F03%2F10%2FIZlAELwBqPFjspU.jpg&pos_id=img-jb56HOte-1722648831450) 缩略图的三张图片连接: 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
主页的信息就不写进去数据库了直接在html中写(懒). {% extends "base.html" %} {% block css %} {% endblock %} {% block panel_title %}主页功能展示{% endblock %} {% block panel_body %} Python 由荷兰数学和计算机科学研究学会的吉多·范罗苏姆于1990年代初设计, 作为一门叫做ABC语言的替代品. Python提供了高效的高级数据结构, 还能简单有效地面向对象编程...
关注 收藏
MySQL 是最流行的关系型数据库管理系统, 在WEB应用方面MySQL是最好的RDBMS(关系数据库管理系统)应用软件之一...
关注 收藏
Linux 全称GNU/Linux, 是一套免费使用和自由传播的类UNIX操作系统, 它主要受到Minix和Unix思想的启发, 是一个基于POSIX和Unix的多用户, 多任务, 支持多线程和多CPU的操作系统...
Button Button
{% endblock %}
启动项目, 访问: http://127.0.0.1:8000/ , 主页面效果如下:
3. 书籍列表 3.1 路由层 在子路由中添加一个路由, 当用户访问: 127.0.0.1:8000/book_list时展示书籍信息. # library/urls.py from django.urls import path from library.views import home, book_list urlpatterns = [ # 主页面 path('', home, name='library'), # 书籍列表 path('book_list', book_list, name='book_list') ]
3.2 视图层 视图函数中读取数据库中的所有的书籍实例并返回给book_list页面(现在数量量少, 先不考虑分页的问题). # library/views.py from django.shortcuts import render # 导入模型 from library.models import Book # 书籍列表 def book_list(request): # 读取所有书籍实例 books = Book.objects.all() # 返回页面与书籍实例 return render(request, 'book_list.html', locals())
3.3 模板层 书籍列表面板展示所有书籍的信息. 1. 在侧边栏的书籍列表中绑定访问地址为. 2. 在templates目录下创建book_list.html页面. 3. 在书籍列表页面中继承base.html页面, 并重新定义css, panel_title, panel_body三个块的内容. 4. 在css块中自定义一个类, 让表格的每行文字垂直对齐(默认向上对齐不怎么好看). 5. 在panel_title块中定义面板的名称. 6. 在panel_body块中使用表格展示书籍信息, 表单展示的信息如下: 序号编号书名作者出版社出版日期价格操作按钮1书籍id号唯一可能有多个唯一唯一唯一编辑删除
书籍列表
{% extends "base.html" %} {% block css %} {% endblock %} {% block panel_title %}书籍信息{% endblock %} {% block panel_body %} 序号 编号 书名 作者 出版社 出版时间 价格 操作 {% for book in books %} {{ forloop.counter }} {{ book.pk }} {{ book.title }} {% for author_obj in book.author.all %} {% if forloop.last %} {{ author_obj.name }} {% else %} {{ author_obj.name }}, {% endif %} {% endfor %} {{ book.publish.name }} {{ book.publication_date|date:'Y-m-d' }} {{ book.price }} 编辑 删除 {% endfor %}
{% endblock %}
启动项目, 访问: http://127.0.0.1:8000/book_list , 书籍列表页面效果如下:
4. 添加书籍 4.1 路由层 在子路由中添加一个路由, 当用户访问: 127.0.0.1:8000/book_add时展示书籍添加页面. # library/urls.py from django.urls import path from library.views import home, book_list, book_add urlpatterns = [ # 主页面 path('', home, name='library'), # 书籍列表 path('book_list', book_list, name='book_list'), # 书籍添加 path('book_add', book_add, name='book_add') ]
4.2 视图层 先分析添加书籍表单中需要的信息: * 1. id字段 , 自增不用管. * 2. title书名字段, 需要表单提供. * 3. price书籍价格字段, 需要表单提供. * 4. publication_date出版时间, 自动添加不用管. * 5. 外键字段publish, 使用已经存在的出版社. * 6. 外键字段author, 使用已经存在的作者. 视图需要读取数据库中的作者表和出版社表的数据再与添加图书页面一同返回. # library/views.py from django.shortcuts import render # 导入模型 from library.models import Book, Publish, Author def book_add(request): # 获取所有的出版社实例 publishing = Publish.objects.all() # 获取所有的作者实例 authors = Author.objects.all() return render(request, 'book_add.html', locals())
4.3 模板层 1. 在base.html模板页面的侧边栏中添加一个列表项. 2. 在templates目录下创建book_add.html页面. 3. 在添加书籍页面中继承base.html页面, 并重新定义panel_title, panel_body两个块的内容. 4. 在panel_title块中定义面板的名称. 5. 在panel_body块中添加一个表单用于收集书籍信息, 收集的信息如下: * 1. id字段 , 自增不用管. * 2. title书名字段, 需要表单提供, 使用input输入框, 名称为: title. * 3. price书籍价格字段, 需要表单提供, 使用input输入框, 名称为: price. * 4. publication_date出版时间字段, 自动添加(数据插入的时间). * 5. 外键字段publish, 使用已经存在的出版社, 使用下拉框, 名称为: publish_id, 并设置单选, 展示的是出版社的名称提交的是出版社id. * 6. 外键字段author, 使用已经存在的作者, 使用下拉框, 名称为: publish_id, 并设置多选, 展示的是作者的名称提交的是作者id. 添加书籍
{% extends "base.html" %} {% block panel_title %} 书籍添加 {% endblock %} {% block panel_body %} {% endblock %}
启动项目, 访问: http://127.0.0.1:8000/book_add , 查看添加书籍页面的效果:
4.4 写入数据 1. 修改视图函数, 从POST请求提交的表单中获取书籍信息. 2. 需要为两张表写入数据(表单中提交的数据都是字符串, 在写入数据库的时候会自动转换类型.) 首先, 往书籍表中写数据(需要为title, price, publish_id三个字段提供值). 最后, 使用书籍对象的author外键字段获取到书籍作者关联表, 再使用set()方法添加多对多关联. set()方法允许传递一个可迭代对象(比如列表, 元组等), 它会遍历这个可迭代对象, 并逐个添加其中的元素. 3. 写入成功后重定向到书籍列表页面. # library/views.py from django.shortcuts import render, redirect # 导入模型 from library.models import Book, Publish, Author # 添加书籍 def book_add(request): # 处理GET请求: if request.method == 'GET': # 获取所有的出版社实例 publishing = Publish.objects.all() # 获取所有的作者实例 authors = Author.objects.all() return render(request, 'book_add.html', locals()) # 处理POST请求: if request.method == 'POST': # 获取书籍信息 title = request.POST.get('title') price = request.POST.get('price') publish_id = request.POST.get('publish_id') # 作者id有多个, 通过getlist方法获取, 值是一个列表 author_id = request.POST.getlist('author_id') # 数据校验跳过 # print(title, price, publish_id, author_id) # 创建书籍实例 book = Book.objects.create(title=title, price=price, publish_id=publish_id) # # 添加多对多关联 book.author.set(author_id) # 重定向到书籍列表页面 return redirect('/book_list')
启动项目, 访问: http://127.0.0.1:8000/book_add , 填写信息并提交.
实例添加成功之后, 会跳转到书籍列表页面, 可以查看新添加的书籍记录.
5. 书籍修改 编辑书籍信息的思路: * 1. 给编辑按钮绑定请求地址, 在书籍列表中点击修改时, 提交一个get请求, 并携带书籍的id. * 2. 路由中使用转换器获取id值并传递给视图函数. * 3. 后端处理请求, 并通过书籍id获取对应书籍实例数据, 返回一个书籍修改页面和需要修改的书籍实例. * 4. 书籍修改页面中展示一个表单, 表单中展示可修改的书籍信息. 5.1 路由层 在子路由中添加一个路由, 当用户访问: 127.0.0.1:8000/book_set/id时展示书籍修改页面. 请求地址携带了书籍id, 可以通过内置的转换器来捕获获取这个值. # library/urls.py from django.urls import path from library.views import home, book_list, book_add, book_set urlpatterns = [ # 主页面 path('', home, name='library'), # 书籍列表 path('book_list', book_list, name='book_list'), # 书籍添加 path('book_add', book_add, name='book_add'), # 书籍修改 path('book_set/', book_set, name='book_set') ]
5.2 视图层 修改数据页面需要获取所有的出版社信息和作者信息和修改的书籍信息, 在视图中获取并返回. # library/views.py # 书籍修改, 需要接收内置转换器传递的参数 def book_set(request, book_id): # 处理GET请求: if request.method == 'GET': # 获取所有的出版社实例 publishing = Publish.objects.all() # 获取所有的作者实例 authors = Author.objects.all() # 获取书籍实例 book = Book.objects.filter(id=book_id).first() return render(request, 'book_set.html', locals())
5.3 模板层 在book_list.html页面中为编辑按钮绑定跳转地址, 提交的get请求携带书籍实例的id. 编辑
在book_set.html页面中展示书籍实例的信息, 通过{% if %}标签可以对外键字段进行默认选中. {% extends "base.html" %} {% block panel_title %} 书籍信息修改 {% endblock %} {% block panel_body %} {% endblock %}
启动项目, 访问: 127.0.0.1:8000/book_list , 选中一书籍并点击编辑按钮.
点击编辑后访问: 127.0.0.1:8000/book_set/4 , 书籍修改页面展示如下:
5.4 修改数据 1. 修改视图函数, 从POST请求提交的表单中获取书籍信息. 2. 需要为两张表更新数据(表单中提交的数据都是字符串, 在写入数据库的时候会自动转换类型.) 首先, 获取书籍对象, 使用update更新字段: title, price, publish_id的值. 最后, 使用书籍对象的author外键字段获取到书籍作者关联表, 再使用set()方法修改多对多关联. set()方法允许传递一个可迭代对象(比如列表, 元组等), 它会遍历这个可迭代对象, 并逐个添加其中的元素. 3. 修改成功后重定向到书籍列表页面. # library/views.py # 书籍修改, 需要接收内置转换器传递的参数 def book_set(request, book_id): # 处理GET请求: if request.method == 'GET': # 获取所有的出版社实例 publishing = Publish.objects.all() # 获取所有的作者实例 authors = Author.objects.all() # 获取书籍实例 book = Book.objects.filter(id=book_id).first() return render(request, 'book_set.html', locals()) # 处理POST请求: if request.method == 'POST': # 获取书籍信息 title = request.POST.get('title') price = request.POST.get('price') publish_id = request.POST.get('publish_id') # 作者id有多个, 通过getlist方法获取, 值是一个列表 author_id = request.POST.getlist('author_id') # 数据校验跳过 # print(title, price, publish_id, author_id) # 获取书籍实例, update是queryset对象方法 query_set = Book.objects.filter(id=book_id) # 更新书籍实例 query_set.update(title=title, price=price, publish_id=publish_id) # 通过first()方法获取书籍实例, 在通过author外键更新多对多关联 query_set.first().author.set(author_id) # 重定向到书籍列表页面 return redirect('/book_list')
启动项目, 访问两次: 127.0.0.1:8000/book_list/4 , 获取书籍id为4的修改页面, 一个做参考一个做修改并提交请求.
修改成功之后, 跳转到书籍列表页面中, 查看修改后的书籍信息.
访问注点意: 修改页面的路由是: 'book_set/' . 视图函数的定义为: def book_set(request, book_id) . 点击编辑的时候, 访问book_set页面需要携带一个id值为路径, 视图函数也始终接收被转换器捕获的id值路径. 例如访问: 127.0.0.1:8000/book_list/4 , 返回一个书籍修改页面. 当修改信息完成后, 表单向当前的url地址(127.0.0.1:8000/book_list/4)提交POST请求. 上诉过程中, 请求地址中一直确保着book_id, 否则路由或book_set视图函数会出错. 6. 删除书籍 删除书籍信息的思路: * 1. 给删除按钮绑定请求地址, 在书籍列表中点击删除时, 提交一个get请求, 并携带书籍的id. * 2. 路由中使用转换器获取id值并传递给视图函数. * 3. 后端处理请求, 并通过书籍id删除对应书籍实例数据. * 4. 删除数据后跳转到图书列表中. 6.1 路由层 在子路由中添加一个路由, 当用户访问: 127.0.0.1:8000/book_delete/id时展示书籍修改页面. 请求地址携带了书籍id, 可以通过内置的转换器来捕获获取这个值. # library/urls.py from django.urls import path from library.views import home, book_list, book_add, book_set, book_delete urlpatterns = [ # 主页面 path('', home, name='library'), # 书籍列表 path('book_list', book_list, name='book_list'), # 书籍添加 path('book_add', book_add, name='book_add'), # 书籍修改 path('book_set/', book_set, name='book_set'), # 书籍删除 path('book_delete/', book_delete, name='book_delete'), ]
6.2 视图层 在视图直接通过书籍id删除实例, 然后重定向到书籍列表页面. # library/views.py # 书籍删除 def book_delete(request, book_id): # 通过书籍主键删除实例 Book.objects.filter(id=book_id).delete() # 重定向到书籍列表页面 return redirect('/book_list')
6.3 模型层 在book_list.html页面中为删除按钮绑定跳转地址, 提交的get请求携带书籍实例的id. 删除
启动项目, 访问: 127.0.0.1:8000/book_list, 选中一个书籍实例并点击删除.
删除成功之后, 跳转到书籍列表页面中, 查看删除后的书籍信息.
7. 页面背景 在模板页面中写写一个js替换body的背景颜色.
启动项目, 访问任意一个页面, 例: 127.0.0.1:8000/book_list , 在导航栏中设置页面的背景颜色, 刷新页面则恢复默认的白色.
出版社列表与作者表有兴趣自己去完善.