Django本身不会自动创建数据库服务器或数据库实例 ,  这一步需要手动完成 . 
可以使用Navicat可视化工具或者命令行创建 'library' 数据库 ,  编码格式为utf8_mp4 . 
mysql - h localhost - P 3306  - u root - p123456
create database library character set  utf8mb4; 
show variables like 'character_set_database' ; 
show create database library; 
 
使用Pychamr工具创建Django项目 . 
项目名称 :  MyDjango  . 
应用名称 :  library  . 
 
编辑Django的settings . py配置文件 ,  使用MySQL数据库 ,  配置信息如下 : 
DATABASES =  { 
    'default' :  { 
        
        'ENGINE' :  'django.db.backends.mysql' , 
        
        'HOST' :  '127.0.0.1' , 
        
        'POST' :  3306 , 
        
        'USER' :  'root' , 
        
        'PASSWORD' :  '123456' , 
        
        'NAME' :  'library' , 
        
        'CHARSET' :  'utf8mb4' 
    } 
} 
 
*  1.  作者表 ( 主表 ) 一对一作者详情表 ( 次表 ) ,  外键建立在作者详情表中名为author . 
*  2.  出版社 ( 一 ) 一对多书籍表 ( 多 ) ,  外键字段建立在多的一方书籍表中名为publish . 
*  3.  作者表多对多书籍表 ,  外键字段建立在查询频率高的一方书籍表中名为author . 
作者表拥有id ,  name ,  age三个字段 . 
from  django. db import  models
class  Author ( models. Model) : 
    
    name =  models. CharField( max_length= 12 ,  verbose_name= '作者名称' ) 
    age =  models. IntegerField( verbose_name= '作者年龄' ) 
    def  __str__ ( self) : 
        return  f' { self. name} ' 
 
作者详情表拥有id ,  phone ,  addr ,  author_id四个字段 . 
class  AuthorDetail ( models. Model) : 
    
    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 } ' 
 
出版社表拥有id ,  name ,  email ,  三个字段 . 
class  Publish ( models. Model) : 
    
    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} ' 
 
书籍表表拥有id ,  title ,  price ,  publication_date ,  publish ,  author六个字段 . 
class  Book ( models. Model) : 
    
    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三个字段 . 
from  django. db import  models
class  Author ( models. Model) : 
    
    name =  models. CharField( max_length= 12 ,  verbose_name= '作者名称' ) 
    age =  models. IntegerField( verbose_name= '作者年龄' ) 
    def  __str__ ( self) : 
        return  f' { self. name} ' class  AuthorDetail ( models. Model) : 
    
    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) : 
    
    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) : 
    
    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} ' 
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工具查询创建的表格 . 
 
逆向数据库到模型 . 
 
在Django  ORM中 ,  执行数据库操作时 ,  通常不会直接返回一个 '成功' 的消息 ,  而是通过返回的结果或是否抛出异常来判断操作是否成功 . 
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) 
 
 
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
    
    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 . 
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) 
 
 
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 :  "<Book: Python>"  needs  to  have  a  value  for  field  "id"  before  this  many-to-many  relationship  can  be  used . 
ValueError :  "<Book: Python>"  需要先为字段  "id"  提供值 ,  然后才能使用此多对多关系 . 
这是因为Django的多对多关系是通过一个额外的表来实现的 ,  这个表需要存储关联的两个对象的主键 . 
如果一个对象还没有保存到数据库 ,  它就没有主键 ,  因此无法建立多对多关系 . 
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 )   
            print ( res) 
        elif  book. pk ==  2 : 
            res =  book. author. add( 2 )   
            print ( res) 
        elif  book. pk ==  3 : 
            res =  book. author. add( 3 )   
            print ( res) 
        elif  book. pk ==  4 : 
            res =  book. author. add( 1 ,  2 )   
            print ( res) 
	
 
 
项目中需要使用到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目录下 . 
 
