昨日内容回顾

  1. 多表方案:
  2. 如何确定表关系呢?
  3. 表关系是在2张表之间建立的,没有超过2个表的情况。
  4. 那么相互之间有2条关系线,先来判断一对多的关系。
  5. 如果其中一张表的记录能够对应另外一张表的多条记录,那么关系线成立!
  6.  
  7. 如果只有一条线成立,那么就是一对多的关系。
  8. 如果有2条线成立,那么就是多对多的关系。
  9.  
  10. 比如bookpublish。一本书不能对应多个出版社(常规是这样的,否则就盗版了),那么不成立。
  11. 一个出版社可以对应多本书,关系线成立。所以bookpublish表的关系是一对多的关系
  12.  
  13. 多对多的关系,就是2张表互相对应多条记录。
  14. 比如bookauthor。一本书可以有多个作者,一个作者可以写多本!
  15.  
  16. 一对一的关系,就很简单了,彼此唯一。
  17. 比如authorauthordetail是一对一的关系。
  18.  
  19. 一对多:
  20. bookpublish表的关系是一对多的关系
  21.  
  22. 一旦确定一对多的关系:在多的表中创建关联字段
  23. # 与Publish建立一对多的关系,外键字段建立在多的一方
  24. publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
  25. #创建的字段名为publish_id。它会自动加_id后缀
  26.  
  27. 多对多:
  28. bookauthor是多对多的关系
  29.  
  30. 一旦确定多对多的关系:创建第三张关系表
  31. # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
  32. authors=models.ManyToManyField(to="Author")
  33. #注意:表名为应用名+book类名小写+authors,也就是book_authors。
  34. #它只有3个字段,分别是主键id,book_id,author_id。
  35. #book_id和author_id分别表示book表和author表的主键id
  36.  
  37. 一对一:
  38. authorauthordetail是一对一的关系
  39.  
  40. 一旦确定一对一的关系 创建关联字段(任意一张表创建都可以)
  41. #但是一般,我们会判断谁是重要的,谁是次要的。在重要的表上面创建关联字段!比如author
  42. #由于authordetail表是author表的延伸,所以在author表创建关联字段
  43. # 与AuthorDetail建立一对一的关系
  44. ad=models.OneToOneField(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,)
  45. #创建的字段名为ad_id,它会自动加_id后缀。一对一关联字段,必须设置唯一属性!

一、django多表添加

昨天已经把5张表,都创建出来了。models.py里面有4个模型,其中第5张表,是book表和author表的关系表。

由book类的authors属性来创建了关系表,表名为:应用名+book+'_'+authors。

修改urls.py,添加add路径

  1. from app01 import views
  2. urlpatterns = [
  3. path('admin/', admin.site.urls),
  4. path('add/', views.add),
  5. ]

由于pycharm对sqlite数据库的时间字段,添加时,会自动转换为时间戳。

这样很不好,所以我使用navicat来连接。

新建一个连接

找到表publish

添加2条记录

添加表记录

create(**kwargs) 建立新对象

返回值是添加的model对象

一对一

举例:添加一条作者信息

姓名=hong,年龄=25,女朋友=唐安琪,电话=1314

  1. def add(request):
  2. #先添加作者详细信息
  3. hong_gf = AuthorDetail.objects.create(gf="唐安琪",tel=1314)
  4. #再添加作者,因为它依赖AuthorDetail表
  5. hong = Author.objects.create(name="hong",age="",ad=hong_gf)
  6. print(hong)
  7.  
  8. return HttpResponse('添加成功')

注意:因为author的ad属性是关联authordetail表,必须添加authordetail表,才能添加author表。

ad必须接收一个model对象。可以从这个model对象中,获取插入的id值。

刷新页面,查看authordetail表,发现多了一条记录

查看author表,发现多了一条记录

一对多

方式1(推荐)

修改views.py,增加add视图函数

  1. from django.shortcuts import render,HttpResponse
  2. from app01.models import Book
  3. # Create your views here.
  4.  
  5. def add(request):
  6. #publish_id就是Book类的publish属性。它的字段为publish_id
  7. book = Book.objects.create(title='西游记',price=100,pub_date="1743-4-12",publish_id=2)
  8. print(book.title) #打印title
  9. return HttpResponse('添加成功')

访问url:http://127.0.0.1:8000/add/

查看book表记录,发现多了一条

方式2

添加一本书《三国演义》,指定出版社为西瓜出版社

首要要导入Publish

  1. def add(request):
  2. xigua = Publish.objects.filter(name="西瓜出版社").first() #model对象
  3. book = Book.objects.create(title='三国演义',price=300,pub_date="1643-4-12",publish=xigua)
  4. print(book.title) #打印标题
  5. print(book.publish) # 与这本书籍关联的出版社对象
  6. print(type(book.publish)) # 打印属性
  7. print(book.publish.id) # 出版社id
  8. print(book.publish.name) # 出版社name
  9.  
  10. return HttpResponse('添加成功')

注意:xigua它是一个model对象,它表示publish表的一条记录

create里面的publish只能接收publish表的model对象,不能接收别的表model对象!

查看models.py的Book类的publish属性

  1. publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)

注意:它只能接收publish表的id字段。

所以执行sql时,它相当于publish_id=xigua.id。

这种添加方式,有严格的限制,必须接收publish的model对象才可以的。不推荐使用

查看控制台信息:

  1. 三国演义
  2. [29/Jun/2018 16:47:44] "GET /add/ HTTP/1.1" 200 12
  3. Publish object (1)
  4. <class 'app01.models.Publish'>
  5. 1
  6. 西瓜出版社

book.publish 是与这本书籍关联的出版社对象

那么就可以得到出版社的id和name属性值

查看表记录,发现多了一条

现在书籍和作者还没有绑定关系,先增加作者详细记录
修改authordetail表,增加2条记录

修改author表,增加2条记录

多对多

