Django中模型层中ORM的多表操作

ORM的多表创建(一对一.一对多,多对多):

1模型创建

  实例:我们来假定下面这些概念,字段和关系

作者模型:一个作者有姓名和年龄。

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

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

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

模型建立如下:

1from django.db import models 2 3 4# Create your models here. 5 6class Book(models.Model): 7 id = models.AutoField(primary_key=True) # 可不填,Django会自动帮你写 8 title = models.CharField(max_length=32) 9 pub_date = models.DateField() 10 price = models.DecimalField(max_digits=5, decimal_places=2) 11 # 与Publish(id)建立一对多的外键关系 12 publish = models.ForeignKey(to="Publish", to_field="id", on_delete=models.CASCADE) 13 # 创建多对多的关系,不会添加外键,会另外创建表格 14 authors = models.ManyToManyField(to="Author") 15 16 def __str__(self): 17 return self.title 18 19 20class Publish(models.Model): 21 name = models.CharField(max_length=32) 22 city = models.CharField(max_length=32) 23 email = models.EmailField() 24 25 def __str__(self): 26 return self.name 27 28 29class Author(models.Model): 30 name = models.CharField(max_length=32) 31 age = models.IntegerField() 32 # 与authorDetail建立一对一的外键关系 33 authorDetail = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE) 34 35 def __str__(self): 36 return self.name 37 38 39class AuthorDetail(models.Model): 40 birthday = models.DateField() 41 phone = models.BigIntegerField() 42 addr = models.CharField(max_length=64) 43 44 def __str__(self): 45 return self.addr 46 47 48class Emp(models.Model): 49 name = models.CharField(max_length=32) 50 age = models.IntegerField() 51 salary = models.DecimalField(max_digits=8, decimal_places=2) 52 dep = models.CharField(max_length=32) 53 province = models.CharField(max_length=32) 54 55 def __str__(self): 56 return self.name 57 58 59class Article(models.Model): 60 title = models.CharField(max_length=32) 61 comment_num = models.IntegerField() 62 poll_num = models.IntegerField() 63 64 def __str__(self): return self.title

View Code

注意事项:

  •  表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称  
  • id 字段是自动添加的
  •  对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
  •  这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
  •  定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
  • 外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

2.多表记录的操作

2.1 多表操作之表记录的创建

  2.1.1一对一以及一对多记录的创建:

11 方式一 22 book = models.Book.objects.create(title="java",price=122,pub_date="2012-02-12",publish_id=1) 33 44 方式二 55 pub_obj = models.Publish.objects.filter(name="西瓜出版社").first() 66 book = models.Book.objects.create(title="PHP", price=122, pub_date="2014-02-12", publish = pub_obj) 77 print(book.title) 88 print(book.publish_id)

View Code

  2.1.2 多对多记录的创建

1######################### 绑定多对多的关系;无非是在关系表创建记录 ########################## 2 tips: 正向操作按字段,反向操作按表名小写(一定要记住) 3 4 为java这本书绑定两个作者: 大锤,尼玛(正向绑定): 5 添加方式一 6 java = models.Book.objects.filter(title="java").first() 7 dachui = models.Author.objects.filter(name="王大锤").first() 8 nima = models.Author.objects.filter(name="王尼玛").first() 9 print(java.price) 10 print(dachui.name) 11 print(nima.name) 12 java.authors.add(dachui,nima) 13 14 添加方式二 15 java.authors.add(2) 16 java.authors.add(*[3,2]) #添加的另外一种方式,较常用,[]内为对应作者的ID,*用于打散 17 18 移除两个作者与java的绑定关系 19 java.authors.remove(dachui, nima) # 将某个特定的对象从被关联对象集合中去除。== book_obj.authors.remove(*[]) 20 21 java.authors.clear() #清空被关联对象集合 22 23 重新赋值关系 24 java.authors.set([3,]) #重新设置值,先clear,在赋值 25 26 27 给王大锤作者绑定两本书籍: PHP,Go(反向绑定) 28 dachui = models.Author.objects.filter(name="王大锤").first() 29 PHP = models.Book.objects.filter(title="PHP").first() 30 Go = models.Book.objects.filter(title="Go").first() 31 方式一: 32 dachui.book_set.add(PHP, Go) ###此处因为是反向绑定采用的是 表名_set 33 方式二 34 dachui.book_set.add(*[3,4])

