多表操作:

创建模型:

  作者模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

  出版商模型:出版商有名称,所在城市以及email。

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

  模型建立如下:

from django.db import models

# Create your models here.

class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
# 与 AuthorDetail建立一对一关系
author_detail = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE) class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
birthday = models.DateField()
tel = models.IntegerField()
addr = models.CharField(max_length=32) class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField() class Book(models.Model):
title = models.CharField(max_length=32)
pub_date = models.DateField()
price = models.DecimalField(max_digits=6,decimal_places=2) # 与Publish建立一对多关系,外键建立在 多 的一方
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) # 与Author 建立多对多关系,ManyTOManyField 可以建在两个模型中的任意一个,将会自动建立第三个对应表。
authors = models.ManyToManyField(to='Author')

注意事项:

  1,id 字段可以不写,django会自动生成主键id.

  2,对于外键字段,django会在字段名上添加'_id'来创建数据库中的列名。例如:'publish'  会生成‘publish_id’。

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

添加表记录:

  一对多:

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

  多对多:

  # 当前生成的书籍对象
book_obj=Book.objects.create(title="追风筝的人",price=200,publishDate="2012-11-12",publish_id=1)
# 为书籍绑定的做作者对象
yuan=Author.objects.filter(name="yuan").first() # 在Author表中主键为2的纪录
egon=Author.objects.filter(name="alex").first() # 在Author表中主键为1的纪录 # 绑定多对多关系,即向关系表book_authors中添加纪录
book_obj.authors.add(yuan,egon) # 将某些特定的 model 对象添加到被关联对象集合中。 ======= book_obj.authors.add(*[])

  多对多关系其他常用API:

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

基于对象的跨表查询:

  一对多查询:(Publish 与 Book)

  正向查询(按字段:publish):关联属性在的类向关联的类查询的方向是正向,反之则是反向。

# 查询主键为5的书籍的出版社所在的城市
book_obj = Book.objects.filter(id=5).first()
print(book_obj.publish.city)
# 北京

  反向查询(按表名(全部小写):book_set)

# 查询是苹果出版社出的书的名字和价格
pub_obj = Publish.objects.filter(name='苹果出版社').first()
# 记住记住,如果是单个信息这里一定是一个对象,而不是QuerySet.
print(pub_obj.book_set.all().values('title','price'))
# <QuerySet [{'title': '西游记', 'price': Decimal('128.00')}, {'title': '三国演义', 'price': Decimal('128.00')}]>

一对一查询:(Author 与 AuthorDetail)

  由于是一对一查询,所以正反向都是一样的。

  正向查询(按字段:author_detail)

# 查询作者egon的电话号码
egon = Author.objects.filter(name='egon').first()
print(egon.author_detail.tel) #

  反向查询:(按表名(小写):author):

# 查询所有住址在北京的作者的姓名
add_obj = AuthorDetail.objects.filter(addr='北京')
for i in add_obj:
print(i.author.name)
# 注意注意:这里的反向查询并没有 _set

多对多查询:(Author 与 Book)

  正向查询:(按字段:author_detail)

# 查询西游记所有作者的名字以及手机号
book_obj = Book.objects.filter(title='西游记').first()
print(book_obj.authors.all().values('name','author_detail__tel'))
# 这里获取手机号属于多表查询方法,后面会讲
# <QuerySet [{'name': 'alex', 'author_detail__tel': 110}, {'name': 'egon', 'author_detail__tel': 911}]>

  反向查询:(按表名:boot_set)

# 查询egon出过的所有书籍的名字
egon = Author.objects.filter(name='egon').first()
print(egon.book_set.all().values('title'))
# <QuerySet [{'title': '西游记'}, {'title': '水浒传'}, {'title': '三国演义'}]>

注意:在通过ForeignKey() 和 ManyToManyField 的定义中设置的 related_name 的值来覆写 Foo_set 的名称。

例如:publish = ForeignKey(Book, related_name='bookList')

那么接下来就会如我们看到这般:

查询 人民出版社出版过的所有书籍:

  publish=Publish.objects.get(name="人民出版社")
  book_list=publish.bookList.all()  # 与人民出版社关联的所有书籍对象集合
 

基于双下划线的跨表查询:

  正向查询按字段,反向查询按表名小写来告诉ORM引擎join哪张表。

  一对多查询:

# 练习:  查询苹果出版社出版过的所有书籍的名字与价格(一对多)
# 正向查询:
obj = Book.objects.filter(publish__name='苹果出版社').values('title','price')
# 双下划线的跨表查询,正向直接按 字段__(双下划线)属性
# 最后用values取值
print(obj)
# <QuerySet [{'title': '西游记', 'price': Decimal('128.00')}, {'title': '三国演义', 'price': Decimal('128.00')}]>
# 反向查询:
obj = Publish.objects.filter(name='苹果出版社').values('book__title','book__price')
print(obj)
# <QuerySet [{'book__price': Decimal('128.00'), 'book__title': '西游记'}, {'book__price': Decimal('128.00'), 'book__title': '三国演义'}]>

  多对多查询:

    # 练习: 查询alex出过的所有书籍的名字(多对多)
# 正向查询:按字段
obj1 = Book.objects.filter(authors__name='alex').values('title')
print(obj1)
# < QuerySet[{'title': '西游记'}, {'title': '红楼梦'}, {'title': '三国演义'}] >
# 反向查询:按表名
obj2 = Author.objects.filter(name='alex').values('book__title')
print(obj2)
# < QuerySet[{'book__title': '西游记'}, {'book__title': '红楼梦'}, {'book__title': '三国演义'}] >

  一对一查询:  

# 查询alex的手机号
# 正向查询:
obj = Author.objects.filter(name='alex').values('author_detail__tel')
print(obj)
# < QuerySet[{'author_detail__tel': 110}] >
# 反向查询:
obj = AuthorDetail.objects.filter(author__name='alex').values('tel')
print(obj)
# < QuerySet[{'tel': 110}] >

连续跨表:

# 练习: 查询苹果出版社出版过的所有书籍的名字以及作者的姓名
# 正向查询:
obj = Book.objects.filter(publish__name='苹果出版社').values('title','authors__name')
print(obj)
# < QuerySet[{'title': '西游记', 'authors__name': 'alex'}, {'title': '三国演义', 'authors__name': 'alex'}, {'title': '西游记',
# 'authors__name': 'egon'}, {
# 'title': '三国演义', 'authors__name': 'egon'}] >
# 反向查询:
obj = Publish.objects.filter(name='苹果出版社').values('book__title','book__authors__name')
print(obj)
# < QuerySet[{'book__title': '西游记', 'book__authors__name': 'alex'}, {'book__title': '三国演义',
# 'book__authors__name': 'alex'}, {
# 'book__title': '西游记', 'book__authors__name': 'egon'}, {'book__title': '三国演义',
# 'book__authors__name': 'egon'}] >
# 由于出版社和作者并没有联系,所以只能通过book来查询。
# 练习: 手机号为110的作者出版过的所有书籍名称以及出版社名称
# 正向查询:
obj = Book.objects.filter(authors__author_detail__tel='').values('title','publish__name')
print(obj)
# < QuerySet[{'title': '西游记', 'publish__name': '苹果出版社'}, {'title': '红楼梦', 'publish__name': '橘子出版社'}, {'title': '三国演义',
# 'publish__name': '苹果出版社'}] >
# 反向查询:
obj = Publish.objects.filter(book__authors__author_detail__tel='').values('book__title','name')
print(obj)
# <QuerySet [{'book__title': '西游记', 'name': '苹果出版社'}, {'book__title': '红楼梦', 'name': '橘子出版社'}, {'book__title': '三国演义', 'name': '苹果出版社'}]>

related_name:

  反向查询时,如果定义了related_name,则用related_name替换表名,例如:

  publish = ForeignKey(Blog,relate_name='booklist')