现在需要在book表里面插入一本书《python》,这本书有2个作者。那么book_authors应该有2条记录

它应该是这样的

  1. id book_id author_id
  2. 1 3 1
  3. 2 3 2

那么如何将这2条记录,插入进去呢?

修改add视图函数,注意导入author类

先插入一条记录

  1. book = Book.objects.create(title='python',price=122,pub_date="2012-12-12",publish_id=1)

再获取2个作者

  1. xiao = Author.objects.filter(name="xiao").first()
  2. zhang = Author.objects.filter(name="zhang").first()

最后插入2条记录,注意:下面2行代码是不能执行的,它是伪代码!

  1. book_authors.objects.create(book_id=book.id,author_id=xiao.id)
  2. book_authors.objects.create(book_id=book.id, author_id=zhang.id)

上面2行代码表示在book_authors表中添加2条记录,只增加book_id和author_id。

那么问题来了,book_authors这张表是用orm创建的
但是orm的models.py里面找不到book_authors这张表的模型类。如果存在的话,那肯定没有问题的。
因为第3张表,是在book类里面的authors属性,用ManyToManyField创建的
因为一本书,对应的不止一个作者,所以不能直接赋值操作。

add() 增加多个关系对象

使用方法1:add(obj1, obj2, ...)

ORM提供了add方法,来添加多对多的关系表。

  1. def add(request):
  2. book = Book.objects.create(title='python',price=122,pub_date="2012-12-12",publish_id=1)
  3. xiao = Author.objects.filter(name="xiao").first()
  4. zhang = Author.objects.filter(name="zhang").first()
  5. book.authors.add(xiao,zhang) # 添加2条数据,接收一个参数,就会产生一条记录
  6.  
  7. return HttpResponse('添加成功')

注意:book.authors.add(xiao,zhang),相当于执行上面2句伪代码!

它会自动获取2个对象的主键id,并插入到对应的字段中。

刷新页面,查看book表,发现多了一条记录

查看book_authors表,发现多2条数据

如果需要为书籍绑定所有作者呢?

  1. author_list = Author.objects.all()
  2. book.authors.add(*author_list)

上面2行代码,就搞定了,非常简洁!

使用方法2:add(主键1, 主键2, ...)

下面这种写法,也是可以的。在html表单页面添加时,会用到此写法!

  1. book.authors.add(1,2)

还有一种写法,是属于python的。*[1,2],表示打散。它相当于上面的写法

  1. book.authors.add(*[1,2])

区别在于:add(1,2)这种写法,它是执行了2次,在book_authors表中插入2条记录。

那么在不知道有多少数值的情况下,需要使用*[args1,args2]这种写法。

注意:在html表单中的复选框中,它提交的数据是多个值,必须使用getlist方法获取,它是列表类型。

因为不知道用户,到底会选择多少个选项。所以就需要使用这种打散写法!

删除记录

remove(obj1, obj2, ...) 去除多个关系对象

举例:删除python这本书的xiao作者
那么只需要删除book_authors表,id为1的这一条记录,就可以了

但是,不能直接对这张表,直接删除。因为它是2个表的关联表。

解除绑定的关系

  1. def add(request):
  2. book = Book.objects.filter(id=3).first() # 先找到这本书
  3. xiao = Author.objects.filter(name="xiao").first() # 再找到作者
  4. book.authors.remove(xiao) # 解除绑定的关系
  5. return HttpResponse('添加成功')

刷新页面,查看book_authors表记录,发现作者没有了

注意:这里可不是级联删除,book_authors并没有on_delete=models.CASCADE属性

clear() 清理所有关系对象

修改book_authors表记录,添加1条记录

举例:将book_id等于3的所有的作者删除

上面的例子,用remove,可以将一个删除。如果这本书,有5个作者呢?

一个个remove?太累了!django提供了clear方法,可以清理所有关系对象。

  1. def add(request):
  2. book = Book.objects.filter(id=3).first()
  3. book.authors.clear() # 清理所有关系对象
  4. return HttpResponse('添加成功')

刷新页面,再次查看book_authors表记录,发现已经空了!

修改authordetail表,增加一条记录

修改author表,增加一条记录

修改book_authors表,增加3条数据

set([obj1,obj2...])  先清空再设置

set([obj1,obj2,...])  它接收多个值,可以一个,也可以多个。适用于后台网页修改操作!

举例:

python这本书目前有3个作者,将wang设置为这本书的唯一作者

怎么做呢?将另外2个作者解除关系就可以了。

  1. def add(request):
  2. book = Book.objects.filter(id=3).first() # 先找到书
  3. xiao = Author.objects.filter(name="xiao").first() # 再找到作者
  4. zhang = Author.objects.filter(name="zhang").first()
  5. book.authors.remove(xiao,zhang) # 解除绑定的关系
  6.  
  7. return HttpResponse('添加成功')

但是这样将2个作者解除,太麻烦了。

还有一种做法,先清空,再设置

  1. def add(request):
  2. book = Book.objects.filter(id=3).first() # 先找到书
  3. book.authors.clear() # 清理所有关系对象
  4. wang = Author.objects.filter(name="wang").first()
  5. book.authors.add(wang)
  6.  
  7. return HttpResponse('添加成功')

django提示了set方法,直接合并了先清空再设置的操作

它必须接收一个数组,因为可以接收多个值

  1. def add(request):
  2. book = Book.objects.filter(id=3).first() # 先找到书
  3. wang = Author.objects.filter(name="wang").first() # 再找作者
  4. book.authors.set([wang]) #先清空再设置
  5.  
  6. return HttpResponse('添加成功')

刷新页面,查看book_authors表记录,发现只有一条了

总结:

重点掌握create,add,remove,clear,set这五个方法!

添加表记录:

  一对一和一对多,使用create方法。它有2种使用方法:

    1. create(字段名1=值1...)。适用于表单添加操作!注意,这里面的字段名是ORM创建表之后的的字段名

      比如: book类的publish属性,它是关联字段,ORM创建之后,字段名为publish_id

    2.create(模型类属性1=值1...)。比如book类的publish属性,它是关联字段。

      直接create(publish=obj1),注意,它接收一个model对象,对象包含了主键id

  多对多使用add方法。add用2种使用方法:

    1.add(obj1,obj2...) 它接收一个model对象,对象包含了主键id

    2.add(主键id1,主键id2...) 它接收一个主键id。适用于表单添加操作!

    还有一个python的打散语法,前面加一个*就可以了。比如*[1,2],它会依次调用前置方法,每次只取一个值。表单操作,会用到!

 删除记录:

  适用于一对一,一对多,多对一。

  remove(obj1, obj2, ...) 去除多个关系对象。它需要指定一个或者多个对象

  clear() 清理所有关系对象。不管现有的关系有多少,一律清空!

  set([obj1,obj2...]) 先清空再设置。不管现有的关系有多少,一律清空再设置。适用于网页后台修改操作

 

基于对象的跨表查询(子查询)

先来查询id为3的书籍,打印publish和authors是什么?

  1. def add(request):
  2. book = Book.objects.filter(id=3).first()
  3. print(book.publish) # 查看publish属性
  4. print(book.authors)
  5. print(type(book.authors)) # 查看类型
  6. print(book.authors.all()) # 返回所有book的关联对象
  7. print(book.authors.all().values()) # 查看关联对象的值
  8.  
  9. return HttpResponse('添加成功')

刷新页面,查看控制台信息

  1. Publish object (1)
  2. app01.Author.None
  3. <class 'django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager'>
  4. <QuerySet [<Author: Author object (3)>]>
  5. <QuerySet [{'name': 'wang', 'age': 27, 'id': 3, 'ad_id': 3}]>

注意:book.authors不能直接print,否则返回的值是None。它是一个多对多的关系管理器,必须用all()才能取值。

book.authors.all() 表示返回所有book的关联对象。注意:这里的book对象,是一个model对象,它是表示id为3的一条记录。从最后一条打印信息中,就可以看出来!

修改book_authors表,添加2条记录

再次刷新页面,查看控制台信息

  1. Publish object (1)
  2. app01.Author.None
  3. <class 'django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager'>
  4. <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>, <Author: Author object (3)>]>
  5. <QuerySet [{'name': 'xiao', 'id': 1, 'ad_id': 1, 'age': 25}, {'name': 'zhang', 'id': 2, 'ad_id': 2, 'age': 26}, {'name': 'wang', 'id': 3, 'ad_id': 3, 'age': 27}]>

注意最后一条信息,它返回了3个model对象。为什么会返回3条信息呢?

它实际是执行了下面这句SQL

  1. SELECT
  2. author.id,
  3. author.name,
  4. author.age,
  5. author.ad_id
  6. FROM
  7. author
  8. INNER JOIN book_authors ON (
  9. author.id = book_authors.author_id
  10. )
  11. WHERE
  12. book_authors.book_id = 3
  13. LIMIT 21;

因为book的id为3,它先从关系表book_authors,查找book_id=3的记录。此时有3条记录!

再和author表关联查询,找出3个作者的记录。所以最终结果就是author的3条记录!

book.authors.all()是与这本书关联的作者对象queryset对象集合

django有2个日期类型,一个是DateField(),它的格式是yyyy-mm-dd

还有一个类型是DateTimeField(),它的格式是yyyy-mm-dd h:i:s。它是带时分秒的!

python中的datetime

举例:

  1. import datetime
  2. now = datetime.datetime.now()
  3. print(now) # 当前时间
  4. print(now.today()) # 当前时间
  5. print(now.date()) # 日期
  6. print(now.time()) # 排除日期,取时分秒
  7. print(now.strftime("%Y-%m-%d %H:%I:%S")) # 格式化时间
  8.  
  9. delta = datetime.timedelta(days=3) # 时间差
  10. print(delta)
  11. print(now+delta) # 3天后
  12. print(now-delta) # 3天后

输出:

  1. 2018-06-29 20:59:02.741780
  2. 2018-06-29 20:59:02.741781
  3. 2018-06-29
  4. 20:59:02.741780
  5. 2018-06-29 20:08:02
  6. 3 days, 0:00:00
  7. 2018-07-02 20:59:02.741780
  8. 2018-06-26 20:59:02.741780

一对多查询(Publish 与 Book)

book_authors表添加2条数据

举例:

查询西游记这本书的出版社的名字

普通写法

先找出这本书,然后取出publish_id。在publish表中,通过publish_id找到对应记录。

  1. def add(request):
  2. book = Book.objects.filter(title="西游记").first()
  3. publish_id = book.publish_id
  4. publish = Publish.objects.filter(id=publish_id).first()
  5. print(publish.name)
  6.  
  7. return HttpResponse('添加成功')

刷新网页,查看控制台,输出:

榴莲出版社

推荐写法:

上面的步骤太麻烦了,下面使用简洁写法,2行就搞定了!

  1. def add(request):
  2. book = Book.objects.filter(title="西游记").first()
  3. print(book.publish.name)
  4.  
  5. return HttpResponse('添加成功')

举例:查询西瓜出版社出版过的所有书籍的名称

  1. def add(request):
  2. publish = Publish.objects.filter(name="西瓜出版社").first() # 先找出版社
  3. ret = Book.objects.filter(publish_id=publish.id).values("title") # 再找书籍
  4. print(ret)
  5.  
  6. return HttpResponse('添加成功')

刷新网页,查看控制台,效果同上

上面写的太麻烦,下面来介绍正向查询和反向查询

正向和反向,就看关键字段在哪里?
如果是通过关联字段查询,就是正向。否则是反向!

简单来说:正向,按照字段。反向,按照表名

正向与反向查询

正向查询:关联属性在book表中,所以book对象找出关联出版社对象,正向查询

反向查询:关联属性在book表中,所以publish对象找出关联书籍,正向查询

  1. 正向:按字段:publish
  2. book -----------> publish
  3. <-----------
  4. 反向:按表名小写_set() 例如:publish.obj.book_set()

正向查询

还是上面的例子:查询西瓜出版社出版过的所有书籍的名称

简洁写法:

  1. def add(request):
  2. publish = Publish.objects.filter(name="西瓜出版社").first() # 先找出版社
  3. # ret = Book.objects.filter(publish_id=publish.id).values("title") # 再找书籍
  4. # print(ret)
  5. #正向查询--简洁写法
  6. ret = publish.book_set.all().values("title")
  7. print(ret)
  8.  
  9. return HttpResponse('添加成功')

刷新网页,控制台输出:

<QuerySet [{'title': '三国演义'}, {'title': 'python'}]>

推荐使用简洁写法,为什么呢?因为如果表越来越多,那么SQL就非常复杂。使用简洁写法,就能避免!

那么它是如何实现的呢?通过Book模型类的authors属性

  1. authors=models.ManyToManyField(to="Author")

反向查询

举例:查询与西瓜出版社关联的所有书籍的名字

  1. def add(request):
  2. publish = Publish.objects.filter(name="西瓜出版社").first() # 先找出版社
  3. ret = publish.book_set.all().values("title") # 再找书籍,过滤title
  4. print(ret)
  5.  
  6. return HttpResponse('添加成功')

刷新网页,控制台输出:

<QuerySet [{'title': '三国演义'}, {'title': 'python'}]>

多对多查询 (Author 与 Book)

正向查询:关联属性在book表中,所以book对象找出关联作者集合,正向查询

反向查询:关联属性在book表中,所以author对象找出关联书籍,正向查询

因为记录有多条,所以结尾要加.all()

  1. 正向:按字段:authors.all()
  2. book -----------> author
  3. <-----------
  4. 反向:按表名小写_set().all() 例如:author.obj.book_set().all()

正向查询

举例:查询西游记这本书籍的所有作者的姓名和年龄

  1. def add(request):
  2. book = Book.objects.filter(title="西游记").first() # 先找书籍
  3. ret = book.authors.all().values("name","age") # 再找作者,过滤name和age
  4. print(ret)
  5.  
  6. return HttpResponse('添加成功')

刷新网页,控制台输出:

<QuerySet [{'age': 25, 'name': 'xiao'}]>

反向查询

举例:查询作者xiao出版过的所有书籍名称

  1. def add(request):
  2. xiao = Author.objects.filter(name="xiao").first() # 先找作者
  3. ret = xiao.book_set.all().values("title") # 再找书籍,过滤title
  4. print(ret)
  5.  
  6. return HttpResponse('添加成功')

刷新网页,控制台输出:

<QuerySet [{'title': 'python'}, {'title': '西游记'}]>

一对一查询(Author 与 AuthorDetail)

正向查询:关联属性在author表中,所以author对象找出关联作者详细信息对象,正向查询

反向查询:关联属性在book表中,所以author对象找出关联书籍,正向查询

因为记录只有一条,所以直接.ad就可以了。ad是关联字段

  1. 正向:按字段:.ad
  2. author -----------> authordetail
  3. <-----------
  4. 反向:按表名小写 例如:authordetail_obj.author

正向查询

举例:查询xiao的女朋友的名字

  1. def add(request):
  2. xiao = Author.objects.filter(name="xiao").first() # 先找作者
  3. ret = xiao.ad.gf # 再找女朋友
  4. print(ret)
  5.  
  6. return HttpResponse('添加成功')

刷新网页,控制台输出:

赵丽颖

反向查询

举例:查询手机号为112的作者名字

  1. def add(request):
  2. phone = AuthorDetail.objects.filter(tel="").first() # 先找号码
  3. ret = phone.author.name # 再找作者的名字
  4. print(ret)

刷新网页,控制台输出:

wang

周末作业

基于多表的图书管理系统

注意:出版社和作者,是从数据库中读取的。

作业是复选框,可以选择多个

编辑页面,作者一栏的灰色背景。表示现有绑定的作者!

它是选择状,使用selected属性

提示:

视图函数接收复选框的值,需要使用request.POST.getlist()。使用get只能获取一个值!

答案

修改urls.py,添加路径

  1. from django.contrib import admin
  2. from django.urls import path,re_path
  3.  
  4. from book import views
  5. urlpatterns = [
  6. path('admin/', admin.site.urls),
  7. path('', views.index),
  8. path('index/', views.index),
  9. path('books/add/', views.add),
  10. path('books/manage/', views.manage),
  11. re_path('books/delete/(?P<id>\d+)', views.delete),
  12. re_path('books/modify/(?P<id>\d+)', views.modify),
  13. ]

修改settings.py

注册app

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'book',
  9. ]

指定模板路径

  1. TEMPLATES = [
  2. {
  3. 'BACKEND': 'django.template.backends.django.DjangoTemplates',
  4. 'DIRS': [os.path.join(BASE_DIR, 'templates')],
  5. 'APP_DIRS': True,
  6. 'OPTIONS': {
  7. 'context_processors': [
  8. 'django.template.context_processors.debug',
  9. 'django.template.context_processors.request',
  10. 'django.contrib.auth.context_processors.auth',
  11. 'django.contrib.messages.context_processors.messages',
  12. ],
  13. },
  14. },
  15. ]

默认使用sqlite3数据库,有需要的使用其他数据库的,自行更改

指定静态资源路径

  1. STATIC_URL = '/static/'
  2. STATICFILES_DIRS=[
  3. os.path.join(BASE_DIR,"static")
  4. ]

手动创建templates和static目录。

在static目录创建css目录,下载bootstrap 3.3.7的数据包。将将bootstrap.min.css放到css目录

修改models.py

  1. from django.db import models
  2.  
  3. # Create your models here.
  4. class Book(models.Model):
  5. title=models.CharField(max_length=32,unique=True)
  6. price=models.DecimalField(max_digits=8,decimal_places=2,null=True)
  7. pub_date=models.DateField()
  8. # 与Publish建立一对多的关系,外键字段建立在多的一方
  9. publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
  10. # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建关系表book_authors
  11. authors=models.ManyToManyField(to="Author")
  12.  
  13. class Publish(models.Model):
  14. name=models.CharField(max_length=32)
  15. email=models.CharField(max_length=32)
  16. addr=models.CharField(max_length=32)
  17.  
  18. class Author(models.Model):
  19. name=models.CharField(max_length=32)
  20. age=models.IntegerField()
  21. # 与AuthorDetail建立一对一的关系
  22. # ad=models.ForeignKey(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,unique=True)
  23. ad=models.OneToOneField(to="AuthorDetail",to_field="id",on_delete=models.CASCADE,)
  24.  
  25. class AuthorDetail(models.Model):
  26. gf=models.CharField(max_length=32)
  27. tel=models.CharField(max_length=32)

使用2个命令生成表

  1. python manage.py makemigrations
  2. python manage.py migrate

使用navicat打开sqlite数据库,5个表,添加初始数据

注意修改应用名,因为每个人的应用名不一样!

下面是sql语句:

  1. #作者详情表
  2. INSERT INTO book_authordetail (`id`, `gf`, `tel`) VALUES (1, '赵丽颖',110);
  3. INSERT INTO book_authordetail (`id`, `gf`, `tel`) VALUES (2, '刘诗诗',111);
  4. INSERT INTO book_authordetail (`id`, `gf`, `tel`) VALUES (3, '唐嫣',112);
  5.  
  6. #作者表
  7.  
  8. INSERT INTO book_author (`id`, `name`, `age`, `ad_id`) VALUES (1, 'xiao',25,1);
  9. INSERT INTO book_author (`id`, `name`, `age`, `ad_id`) VALUES (2, 'zhang',26,2);
  10. INSERT INTO book_author (`id`, `name`, `age`, `ad_id`) VALUES (3, 'wang',27,3);
  11.  
  12. #出版社表
  13.  
  14. INSERT INTO book_publish (`id`, `name`, `email`, `addr`) VALUES (1, '人民教育出版社', 'rm@qq.com', '北京');
  15. INSERT INTO book_publish (`id`, `name`, `email`, `addr`) VALUES (2, '中国农业出版社', 'zg@qq.com', '北京');
  16. INSERT INTO book_publish (`id`, `name`, `email`, `addr`) VALUES (3, '中国林业出版社', 'ly@qq.com', '云南');
  17.  
  18. #书籍表
  19. INSERT INTO book_book (`id`, `title`, `price`, `pub_date`, `publish_id`) VALUES (1, '西游记',2, '1501-01-23',1);
  20. INSERT INTO book_book (`id`, `title`, `price`, `pub_date`, `publish_id`) VALUES (2, '红楼梦',3, '1715-02-13',2);
  21. INSERT INTO book_book (`id`, `title`, `price`, `pub_date`, `publish_id`) VALUES (3, '三国演义',4, '1330-03-25',3);
  22.  
  23. #书籍和作者关系表
  24. INSERT INTO book_book_authors (`id`, `book_id`, `author_id`) VALUES (1,1,1);
  25. INSERT INTO book_book_authors (`id`, `book_id`, `author_id`) VALUES (2,2,2);
  26. INSERT INTO book_book_authors (`id`, `book_id`, `author_id`) VALUES (3,3,3);

修改views.py

  1. from django.shortcuts import render,HttpResponse
  2. #导入4个表模型
  3. from book.models import Book,Publish,Author,AuthorDetail
  4.  
  5. # Create your views here.
  6. def index(request): #首页
  7. ret = Book.objects.all().exists() # 判断表是否有记录
  8. if ret:
  9. book_list = Book.objects.all() # 查询表的所有记录
  10. return render(request, "index.html", {"book_list": book_list})
  11.  
  12. else:
  13. hint = '<script>alert("没有书籍,请添加书籍");window.location.href="/books/add"</script>'
  14. return HttpResponse(hint) # js跳转到添加页面
  15.  
  16. def add(request): # 添加
  17. if request.method=="POST":
  18. # print(request.POST)
  19. title=request.POST.get("title")
  20. the_book = Book.objects.filter(title=title).exists()
  21. if the_book:
  22. hint = '<script>alert("书籍已存在!不能重复添加");window.location.href="/books/add/"</script>'
  23. return HttpResponse(hint) # js跳转到添加页面
  24. else:
  25. price=request.POST.get("price")
  26. pub_date=request.POST.get("pub_date")
  27. publish_id=request.POST.get("publish_id")
  28. author_id=request.POST.getlist("author_id") # 返回列表
  29. print(title,price,pub_date,publish_id,author_id)
  30. #先插入书籍
  31. book = Book.objects.create(title=title, price=price, pub_date=pub_date, publish_id=publish_id)
  32. #再插入作者
  33. book.authors.add(*author_id)
  34.  
  35. hint = '<script>alert("添加成功");window.location.href="/index/"</script>'
  36. return HttpResponse(hint) # js跳转到首页
  37.  
  38. #读取所有出版社,过滤出id和name
  39. publish_list = Publish.objects.all().values("id","name")
  40. # 读取所有作者,过滤出id和name
  41. author_list = Author.objects.all().values("id","name")
  42.  
  43. return render(request, "add.html", {"publish_list": publish_list,"author_list":author_list})
  44.  
  45. def delete(request,id): # 删除
  46. # 先删除关系表中的作者
  47. book_ad = Book.objects.filter(id=id).first()
  48. book_ad.authors.clear()
  49.  
  50. # 再删除书籍
  51. ret = Book.objects.filter(id=id).delete() # 返回元组
  52. print(ret)
  53.  
  54. if ret[0]: # 取值为1的情况下
  55. hint = '<script>alert("删除成功");window.location.href="/index/"</script>'
  56. return HttpResponse(hint)
  57. else: # 取值为0的情况下
  58. hint = '<script>alert("删除失败");window.location.href="/index/"</script>'
  59. return HttpResponse(hint)
  60.  
  61. def manage(request): # 管理页面
  62. ret = Book.objects.all().exists()
  63. if ret:
  64. book_list = Book.objects.all()
  65. #加载管理页面
  66. return render(request, "manage.html", {"book_list": book_list})
  67. else:
  68. hint = '<script>alert("没有书籍,请添加书籍");window.location.href="/books/add"</script>'
  69. return HttpResponse(hint)
  70.  
  71. def modify(request,id): # 修改
  72. if request.method == "POST":
  73. title = request.POST.get("title")
  74. price = request.POST.get("price")
  75. pub_date = request.POST.get("pub_date")
  76. publish_id = request.POST.get("publish_id")
  77. author_id = request.POST.getlist("author_id") # 返回列表
  78.  
  79. # 先修改书籍
  80. ret = Book.objects.filter(id=id).update(title=title, price=price, pub_date=pub_date, publish_id=publish_id)
  81. # 获取当前书籍
  82. book_ad = Book.objects.filter(id=id).first()
  83. book_ad.authors.set(author_id) # 先清空再设置
  84.  
  85. if ret: # 判断返回值为1
  86. hint = '<script>alert("修改成功");window.location.href="/index/"</script>'
  87. return HttpResponse(hint) # js跳转
  88. else: # 返回为0
  89. hint = '<script>alert("修改失败");window.location.href="/index/"</script>'
  90. return HttpResponse(hint) # js跳转
  91.  
  92. book = Book.objects.get(id=id) # 默认获取id值
  93. # print(book)
  94.  
  95. # 读取所有出版社,过滤出id和name
  96. publish_list = Publish.objects.all().values("id", "name")
  97. # 读取所有作者,过滤出id和name
  98. author_list = Author.objects.all().values("id", "name")
  99. the_author = [] # 当前书籍的作者
  100. for i in book.authors.all():
  101. the_author.append(i.name) # 最加到列表中
  102. print(the_author)
  103.  
  104. return render(request, "modify.html", {"book":book,"publish_list": publish_list, "author_list": author_list,"the_author":the_author})

在templates目录新建几个html文件