View Code

2.2多表操作之跨表查询

2.2.1基于对象的跨表查询

  总的查询思路

1基于对象的跨表查询( 子查询:以上一次的查询结果作为下一次的查询条件) 2 (1)一对多 3 正向查询:按字段 book.publish 4 Book对象 ---------------------------------- > Publish 对象 5 <--------------------------------- 6 反向查询:按表名小写_set.all() 7 8 9 (2)多对多 10 正向查询:按字段 book.authors.all() 11 Book对象 ---------------------------------- > Author 对象 12 <--------------------------------- 13 反向查询:按表名小写_set.all() 14 15 16 (2)一对一 17 正向查询:按字段 book.ad 18 Author 对象 ---------------------------------- > AuthorDetail 对象 19 <--------------------------------- 20 反向查询:按表名小写

  2.2.1.1 基于对象的一对多的跨表查询

1(1)一对多 2 3 1 查询PHP这本书籍的出版社的地址(正向查询) 4 addr = models.Book.objects.filter(title="PHP").first().publish.city 5 print(addr) 6 7 8 2 查询香蕉出版社出版的所有书籍(反向查询) 9 queryset = models.Publish.objects.filter(name="西瓜出版社").first().book_set.all() 10 print(queryset)

View Code

  2.2.1.2 基于对象的多对多的跨表查询

1(2)多对多 2 3 1 查询java书籍的所有作者 4 queryset = models.Book.objects.filter(title="java").first().authors.all() 5 print(queryset) 6 7 2 查询王大锤作者出版过得所有书籍 8 queryset = models.Author.objects.filter(name="王大锤").first().book_set.all() 9 print(queryset)

View Code

  2.2.1.3 基于对象的一对一的跨表查询

1(3)一对一 2 1 查询王大锤的手机号 3 phone = models.Author.objects.filter(name="王大锤").first().authorDetail.phone 4 print(phone) 5 6 2 查询手机号为123的作者的名字 7 name = models.AuthorDetail.objects.filter(phone="123").first().author.name 8 print(name)

View Code

2.2.2  基于双下划綫的跨表查询:

 KEY: 通知ORM引擎如何跨表: 正向查询按字段, 反向查询按表名小写

2.2.2.1基于双下划线的跨表查询(join查询)

1################基于双下划线的跨表查询(join查询)########################## 2 1 查询PHP这本书籍的出版社的地址 3 ''' 4 SELECT app01_publish.city from app01_book INNER JOIN app01_publish 5 ON app01_book.publish_id = app01_publish.id 6 WHERE app01_book.title ="PHP" 7 ''' 8方式1 9 queryset_addr = models.Book.objects.filter(title="PHP").values("publish__city") 10 print(queryset_addr) 11 12 方式2 13 queryset_addr = models.Publish.objects.filter(book__title="PHP").values("city") 14 print(queryset_addr) 15 16 17 2 查询java书籍的所有作者 18 queryset_author = models.Book.objects.filter(title="java").values("authors__name") 19 queryset_author = models.Book.objects.filter(title__startswith="P").values("authors__name") 20 print(queryset_author) 21 22 3 查询唐马儒的手机号 23 queryset_tel = models.Author.objects.filter(name="唐马儒").values("authorDetail__phone") 24 queryset_tel = models.AuthorDetail.objects.filter(author__name="唐马儒").values("phone") 25 print(queryset_tel)

View Code

2.2.2.2 连续跨表操作及其示例:

1连续跨表 2 4 查询西瓜出版社出版过的所有书籍的名字以及作者的姓名 3 queryset_info = models.Book.objects.filter(publish__name="西瓜出版社").values("title","authors__name") 4 queryset_info = models.Author.objects.filter(book__publish__name="西瓜出版社").values("book__title","name") 5 print(queryset_info) 6 7 5 手机号以151开头的作者出版过的所有书籍名称以及出版社名称 8 queryset_info = models.Book.objects.filter(authors__authorDetail__phone__startswith="1").values("title","publish__name") 9 print(queryset_info

View Code

2.2.3  聚合查询:

11 ######################聚合查询#############################3 22 aggregate() 33 44 from django.db.models import Avg,Max,Min,Count 55 1.计算所有人的平均工资 66 ret = models.Emp.objects.all().aggregate(平均工资=Avg("salary")) 77 print(re

2.2.4  单表分组查询:

1############## 单表分组查询 ############### 2查询每一个部门的人数 3 ret = models.Emp.objects.values("dep").annotate(Count("id")) 4 5查询省份名字有东的部门的人数 6 ret = models.Emp.objects.filter(province__contains="东").values("dep").annotate(c = Count("id")) 7 print(ret) 8 9# 查询每一个省份的平均薪水 10 ret = models.Emp.objects.values("province").annotate(avg_salary=Avg("salary")) 11 print(ret)

2.2.4  多表分组查询:

1############## 多表分组查询 ############### 2 3 1 查询每一个出版社的名字和出版过的书籍的平均价格 4 querryset = models.Publish.objects.values("name").annotate(avg_salary=Avg("book__price")) 5 querryset = models.Publish.objects.annotate(avg_salary=Avg("book__price")).values("name","avg_salary") 6 print(querryset) 7 8 2 查询每一个作者的名字以及出版书籍的个数 9 querryset = models.Author.objects.values("name").annotate(c = Count("book__id")) 10 querryset = models.Author.objects.annotate(c = Count("book__id")).values("name","c") 11 print(querryset) 12 13 3 查询每一个书籍的名称以及作者的个数 14 querryset = models.Book.objects.values("title").annotate(c = Count("authors__id")) 15 print(querryset) 16 17 18 4 查询作者个数大于1 的每一本书籍的名称和作者个数 19 20 querryset = models.Book.objects.annotate(c = Count("authors__id")).filter(c__gt=1).values("title","c") 21 print(querryset) 22 23 5 查询书籍名称包含"h"的书籍名称和作者个数 24 querryset = models.Book.objects.filter(title__contains="P").annotate(c = Count("authors__id")).values("title","c") 25 querryset = models.Book.objects.annotate(c=Count("authors__id")).filter(title__contains="P").values("title", "c") 26 print(querryset)

2.2.4  F与Q查询:

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

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

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

1##################################### F查询与Q查询 2 3 F查询 4 from django.db.models import F,Q,Avg 5 1 查询评论数大于100的文章 6 ret = models.Article.objects.filter(comment_num__gt=300) 7 print(ret) 8 9 2 查询评论数大于点赞数的文章 10 ret = models.Article.objects.filter(comment_num__gt=F("poll_num")) 11 print(ret) 12 13 14 3 查询评论数大于两倍点赞数 15 ret = models.Article.objects.filter(comment_num__gt = F("poll_num")*2) 16 print(ret) 17 18 4 将所有的书籍的价格提高10019 ret = models.Book.objects.update(price = F("price")+10) 20 print(ret) 21 22 23 Q查询 24 5 查询价格大于300或者名称以p开头的书籍 25 Q : & | ~ 26 ret = models.Book.objects.filter(Q(price__gt=150)|Q(title__startswith="P")) 27 print(ret) 28 29 # 5 查询价格大于300或者不是20122月份的书籍 30 ret = models.Book.objects.filter(Q(price__gt=140) | Q(Q(pub_date__year=2012)&Q(pub_date__month=2))) 31 ret = models.Book.objects.filter(Q(price__gt=140) | Q(pub_date__year=2012) & Q(pub_date__month=2)) 32 ret = models.Book.objects.filter(Q(price__gt=140) | Q(pub_date__year=2012,pub_date__month=2)) 33 print(ret)

View Code

详细请参考:ORM多表查询

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

Nginx + lua +[memcached,redis]

精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用

Django中Admin中的一些参数配置

设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable