码迷,mamicode.com
首页 > 其他好文 > 详细

django-模型层(model)-多表相关操作(图书管理练习)

时间:2017-11-13 14:00:37      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:first   了解   query   外键   blank   objects   对象   默认   creat   

66、django之模型层(model)--多表相关操作(图书管理小练习)

前面几篇随笔的数据库增删改查操作都是在单表的操作上的,然而现实中不可能都是单表操作,更多的是多表操作,一对一,一对多,多对多的表结构才是我们经常需要处理的,本篇将带我们了解多表操作的一些相关操作。也会带着大家做一个简单的图书管理的小练习。

 

本篇导航:

 

一、建表

本篇继续以图书管理的例子。

模型:书籍有书名、作者、出版日期、价格,出版社,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

1、准备工作

1)创建一个项目

2)提前在mysql数据库里建立一个库

3)修改相关setting配置。(详情可以参考前面63、64、65三篇随笔)

2、建表

你如果在建表时没有添加主键,django会自动给我们的表添加一个主键id,是不是很棒0.0

1)语法

技术分享
一对一:
models.OneToOneField() ===>models.ForeignKey(,unique="True")
一对多:
models.ForeignKey()
多对多:
models.ManyToManyField()

属性:
related_name=""    
可选属性用来给此次关联起名,如果不用此属性django会自动给一个名字后面查询的例子会说明(是关联的名字不是字段名)
技术分享

2)建表实例

技术分享 图书、出版社、作者

这个图书的小练习中的表没有一对一关联用法用其他两个关联基本相同

3、注意

1)主键id 字段是自动添加的

2)对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名

3)外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

4)在表与表的连接中有related_name属性可以起名用于反向查询,当然不写有默认(表名_set),一对一关联可以直接用表名 


 

二、template模版的设计

此次的小练习template是用Bootstrap框架搭建的,因为我们本篇主讲的django模版层所以会贴出代码逮捕做分析,对前端有问题的可以看以前相关随笔哦。

相关随笔推荐:

Bootstrap使用:http://www.cnblogs.com/liluning/p/7643879.html

静态文件在模版中的使用:http://www.cnblogs.com/liluning/p/7724699.html

Bootstrap官网:http://v3.bootcss.com/

 

模版使用:http://v3.bootcss.com/examples/dashboard/


 

三、添加表记录

1、一对多添加语法

方式1:
   publish_obj=Publish.objects.get(nid=1)
   Book.objects.create(title="金瓶眉",publishDate="2012-12-12",publish=publish_obj)
 
方式2:
   Book.objects.create(title="金瓶眉",publishDate="2012-12-12",publish_id=1)

推荐使用第一种方式 第二种方式在你知道外键publish_id确切的值时可以使用

2、多对多添加语法

技术分享
book_obj=Book.objects.create(title="追风筝的人",publishDate="2012-11-12",prince=69,publish_id=1)
 
author_yuan=Author.objects.create(name="yuan",age=23...)
author_egon=Author.objects.create(name="egon",age=32...)
 
book_obj.authorlish.add(author_egon,author_yuan)    #  将某个特定的 model 对象添加到被关联对象集合中。   =======    book_obj.authors.add(*[])
 
book_obj.authorlish.create()      #创建并保存一个新对象,然后将这个对象加被关联对象的集合中,然后返回这个新对象。
技术分享

当然我们绑定的关联也可以解除:

book_obj.authorlish.remove()     # 将某个特定的对象从被关联对象集合中去除。    ======   book_obj.authors.remove(*[])
book_obj.authorlish.clear()       #清空被关联对象集合。

3、一对多添加和多对多添加实例

技术分享 View Code

一对一因为没用用到不做演示 用法与其他两个关联相同

4、相关方法演示(例子选自官网)

1)add

把指定的模型对象添加到关联对象集中。

b = Blog.objects.get(id=1)
e = Entry.objects.get(id=234)
b.entry_set.add(e)

2)create

创建一个新的对象,保存对象,并将它添加到关联对象集之中。返回新创建的对象。

b = Blog.objects.get(id=1)
e = b.entry_set.create(
    headline=Hello,
    body_text=Hi,
    pub_date=datetime.date(2005, 1, 1)
)

3)remove

从关联对象集中移除执行的模型对象

b = Blog.objects.get(id=1)
e = Entry.objects.get(id=234)
b.entry_set.remove(e)

4)clear

从关联对象集中移除一切对象。

b = Blog.objects.get(id=1)
b.entry_set.clear()

 

四、查询表记录

查询相关API前面的随笔已经写到 单表查询还有双下划线查询0.0

1、双下划线单表查询

技术分享
models.book.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
 
models.book.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
models.book.objects.exclude(id__in=[11, 22, 33])  # not in
 
models.book.objects.filter(name__contains="ven")  #模糊匹配
models.book.objects.filter(name__icontains="ven") # icontains大小写不敏感
 
models.book.objects.filter(id__range=[1, 2])      # 范围bettwen and
 
startswith,istartswith, endswith, iendswith 
技术分享

2、基于对象的跨表查询

1)一对多查询

正向查询

# 查询id=1的书籍的出版社所在的城市
book_obj=Book.objects.get(id=1)
print(book_obj.publish.city) 
# book_obj.publish 是id=1的书籍对象关联的出版社对象

反向查询

# 查询 人民出版社出版过的所有书籍
 
publish=Publish.objects.get(name="人民出版社")
book_list=publish.book_set.all()  # 与人民出版社关联的所有书籍对象集合
for book_obj in book_list:
    print(book_obj.title)

2)多对多查询

正向查询

技术分享
# 金瓶眉所有作者的名字
 
book_obj=Book.objects.filter(title="金瓶眉").first()
authors=book_obj.authorlish.all()
 
for author_obj in authors:
    print(author_obj.name)
技术分享

反向查询

# 查询egon出过的所有书籍的名字
author_obj=Author.objects.get(name="egon")
book_list=author_obj.book_set.all() #与egon作者相关的所有书籍
 
for book_obj in book_list:
    print(book_obj.title)

3、查询实例

1)views

技术分享 View Code

2)template——index.html

技术分享 View Code

4、基于双下划线的跨表查询

Django 还提供了一种直观而高效的方式在查询中表示关联关系那就是强大的双划线

技术分享
# 练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)
    # 正向查询 按字段:publish
    queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","price")

    # 反向查询 按表名:book
    queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__price")

# 练习2: 查询egon出过的所有书籍的名字(多对多)
    # 正向查询 按字段:authors:
    queryResult=Book.objects.filter(authors__name="yuan").values_list("title")

    # 反向查询 按表名:book
    queryResult=Author.objects.filter(name="egon").values_list("book__title","book__price")


# 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名
    # 正向查询
    queryResult=Book.objects.filter(publish__name="人民出版社").values_list("title","authors__name")
    # 反向查询
    queryResult=Publish.objects.filter(name="人民出版社").values_list("book__title","book__authors__age","book__authors__name")


# 练习4: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称
queryResult=Book.objects.filter(authors__authorDetail__telephone__regex="151").values_list("title","publish__name")
技术分享

练习四需要在本建表实例上添加一个authorDetail作者详细信息表将电话号等详细信息放进去与作者表建立一对一关联

5、聚合查询与分组查询

1)聚合:aggregate()

# 计算所有图书的平均价格
from django.db.models import Avg
Book.objects.all().aggregate(Avg(price))
#{‘price__avg‘: 34.35}

需要使用什么函数都要通过import导入 例如常用函数:Avg,Sum,Count,Max,Min

字典的key默认(字段名__函数名)也可以自己起名字average_price

Book.objects.aggregate(average_price=Avg(price‘))

一次也查询多个可以

Book.objects.aggregate(Avg(price‘), Max(price‘), Min(price‘))

2)分组:annotate() 

#统计每一本书的作者个数
bookList=Book.objects.annotate(authorsNum=Count(authors))
for book_obj in bookList:
    print(book_obj.title,book_obj.authorsNum)

annotate的返回值是querySet

3)练习

技术分享 View Code

 

五、修改表记录

修改和以前的一样还是update比较简单就不做详细解释了直接上实例

技术分享
def editbook(request,id) :
    # 点击保存POST提交
    if request.method == "POST" :
        # 提取数据
        id = request.POST.get("id")
        title = request.POST.get("title")
        author_name = request.POST.getlist("author")
        publishDate = request.POST.get("publishDate")
        prince = request.POST.get("prince")
        publish_name = request.POST.get("publish")
        # 出版社object
        publish_obj = models.Publish.objects.get(name=publish_name)
        # 移除旧关联
        book_obj = models.Book.objects.filter(id=id)[0]
        book_obj.authorlish.clear()
        

        # 更新图书表
        models.Book.objects.filter(id=id).update(title=title, publishDate=publishDate, prince=prince,publish_id=publish_obj)


        book_obj = models.Book.objects.filter(id=id)[0]
        # 添加新关联
        for i in author_name :
            print(i)
            obj = models.Author.objects.filter(name=i)[0]
            book_obj.authorlish.add(obj)
        return redirect("/index/")
技术分享

虽然修改比较简单就一句update搞定,可是因为现在图书表和作者表是多对多连接所以在更新图书表时需要清楚之前的连键和建立新的连接,语法在之前都有讲解在代码中也都标记出来了。


 

六、删除表记录

实例:

def delbook(request,id) :
    # 删除图书
    models.Book.objects.filter(id=id).delete()
    return redirect("/index/")

在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。


 

七、图书管理小练习(只贴上图书的增删改查代码)

1、model 建表

技术分享 View Code

2、template 模版

技术分享 index.html
技术分享 addbook.html
技术分享 editbook.html
技术分享 searchbook.html

3、url 分发

技术分享 View Code

4、views 视图函数

技术分享 View Code

5、部分效果图

1)首页

技术分享

2)添加图书

技术分享

3)修改图书信息

技术分享

4)搜索框搜索图书

技术分享

django-模型层(model)-多表相关操作(图书管理练习)

标签:first   了解   query   外键   blank   objects   对象   默认   creat   

原文地址:http://www.cnblogs.com/52forjie/p/7825255.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!