# 练习: 查询人民出版社出版过的所有书籍的名字与价格(一对多)

# 反向查询 不再按表名:book,而是related_name:bookList

    queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("bookList__title","bookList__price")

聚合查询与分组查询:

  聚合:aggregate(*args,**kwargs)

# 计算所有图书的平均价格
from django.db.models import Avg
ret = Book.objects.all().aggregate(avg_price=Avg('price'))
print(ret)
# 可以自己取变量名{'avg_price': 118.0},若是不取会系统默认拼接变量名

  aggregate() 是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典,键的名称是聚合值得标识符,值是计算出来的聚合值。键得名称是按照字段和聚合函数的名称自动生成出来的,也可以自定义名称。

  如果你想生成不止一个聚合,可以在aggregate()子句中添加另一个参数。

from django.db.models import Avg,Max
ret = Book.objects.all().aggregate(Avg('price'),Max('price'))
print(ret)
# {'price__avg': 118.0, 'price__max': Decimal('128.00')}

分组:

  单表分组查询:

###################################--单表分组查询--#######################################################

查询每一个部门名称以及对应的员工数

emp:

id  name age   salary    dep
1 alex 12 2000 销售部
2 egon 22 3000 人事部
3 wen 22 5000 人事部 sql 语句:
SELECT dep,count(1) from app01_emp GROUP BY dep; ORM:
ret = Emp.objects.values('dep').annotate(c= Count(1))
# values里的字段,相当于对这个字段进行分组,annotate里使用函数,
# 相当于在分组后的新表中添加一个新的字段,且必须起别名,如上:c(别名) = Count(1)
print(ret)
# < QuerySet[{'dep': '销售部', 'c': 1}, {'dep': '人事部', 'c': 2}] >
# 结果是一个QuerySet类型的值

  多表分组查询:

emp:

id  name age   salary   dep_id
1 alex 12 2000 1
2 egon 22 3000 2
3 wen 22 5000 2 dep id name
1 销售部
2 人事部 emp-dep: id name age salary dep_id id name
1 alex 12 2000 1 1 销售部
2 egon 22 3000 2 2 人事部
3 wen 22 5000 2 2 人事部 sql语句:
SELECT app01_dep.name,count(1) from app01_emp2 inner join app01_dep on app01_emp2.dep_id = app01_dep.id GROUP BY dep_id; ORM:
ret = Dep.objects.values('id').annotate(c = Count('emp2__id')).values('name','c')
# 多表查询annotate中的是要连表的表名。
print(ret)
# <QuerySet [{'c': 1, 'name': '销售部'}, {'c': 2, 'name': '人事部'}]>

F查询与Q查询:

  F查询:

  在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

  Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

# 查询评论数大于收藏数的书籍

   from django.db.models import F
Book.objects.filter(commnetNum__lt=F('keepNum'))

  Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

# 查询评论数大于收藏数2倍的书籍
Book.objects.filter(commnetNum__lt=F('keepNum')*2)

  修改操作也可以使用F函数,比如将每一本书的价格提高30元:

ret = Book.objects.all().update(price=F('price')+30)
print(ret)
return HttpResponse('query')

  Q查询:

  filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象

from django.db.models import Q
Q(title__startswith='Py')

  Q 对象可以使用& 和 | 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

  等同于下面的SQL WHERE 子句:

WHERE name ="yuan" OR name ="egon"

  你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")

  查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
title__icontains="python"
)

Django 模型层(2)的更多相关文章

  1. django 模型层(2)

    Django 模型层(2) 多表操作---模型之间的关系 1 一对一:作者----作者详细信息 2 一对多:书籍----出版社 3 多对多:书籍----作者 一  创建模型(主键(id)自动创建) 没 ...

  2. Django模型层(2)

    <!DOCTYPE html><html lang="zh-cn"><head><meta charset="utf-8&quo ...

  3. {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询

    Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...

  4. Django模型层之ORM

    Django模型层之ORM操作 一 ORM简介 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数据库管理软 ...

  5. Django模型层之单表操作

    Django模型层之单表操作 一 .ORM简介 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数据库管理软 ...

  6. Django模型层之更多操作

    Django模型层之更多操作 一 .ORM字段 1.1 常用字段 AutoField int自增列,必须填入参数 primary_key=True.当model中如果没有自增列,则自动会创建一个列名为 ...

  7. Django模型层(各种表及表数据的操作)

    目录 一.Django模型层 0. django模型层的级联关系 1. 配置django测试脚本 (1)方式一 (2)方式二 2. orm表数据的两种增删改 (1)方式一: (2)方式二: 3. pk ...

  8. day 70 Django基础五之django模型层(二)多表操作

    Django基础五之django模型层(二)多表操作   本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 ORM ...

  9. day 69 Django基础五之django模型层(一)单表操作

    Django基础五之django模型层(一)单表操作   本节目录 一 ORM简介 二 单表操作 三 章节作业 四 xxx 一 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现 ...

  10. day 57 Django基础五之django模型层之关联管理器

    Django基础五之django模型层之关联管理器   class RelatedManager "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器.它存在于下面两种情况 ...

随机推荐

  1. JS跨页面或跨JS文件对变量赋值

    JS跨页面或跨JS文件对变量赋值,这是很小的一个问题. 但问题虽小,却总觉得有点不够自然,不爽. 为什么呢?访问一个页面上的变量不是什么难事,比如用parent.变量名,或者windows名.变量名, ...

  2. Android Studio3.0 Kotlin工程问题集

    问题1: 新建支持Kotlin的Android项目,卡在"Resolve dependency :classpath" 解决分析: 一般碰到"Resolve depend ...

  3. 【剑指offer】连续子数组的最大和,C++实现

    原创博文,转载请注明出处!本题牛客网地址 博客文章索引地址 博客文章中代码的github地址 # 题目       输入一个整形数组,数组里有正数也有负数.数组中的一个或连续多个整数组成一个子数组.求 ...

  4. 为Linux服务器的SSH登录启用Google两步验证

    对于Linux服务器而言使用密钥登录要比使用密码登录安全的多,毕竟当前网上存在多个脚本到处进行爆破. 这类脚本都是通过扫描IP端的开放端口并使用常见的密码进行登录尝试,因此修改端口号也是非常有必要的. ...

  5. del语句的总结

    删除属性 del 语句 可以删除对象(实例)的属性 语法: del 对象.实例变量名 del 语句 del 变量名 删除变量 del name del 列表[整数表达式] 删除列表中的元素 del L ...

  6. L2-017. 人以群分

    社交网络中我们给每个人定义了一个“活跃度”,现希望根据这个指标把人群分为两大类,即外向型(outgoing,即活跃度高的)和内向型(introverted,即活跃度低的).要求两类人群的规模尽可能接近 ...

  7. 重温CLR(十二) 委托

    回调函数是一种非常有用的编程机制,它的存在已经有很多年了..NET通过委托来提供回调函数机制.不同于其他平台(比如非托管C++)的回调机制,委托的功能要多得多.例如,委托确保回调方法是类型安全的(这是 ...

  8. 《DSP using MATLAB》示例Example 6.8

    今天情人节,又在外地出差,苦逼中…… 继续写读书笔记吧. 代码: % All-Zeros FIR filter to Lattice structure filter b = [2, 13/12, 5 ...

  9. 【DUBBO】 Dubbo原理解析-Dubbo内核实现之基于SPI思想Dubbo内核实现

    转载:http://blog.csdn.net/quhongwei_zhanqiu/article/details/41577235 SPI接口定义 定义了@SPI注解 public @interfa ...

  10. UVA11538 Chess Queen

    题意 给一个\(n \times m\)的棋盘,输出有多少种方法放置两个互相攻击的皇后. \(n,m \leq 10^6\) 分析 参照刘汝佳的题解. 横.竖.斜三种情况互不相干,加法原理统计. 横竖 ...