*  1.  在项目配置目录的路由文件中设置路由分发 . 
*  2.  在应用的目录下创建子路由文件 . 
*  3.  编写路由与视图函数的对应关系 . 
*  4.  在视图层中写视图函数处理请求 . 
*  5.  编写视图函数放回的主页面 . 
在项目配置目录的路由文件中设置路由分发 . 
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 /  .  
from  django. urls import  path
from  library. views import  home
urlpatterns =  [ 
    
    path( '' ,  home,  name= 'library' ) 
] 
 
主页面视图返回一个home主页面 . 
from  django. shortcuts import  render
def  home ( request) : 
    return  render( request,  'home.html' ,  locals ( ) ) 
 
1.  在templates目录下创建base模板页面 . 
2.  在页面中导入jQuery与bootstrap文件 . 
3.  在页面中划分css ,  html ,  js三个块 ,  用于模板继承 . 
4.  在templates目录下创建home页面并继承base模板页面 . 
<! DOCTYPE  html > < htmllang = " en" > < head> < metacharset = " UTF-8" > < title> </ title> < scriptsrc = " {% static 'js/jquery.js' %}" > </ script> < linkrel = " stylesheet" href = " {% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}" > < scriptsrc = " {% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}" > </ script> </ head> < bodyclass = " container-fluid" > </ body> </ html> 
 
{% extends "base.html" %}
 
在base模板页面中添加一个导航条 ,  代码如下 ( 这里只是为了装饰页面 ,  大部分功能没有实现 ) : 
< navclass = " navbar bg-info" > < divclass = " container-fluid" > < divclass = " navbar-header" > < buttontype = " button" class = " navbar-toggle collapsed" data-toggle = " collapse" data-target = " #bs-example-navbar-collapse-1" aria-expanded = " false" > < spanclass = " sr-only" > </ span> < spanclass = " icon-bar" > </ span> < spanclass = " icon-bar" > </ span> < spanclass = " icon-bar" > </ span> </ button> < aclass = " navbar-brand" href = " #" > </ a> </ div> < divclass = " collapse navbar-collapse" id = " bs-example-navbar-collapse-1" > < ulclass = " nav navbar-nav" > < liclass = " dropdown" > < ahref = " #" class = " dropdown-toggle" data-toggle = " dropdown" role = " button" aria-haspopup = " true" aria-expanded = " false" > < spanclass = " caret" > </ span> </ a> < ulclass = " dropdown-menu" > < li> < ahref = " #" > </ a> </ li> < li> < ahref = " #" > </ a> </ li> < li> < ahref = " #" > </ a> </ li> </ ul> </ li> </ ul> < formclass = " navbar-form navbar-left" > < divclass = " form-group" > < inputtype = " text" class = " form-control" placeholder = " 输入并搜索..." > </ div> < buttontype = " submit" class = " btn btn-default" > </ button> </ form> < ulclass = " nav navbar-nav navbar-right" > < li> < ahref = " #" > </ a> </ li> < liclass = " dropdown" > < ahref = " #" class = " dropdown-toggle" data-toggle = " dropdown" role = " button" aria-haspopup = " true" aria-expanded = " false" > < spanclass = " caret" > </ span> </ a> < ulclass = " dropdown-menu" > < li> < ahref = " #" > </ a> </ li> < li> < ahref = " #" > </ a> </ li> < li> < ahref = " #" > </ a> </ li> </ ul> </ li> </ ul> </ div> </ div> </ nav> 
 
启动项目 ,  访问 :  http : / / 127.0 .0 .1 : 8000 /  ,  目前的主页面效果如下 : 
 
*  1.  页面内容使用栅格布局 3 - 9 分 . 
*  2.  栅格左边部分存放一个功能选项侧边栏并存放多个功能选项 ,  还实现点击列表项时使其高亮显示 . 
*  3.  栅格右边部分放一个功能展示面板 ,  面板含有面板标题和面板内容两个区域 ,  将面板内容作为可替换区域 . 
< divclass = " row" > < divclass = " col-md-3" > < divclass = " list-group" > < ahref = " /" class = " list-group-item active" > </ a> < ahref = " #" class = " list-group-item" > </ a> < ahref = " #" class = " list-group-item" > </ a> < ahref = " #" class = " list-group-item" > </ a> < ahref = " #" class = " list-group-item" > </ a> </ div> </ div> < divclass = " col-md-9" > < divclass = " panel panel-primary" > < divclass = " panel-heading" > < h3class = " panel-title" > </ h3> </ div> < divclass = " panel-body" > </ div> </ div> </ div> </ div> 
 
这段代码的主要作用是在网页上创建一个带有响应式布局的侧边栏或导航栏 ,  用于引导用户访问网站的不同部分或功能 . 
其中包含了五个链接选项 :  '首页' ,  '图书列表' ,  '出版社列表' ,  '作者列表' 和 '更多' . 
而内容展示区则通过面板来展示链接选项的内容 . 
启动项目 ,  访问 :  http : / / 127.0 .0 .1 : 8000 /  ,  目前的主页面效果如下 : 
 
为列表项添加模板标签 ,  根据请求的URL来决定哪个列表项应该被高亮 ( active类为激活状态有高亮效果 ,  disabled为禁用状态不可选中 ) . 
< divclass = " list-group" > < ahref = " /" class = " list-group-item {% if request.path  == '/' %} active {% endif %}" > </ a> < ahref = " " class = " list-group-item {% if request.path == '/book_list' %} active {% endif %}" > </ a> < ahref = " #" class = " list-group-item {% if request.path == '/publish_list' %} active {% endif %}" > </ a> < ahref = " #" class = " list-group-item {% if request.path == '/author_list' %} active {% endif %}" > </ a> < ahref = " #" class = " list-group-item disabled" > </ a> </ div> 
 
启动项目 ,  访问主页 :  127.0 .0 .1 : 8000  ,  查看高亮效果 : 
 
列表项的a标签通过反向解析生成url ,  必须先在路由层创建好路由 ,  模板层中才能使用 ,  否则会报错 . 
还没有填写url地址的列表项还不能点击 . 
主页面面板是访问主页面默认展示的信息 . 
在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 % 3 A % 2 F % 2 Fs2 . loli . net % 2 F2022 % 2 F03 % 2 F10 % 2 FCNJFHvDlquibBda . jpg & pos_id = img-S9SIts4y- 1722648817610 ) 
2.  https : / / img-home . csdnimg . cn / images / 20230724024159. png?origin_url = https % 3 A % 2 F % 2 Fs2 . loli . net % 2 F2022 % 2 F03 % 2 F10 % 2 FAWzJVDgPKlc8OZt . jpg & pos_id = img-ZCuvdZg2- 1722648821936 ) 
3.  https : / / img-home . csdnimg . cn / images / 20230724024159. png?origin_url = https % 3 A % 2 F % 2 Fs2 . loli . net % 2 F2022 % 2 F03 % 2 F10 % 2 FIZlAELwBqPFjspU . 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 / 8 ojETnzqRkLyG6h . jpg 
 
 
 
主页的信息就不写进去数据库了直接在html中写 ( 懒 ) . 
{% extends "base.html" %}
{% block css %}
    < style> 
        
        .img-fluid  { 
            width :  100%; 
            height :  auto; 
        } 
     </ style> < div> < divid = " carousel-example-generic" class = " carousel slide" data-ride = " carousel" > < olclass = " carousel-indicators" > < lidata-target = " #carousel-example-generic" data-slide-to = " 0" class = " active" > </ li> < lidata-target = " #carousel-example-generic" data-slide-to = " 1" > </ li> < lidata-target = " #carousel-example-generic" data-slide-to = " 2" > </ li> </ ol> < divclass = " carousel-inner " role = " listbox" > < divclass = " item active " > < imgsrc = " 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)" alt = " ..." class = " img-fluid" > </ div> < divclass = " item" > < imgsrc = " 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)" alt = " ..." class = " img-fluid" > </ div> < divclass = " item" > < imgsrc = " 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)" alt = " ..." class = " img-fluid" > </ div> </ div> < aclass = " left carousel-control" href = " #carousel-example-generic" role = " button" data-slide = " prev" > < spanclass = " glyphicon glyphicon-chevron-left" aria-hidden = " true" > </ span> < spanclass = " sr-only" > </ span> </ a> < aclass = " right carousel-control" href = " #carousel-example-generic" role = " button" data-slide = " next" > < spanclass = " glyphicon glyphicon-chevron-right" aria-hidden = " true" > </ span> < spanclass = " sr-only" > </ span> </ a> </ div> </ div> < br> < div> < divclass = " row" > < divclass = " col-sm-6 col-md-4" > < divclass = " thumbnail" > < imgsrc = " https://s2.loli.net/2022/03/10/I4ziahsHbWCAkJU.jpg" alt = " ..." > < divclass = " caption" > < h3> </ h3> < p> </ p> < p> < ahref = " #" class = " btn btn-primary" role = " button" > </ a> < ahref = " #" class = " btn btn-default" role = " button" > </ a> </ p> </ div> </ div> </ div> < divclass = " col-sm-6 col-md-4" > < divclass = " thumbnail" > < imgsrc = " https://s2.loli.net/2022/03/10/fFm9Lu2hkQRoJNg.jpg" alt = " ..." > < divclass = " caption" > < h3> </ h3> < p> </ p> < p> < ahref = " #" class = " btn btn-primary" role = " button" > </ a> < ahref = " #" class = " btn btn-default" role = " button" > </ a> </ p> </ div> </ div> </ div> < divclass = " col-sm-6 col-md-4" > < divclass = " thumbnail" > < imgsrc = " https://s2.loli.net/2022/03/10/8ojETnzqRkLyG6h.jpg" alt = " ..." > < divclass = " caption" > < h3> </ h3> < p> </ p> < p> < ahref = " #" class = " btn btn-primary" role = " button" > </ a> < ahref = " #" class = " btn btn-default" role = " button" > </ a> </ p> </ div> </ div> </ div> </ div> </ div> 
 
启动项目 ,  访问 :  http : / / 127.0 .0 .1 : 8000 /  ,  主页面效果如下 : 
 
在子路由中添加一个路由 ,  当用户访问 :  127.0 .0 .1 : 8000 /book_list时展示书籍信息. 
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' ) 
] 
 
视图函数中读取数据库中的所有的书籍实例并返回给book_list页面 ( 现在数量量少 ,  先不考虑分页的问题 ) . 
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 ( ) ) 
 
书籍列表面板展示所有书籍的信息 . 
1.  在侧边栏的书籍列表中绑定访问地址为 . 
2.  在templates目录下创建book_list . html页面 . 
3.  在书籍列表页面中继承base . html页面 ,  并重新定义css ,  panel_title ,  panel_body三个块的内容 . 
4.  在css块中自定义一个类 ,  让表格的每行文字垂直对齐 ( 默认向上对齐不怎么好看 ) . 
5.  在panel_title块中定义面板的名称 . 
6.  在panel_body块中使用表格展示书籍信息 ,  表单展示的信息如下 : 
序号编号书名作者出版社出版日期价格操作按钮1书籍id号唯一可能有多个唯一唯一唯一编辑 删除
 
< ahref = " {% url 'library:book_list' %}" class = " list-group-item {% if request.path == '/book_list' %} active {% endif %}" > </ a> 
 
{% extends "base.html" %}
{% block css %}
    < style> 
        .table > tbody > tr > td  { 
            vertical-align :  middle; 
        <!-- 书籍信息在表格中垂直对齐 -->
        } 
     </ style> < tableclass = " 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> < tr> < td> </ td> < td> </ td> < td> </ td> < td> </ td> < td> </ td> < td> </ td> < td> </ td> < td> < ahref = " " class = " btn btn-primary btn-sm" > </ a> < ahref = " " class = " btn btn-danger btn-sm" > </ a> </ td> </ tr> </ tbody> </ table> 
 
启动项目 ,  访问 :  http : / / 127.0 .0 .1 : 8000 /book_list  ,  书籍列表页面效果如下 : 
 
在子路由中添加一个路由 ,  当用户访问 :  127.0 .0 .1 : 8000 /book_add时展示书籍添加页面. 
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' ) 
] 
 
先分析添加书籍表单中需要的信息 : 
*  1.  id字段  ,  自增不用管 . 
*  2.  title书名字段 ,  需要表单提供 .  
*  3.  price书籍价格字段 ,  需要表单提供 .                      
*  4.  publication_date出版时间 ,  自动添加不用管 .   
*  5.  外键字段publish ,  使用已经存在的出版社 . 
*  6.  外键字段author ,  使用已经存在的作者 . 
视图需要读取数据库中的作者表和出版社表的数据再与添加图书页面一同返回 . 
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 ( ) ) 
 
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 .  
< ahref = " {% url 'library:book_add' %}" class = " list-group-item {% if request.path == '/book_add' %} active {% endif %}" > </ a> 
 
{% extends "base.html" %}
{% block panel_title %} 书籍添加 {% endblock %}
{% block panel_body %}
    
    < formaction = " " method = " post" > < divclass = " input-group" > < spanclass = " input-group-addon" > </ span> < inputtype = " text" class = " form-control mt-5" placeholder = " 书籍名称" name = " title" > </ div> < br> < divclass = " input-group" > < spanclass = " input-group-addon" > </ span> < inputtype = " text" class = " form-control" placeholder = " 书籍价格" name = " price" > </ div> < br> < divclass = " input-group" > < spanclass = " input-group-addon" > </ span> < selectname = " publish_id" class = " form-control" > < optionselected  disabled  hidden > </ option> < optionvalue = " {{ publish.pk }}" > </ option> </ select> </ div> < br> < divclass = " input-group" > < spanclass = " input-group-addon" > </ span> < selectname = " author_id" multiple = " multiple" class = " form-control" > < optionvalue = " {{ author.pk }}" > </ option> </ select> </ div> < br> < p> < inputtype = " submit" value = " 添加" class = " btn btn-primary form-control" > </ p> </ form> 
 
启动项目 ,  访问 :  http : / / 127.0 .0 .1 : 8000 /book_add  ,  查看添加书籍页面的效果 : 
 
1.  修改视图函数 ,  从POST请求提交的表单中获取书籍信息 . 
2.  需要为两张表写入数据 ( 表单中提交的数据都是字符串 ,  在写入数据库的时候会自动转换类型 . ) 
   首先 ,  往书籍表中写数据 ( 需要为title ,  price ,  publish_id三个字段提供值 ) . 
   最后 ,  使用书籍对象的author外键字段获取到书籍作者关联表 ,  再使用set ( ) 方法添加多对多关联 . 
   set ( ) 方法允许传递一个可迭代对象 ( 比如列表 ,  元组等 ) ,  它会遍历这个可迭代对象 ,  并逐个添加其中的元素 . 
3.  写入成功后重定向到书籍列表页面 . 
from  django. shortcuts import  render,  redirect
from  library. models import  Book,  Publish,  Author
def  book_add ( request) : 
    
    if  request. method ==  'GET' : 
        
        publishing =  Publish. objects. all ( ) 
        
        authors =  Author. objects. all ( ) 
        return  render( request,  'book_add.html' ,  locals ( ) ) 
    
    if  request. method ==  'POST' : 
        
        title =  request. POST. get( 'title' ) 
        price =  request. POST. get( 'price' ) 
        publish_id =  request. POST. get( 'publish_id' ) 
        
        author_id =  request. POST. getlist( '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  ,  填写信息并提交 . 
 
实例添加成功之后 ,  会跳转到书籍列表页面 ,  可以查看新添加的书籍记录 . 
 
编辑书籍信息的思路 : 
*  1.  给编辑按钮绑定请求地址 ,  在书籍列表中点击修改时 ,  提交一个get请求 ,  并携带书籍的id . 
*  2.  路由中使用转换器获取id值并传递给视图函数 . 
*  3.  后端处理请求 ,  并通过书籍id获取对应书籍实例数据 ,  返回一个书籍修改页面和需要修改的书籍实例 . 
*  4.  书籍修改页面中展示一个表单 ,  表单中展示可修改的书籍信息 . 
在子路由中添加一个路由 ,  当用户访问 :  127.0 .0 .1 : 8000 /book_set/id时展示书籍修改页面. 
请求地址携带了书籍id ,  可以通过内置的转换器来捕获获取这个值 . 
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/<int:book_id>' ,  book_set,  name= 'book_set' ) 
] 
 
修改数据页面需要获取所有的出版社信息和作者信息和修改的书籍信息 ,  在视图中获取并返回 . 
def  book_set ( request,  book_id) : 
    
    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 ( ) ) 
 
在book_list . html页面中为编辑按钮绑定跳转地址 ,  提交的get请求携带书籍实例的id . 
< ahref = " {% url 'library:book_set'  book.pk %}" class = " btn btn-primary btn-sm" > </ a> 
 
在book_set . html页面中展示书籍实例的信息 ,  通过 { %  if  % } 标签可以对外键字段进行默认选中 . 
{% extends "base.html" %}
{% block panel_title %} 书籍信息修改 {% endblock %}
{% block panel_body %}
    
    < formaction = " " method = " post" > < divclass = " input-group" > < spanclass = " input-group-addon" > </ span> < inputtype = " text" class = " form-control mt-5" placeholder = " 书籍名称" name = " title" value = " {{ book.title }}" > </ div> < br> < divclass = " input-group" > < spanclass = " input-group-addon" > </ span> < inputtype = " text" class = " form-control" placeholder = " 书籍价格" name = " price" value = " {{ book.price }}" > </ div> < br> < divclass = " input-group" > < spanclass = " input-group-addon" > </ span> < selectname = " publish_id" class = " form-control" > < optionselected  value = " {{ publish.pk }}" > </ option> < optionvalue = " {{ publish.pk }}" > </ option> </ select> </ div> < br> < divclass = " input-group" > < spanclass = " input-group-addon" > </ span> < selectname = " author_id" multiple = " multiple" class = " form-control" > < optionselected  value = " {{ author.pk }}" > </ option> < optionvalue = " {{ author.pk }}" > </ option> </ select> </ div> < br> < p> < inputtype = " submit" value = " 提交" class = " btn btn-primary form-control" > </ p> </ form> 
 
启动项目 ,  访问 :  127.0 .0 .1 : 8000 /book_list  ,  选中一书籍并点击编辑按钮 . 
 
点击编辑后访问 :  127.0 .0 .1 : 8000 /book_set/ 4  ,  书籍修改页面展示如下 : 
 
1.  修改视图函数 ,  从POST请求提交的表单中获取书籍信息 . 
2.  需要为两张表更新数据 ( 表单中提交的数据都是字符串 ,  在写入数据库的时候会自动转换类型 . ) 
   首先 ,  获取书籍对象 ,  使用update更新字段 :  title ,  price ,  publish_id的值 .  
   最后 ,  使用书籍对象的author外键字段获取到书籍作者关联表 ,  再使用set ( ) 方法修改多对多关联 . 
   set ( ) 方法允许传递一个可迭代对象 ( 比如列表 ,  元组等 ) ,  它会遍历这个可迭代对象 ,  并逐个添加其中的元素 . 