base.html,这个是所有html的母版文件

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. {% block title %}
  6. <title>title</title>
  7. {% endblock title %}
  8. {#bootstrap,版本为3.3.7#}
  9. <link rel="stylesheet" href="/static/css/bootstrap.min.css">
  10. {#美化复选框#}
  11. <link rel="stylesheet" href="https://cdn.bootcss.com/awesome-bootstrap-checkbox/0.3.7/awesome-bootstrap-checkbox.css">
  12. <link href="http://cdn.bootcss.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet">
  13. <style>
  14. * {
  15. margin: 0;
  16. padding: 0;
  17. }
  18.  
  19. .header {
  20. width: 100%;
  21. height: 60px;
  22. background-color: #369;
  23. }
  24.  
  25. .title {
  26.  
  27. line-height: 60px;
  28. color: white;
  29. font-weight: 100;
  30. margin-left: 20px;
  31. font-size: 20px;
  32. }
  33.  
  34. .container {
  35. margin-top: 20px;
  36. }
  37.  
  38. .table th, .table td {
  39. text-align: center;
  40. vertical-align: middle !important;
  41. }
  42. </style>
  43. </head>
  44. <body>
  45.  
  46. <div class="header">
  47. <p class="title">
  48. 图书管理系统
  49. </p>
  50. </div>
  51.  
  52. <div class="container">
  53. <div class="row">
  54. <div class="col-md-3">
  55. <div class="panel panel-danger">
  56. <div class="panel-heading"><a href="/index/">查看书籍</a></div>
  57. <div class="panel-body">
  58. Panel content
  59. </div>
  60. </div>
  61. <div class="panel panel-success">
  62. <div class="panel-heading"><a href="/books/add/">添加书籍</a></div>
  63. <div class="panel-body">
  64. Panel content
  65. </div>
  66. </div>
  67. <div class="panel panel-warning">
  68. <div class="panel-heading"><a href="/books/manage/">管理书籍</a></div>
  69. <div class="panel-body">
  70. Panel content
  71. </div>
  72. </div>
  73. </div>
  74. <div class="col-md-9">
  75. {% block content %}
  76.  
  77. {% endblock %}
  78. </div>
  79. </div>
  80. </div>
  81.  
  82. </body>
  83. </html>

index.html,首页

  1. {% extends 'base.html' %}
  2.  
  3. {% block title %}
  4.  
  5. <title>查看书籍</title>
  6.  
  7. {% endblock title %}
  8.  
  9. {% block content %}
  10. <h3>查看书籍</h3>
  11. <table class="table table-hover table-striped ">
  12. <thead>
  13. <tr>
  14. <th>编号</th>
  15. <th>书籍名称</th>
  16. <th>价格</th>
  17. <th>出版日期</th>
  18. <th>出版社</th>
  19. <th>作者</th>
  20. </tr>
  21. </thead>
  22. <tbody>
  23. {#遍历所有书籍#}
  24. {% for book in book_list %}
  25. <tr>
  26. <td>{{ book.id }}</td>
  27. <td>{{ book.title }}</td>
  28. <td>{{ book.price }}</td>
  29. <td>{{ book.pub_date|date:"Y-m-d" }}</td>
  30. <td>{{ book.publish.name }}</td>
  31. <td>
  32. {#遍历所有书籍相关的作者#}
  33. {% for j in book.authors.all %}
  34. {#使用forloop.last判断,如果如果是最后一个,不增加逗号#}
  35. {{ j.name }}{% if not forloop.last %},{% endif %}
  36. {% endfor %}
  37. </td>
  38.  
  39. </tr>
  40. {% endfor %}
  41.  
  42. </tbody>
  43. </table>
  44.  
  45. {% endblock content %}

add.html,添加页面

  1. {% extends 'base.html' %}
  2.  
  3. {% block title %}
  4.  
  5. <title>添加书籍</title>
  6.  
  7. {% endblock title %}
  8.  
  9. {% block content %}
  10. <h3>添加书籍</h3>
  11. <form action="" method="post">
  12. {% csrf_token %}
  13. <div class="form-group">
  14. <label for="">书籍名称</label>
  15. <input type="text" name="title" class="form-control">
  16. </div>
  17. <div class="form-group">
  18. <label for="">价格</label>
  19. <input type="text" name="price" class="form-control">
  20. </div>
  21. <div class="form-group">
  22. <label for="">出版日期</label>
  23. <input type="date" name="pub_date" class="form-control">
  24. </div>
  25. <div class="form-group">
  26. <label for="">出版社</label>
  27. <select name="publish_id" id="" class="form-control">
  28. {#使用for循环遍历所有出版社#}
  29. {% for p in publish_list %}
  30. {#由于表关系是通过id关联的,所以value值必须是id#}
  31. <option value="{{ p.id }}">{{ p.name }}</option>
  32. {% endfor %}
  33. </select>
  34.  
  35. </div>
  36. <div class="form-group">
  37. <label for="">作者</label>
  38. <ul class="list-group">
  39. {#使用for循环遍历所有作者#}
  40. {% for author in author_list %}
  41. <li class="list-group-item">
  42. <div class="checkbox checkbox-success ">
  43. {#由于表关系是通过id关联的,所以value值必须是id#}
  44. <input class="styled" type="checkbox" name="author_id" value="{{ author.id }}">
  45. <label class="checkbox-inline">
  46. {{ author.name }}
  47. </label>
  48. </div>
  49. </li>
  50. {% endfor %}
  51. </ul>
  52.  
  53. </div>
  54. <input type="submit" class="btn btn-success pull-right" value="添加">
  55. </form>
  56.  
  57. {% endblock content %}

manage.html,管理页面,用来删除和修改的

  1. {% extends 'base.html' %}
  2.  
  3. {% block title %}
  4.  
  5. <title>管理书籍</title>
  6.  
  7. {% endblock title %}
  8.  
  9. {% block content %}
  10. <h3>管理书籍</h3>
  11. <table class="table table-hover table-striped ">
  12. <thead>
  13. <tr>
  14. <th>编号</th>
  15. <th>书籍名称</th>
  16. <th>价格</th>
  17. <th>出版日期</th>
  18. <th>出版社</th>
  19. <th>作者</th>
  20. <th>删除</th>
  21. <th>编辑</th>
  22. </tr>
  23. </thead>
  24. <tbody>
  25. {% for book in book_list %}
  26. <tr>
  27. <td>{{ book.id }}</td>
  28. <td>{{ book.title }}</td>
  29. <td>{{ book.price }}</td>
  30. <td>{{ book.pub_date|date:"Y-m-d" }}</td>
  31. <td>{{ book.publish.name }}</td>
  32. <td>
  33. {#遍历所有书籍相关的作者#}
  34. {% for j in book.authors.all %}
  35. {#使用forloop.last判断,如果如果是最后一个,不增加逗号#}
  36. {{ j.name }}{% if not forloop.last %},{% endif %}
  37. {% endfor %}
  38. </td>
  39. <td>
  40. {#由于表关系是通过id关联的,所以参数必须是id#}
  41. <a href="/books/delete/{{ book.id }}">
  42. <button type="button" class="btn btn-danger" data-toggle="modal" id="modelBtn">删除</button>
  43. </a>
  44. </td>
  45. <td>
  46. <a href="/books/modify/{{ book.id }}">
  47. <button type="button" class="btn btn-success" data-toggle="modal">编辑</button>
  48. </a>
  49. </td>
  50. </tr>
  51. {% endfor %}
  52.  
  53. </tbody>
  54. </table>
  55.  
  56. {% endblock content %}

modify.html,修改页面

  1. {% extends 'base.html' %}
  2.  
  3. {% block title %}
  4.  
  5. <title>修改书籍</title>
  6.  
  7. {% endblock title %}
  8.  
  9. {% block content %}
  10. <h3>修改书籍</h3>
  11. <form action="" method="post">
  12. {% csrf_token %}
  13. <div class="form-group">
  14. <label for="">书籍名称</label>
  15. <input type="text" name="title" class="form-control" value="{{ book.title }}">
  16. </div>
  17. <div class="form-group">
  18. <label for="">价格</label>
  19. <input type="text" name="price" class="form-control" value="{{ book.price }}">
  20. </div>
  21. <div class="form-group">
  22. <label for="">出版日期</label>
  23. <input type="date" name="pub_date" class="form-control" value="{{ book.pub_date|date:"Y-m-d" }}">
  24. </div>
  25. <div class="form-group">
  26. <label for="">出版社</label>
  27. <select name="publish_id" id="" class="form-control">
  28. {#遍历所有出版社#}
  29. {% for p in publish_list %}
  30. {#判断当前书籍的出版社id等于出版社表的id时#}
  31. {% if book.publish_id == p.id %}
  32. {#添加选中状态selected="selected"#}
  33. {#由于表关系是通过id关联的,所以value值必须是id#}
  34. <option value="{{ p.id }}" selected="selected">{{ p.name }}</option>
  35. {% else %}
  36. <option value="{{ p.id }}">{{ p.name }}</option>
  37. {% endif %}
  38.  
  39. {% endfor %}
  40. </select>
  41. </div>
  42. <div class="form-group">
  43. <label for="">作者</label>
  44. <ul class="list-group">
  45. {% for author in author_list %}
  46. <li class="list-group-item">
  47. <div class="checkbox checkbox-success ">
  48. {#判断作者的名字在当前书籍作者列表中#}
  49. {% if author.name in the_author %}
  50. {#添加选中状态checked="checked"#}
  51. {#由于表关系是通过id关联的,所以value值必须是id#}
  52. <input class="styled" type="checkbox" checked="checked" name="author_id"
  53. value="{{ author.id }}">
  54. <label class="checkbox-inline">{{ author.name }}</label>
  55. {% else %}
  56. <input class="styled" type="checkbox" name="author_id" value="{{ author.id }}">
  57. <label class="checkbox-inline">{{ author.name }}</label>
  58. {% endif %}
  59. </div>
  60. </li>
  61. {% endfor %}
  62. </ul>
  63.  
  64. </div>
  65. <input type="submit" class="btn btn-default pull-right" value="修改">
  66. </form>
  67.  
  68. {% endblock content %}

项目文件结构如下:

  1. bms_mto
  2. ├── bms_mto
  3.    ├── __init__.py
  4.    ├── settings.py
  5.    ├── urls.py
  6.    └── wsgi.py
  7. ├── book
  8.    ├── admin.py
  9.    ├── apps.py
  10.    ├── __init__.py
  11.    ├── models.py
  12.    ├── tests.py
  13.    └── views.py
  14. ├── db.sqlite3
  15. ├── manage.py
  16. ├── static
  17.    └── css
  18.    ├── bootstrap.min.css
  19. └── templates
  20. ├── add.html
  21. ├── base.html
  22. ├── index.html
  23. ├── manage.html
  24. └── modify.html

启动项目访问首页:http://127.0.0.1:8000/

点击左侧的添加书籍

添加一本书,选择2个作者

提示添加成功

首页就会多一本书籍

点击编辑按钮

修改价格,增加一个作者

提示修改成功

首页的书籍,价格和作者更新过来了

点击删除

提示删除成功

首页少了一条数据

python 全栈开发,Day73(django多表添加,基于对象的跨表查询)的更多相关文章

  1. Python全栈开发:django网络框架(一)

    Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...

  2. python 全栈开发,Day95(RESTful API介绍,基于Django实现RESTful API,DRF 序列化)

    昨日内容回顾 1. rest framework serializer(序列化)的简单使用 QuerySet([ obj, obj, obj]) --> JSON格式数据 0. 安装和导入: p ...

  3. Python全栈开发:django网络框架(二)

    Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行 ...

  4. python 全栈开发,Day75(Django与Ajax,文件上传,ajax发送json数据,基于Ajax的文件上传,SweetAlert插件)

    昨日内容回顾 基于对象的跨表查询 正向查询:关联属性在A表中,所以A对象找关联B表数据,正向查询 反向查询:关联属性在A表中,所以B对象找A对象,反向查询 一对多: 按字段:xx book ----- ...

  5. python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)

    昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...

  6. Python全栈开发【基础二】

    Python全栈开发[基础二] 本节内容: Python 运算符(算术运算.比较运算.赋值运算.逻辑运算.成员运算) 基本数据类型(数字.布尔值.字符串.列表.元组.字典) 其他(编码,range,f ...

  7. python 全栈开发之路 day1

    python 全栈开发之路 day1   本节内容 计算机发展介绍 计算机硬件组成 计算机基本原理 计算机 计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可 ...

  8. python全栈开发-Day7 字符编码总结

    python全栈开发-Day7 字符编码总结 一.字符编码总结 1.什么是字符编码 人类的字符--------->翻译--------->数字 翻译的过程遵循的标准即字符编码(就是一个字符 ...

  9. python全栈开发-Day2 布尔、流程控制、循环

    python全栈开发-Day2 布尔 流程控制 循环   一.布尔 1.概述 #布尔值,一个True一个False #计算机俗称电脑,即我们编写程序让计算机运行时,应该是让计算机无限接近人脑,或者说人 ...

随机推荐

  1. Kafka集群优化篇-调整broker的堆内存(heap)案例实操

    Kafka集群优化篇-调整broker的堆内存(heap)案例实操 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查看kafka集群的broker的堆内存使用情况 1>. ...

  2. JAVA中初始化ArrayList的三种方式

    下面讲一下ArrayList初始化的几种不同方式. 一.最常用的初始化方式. List<String> list1 = new ArrayList<String>(); lis ...

  3. C语言上机复习(一)文件操作

    C语言—文件操作 1.1 fgetc() + fputc(): 以 字符 形式存取数据定义文件指针 #define _CRT_SECURE_NO_WARNINGS #include <cstdi ...

  4. 常用关于Android活动的实践技巧

    //知晓当前是在哪一个活动 /* 新建一个BaseActivity类(Java class), 继承自AppCompatActivity * 重写 onCreate()方法,已有的活动无需再继承自Ap ...

  5. Spring Boot 启动过程及 自定义 Listener等组件

    一.启动过程 二.自定义组件 package com.example.jdbc.listener; import org.springframework.context.ApplicationCont ...

  6. JavaScript之原生接口类设计

    //接口类         var Interface =  function(name , methods){             if(arguments.length!=2){       ...

  7. POJ3635 Full Tank?【Dijkstra+DP】

    题意: n个城市之间有m条双向路.每条路要耗费一定的油量.每个城市的油价是固定并且已经给出的.有q个询问,表示从城市s走到e,油箱的容量为c,求最便宜的方案. 思路: 用Dijkstra+Heap即可 ...

  8. 第16月第27天 pip install virtualenv ipython sip brew search

    1. pip install virtualenv virtualenv testvir cd testvir cd Scripts activate pip https://zhuanlan.zhi ...

  9. Poj3696 The Lukiest Number

    传送门 Solution 懒得写啦 Code #include<iostream> #include<cstdio> #include<cmath> #define ...

  10. extern的作用

    #include <stdio.h>extern int a;static int a;extern int b;int b;static int c;extern int c;