3.  修改成功后重定向到书籍列表页面 . 
def  book_set ( request,  book_id) : 
    
    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 ( ) ) 
    
    if  request. method ==  'POST' : 
        
        title =  request. POST. get( 'title' ) 
        price =  request. POST. get( 'price' ) 
        publish_id =  request. POST. get( 'publish_id' ) 
        
        author_id =  request. POST. getlist( 'author_id' ) 
        
        
        
        query_set =  Book. objects. filter ( id = book_id) 
        
        query_set. update( title= title,  price= price,  publish_id= publish_id) 
        
        query_set. first( ) . author. set ( author_id) 
        
        return  redirect( '/book_list' ) 
 
启动项目 ,  访问两次 :  127.0 .0 .1 : 8000 /book_list/ 4  ,  获取书籍id为 4 的修改页面 ,  一个做参考一个做修改并提交请求 . 
 
修改成功之后 ,  跳转到书籍列表页面中 ,  查看修改后的书籍信息 . 
 
访问注点意 : 
修改页面的路由是 :  'book_set/<int:book_id>'  . 
视图函数的定义为 :  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视图函数会出错 . 
删除书籍信息的思路 : 
*  1.  给删除按钮绑定请求地址 ,  在书籍列表中点击删除时 ,  提交一个get请求 ,  并携带书籍的id . 
*  2.  路由中使用转换器获取id值并传递给视图函数 . 
*  3.  后端处理请求 ,  并通过书籍id删除对应书籍实例数据 . 
*  4.  删除数据后跳转到图书列表中 . 
在子路由中添加一个路由 ,  当用户访问 :  127.0 .0 .1 : 8000 /book_delete/id时展示书籍修改页面. 
请求地址携带了书籍id ,  可以通过内置的转换器来捕获获取这个值 . 
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/<int:book_id>' ,  book_set,  name= 'book_set' ) , 
    
    path( 'book_delete/<int:book_id>' ,  book_delete,  name= 'book_delete' ) , 
] 
 
在视图直接通过书籍id删除实例 ,  然后重定向到书籍列表页面 . 
def  book_delete ( request,  book_id) : 
    
    Book. objects. filter ( id = book_id) . delete( ) 
    
    return  redirect( '/book_list' ) 
 
在book_list . html页面中为删除按钮绑定跳转地址 ,  提交的get请求携带书籍实例的id . 
< ahref = " {% url 'library:book_delete'  book.pk %}" class = " btn btn-danger btn-sm" > </ a> 
 
启动项目 ,  访问 :  127.0 .0 .1 : 8000 /book_list,  选中一个书籍实例并点击删除 . 
 
删除成功之后 ,  跳转到书籍列表页面中 ,  查看删除后的书籍信息 . 
 
在模板页面中写写一个js替换body的背景颜色 . 
< script> 
    $ ( document) . ready ( function  ( )  { 
        
        $ ( '.dropdown-menu a' ) . click ( function  ( e )  { 
            e. preventDefault ( ) ;  
            
            var  $body =  $ ( 'body' ) ; 
            $body. removeClass ( 'bg-success bg-danger bg-warning' ) ; 
            
            var  text =  $ ( this ) . text ( ) ; 
            switch  ( text)  { 
                case  '浅绿色' : 
                    $body. addClass ( 'bg-success' ) ; 
                    break ; 
                case  '浅粉色' : 
                    $body. addClass ( 'bg-danger' ) ; 
                    break ; 
                case  '浅黄色' : 
                    $body. addClass ( 'bg-warning' ) ; 
                    break ; 
            } 
        } ) ; 
    } ) ; 
 </ script> 
 
启动项目 ,  访问任意一个页面 ,  例 :  127.0 .0 .1 : 8000 /book_list  ,  在导航栏中设置页面的背景颜色 ,  刷新页面则恢复默认的白色 . 
 
出版社列表与作者表有兴趣自己去完善 .