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

Stella981
• 阅读 574

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

1模型创建

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

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

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

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

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

模型建立如下:

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

from django.db import models


# Create your models here.

class Book(models.Model):
    id = models.AutoField(primary_key=True)  # 可不填,Django会自动帮你写
    title = models.CharField(max_length=32)
    pub_date = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)
    # 与Publish(id)建立一对多的外键关系
    publish = models.ForeignKey(to="Publish", to_field="id", on_delete=models.CASCADE)
    # 创建多对多的关系,不会添加外键,会另外创建表格
    authors = models.ManyToManyField(to="Author")

    def __str__(self):
        return self.title


class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    # 与authorDetail建立一对一的外键关系
    authorDetail = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE)

    def __str__(self):
        return self.name


class AuthorDetail(models.Model):
    birthday = models.DateField()
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

    def __str__(self):
        return self.addr


class Emp(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    salary = models.DecimalField(max_digits=8, decimal_places=2)
    dep = models.CharField(max_length=32)
    province = models.CharField(max_length=32)

    def __str__(self):
        return self.name


class Article(models.Model):
    title = models.CharField(max_length=32)
    comment_num = models.IntegerField()
    poll_num = models.IntegerField()

    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一对一以及一对多记录的创建:

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

1  方式一
2     book = models.Book.objects.create(title="java",price=122,pub_date="2012-02-12",publish_id=1)
3 
4     方式二
5     pub_obj = models.Publish.objects.filter(name="西瓜出版社").first()
6     book = models.Book.objects.create(title="PHP", price=122, pub_date="2014-02-12", publish = pub_obj)
7     print(book.title)
8     print(book.publish_id)

View Code

  2.1.2 多对多记录的创建

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

######################### 绑定多对多的关系;无非是在关系表创建记录 ##########################
    tips: 正向操作按字段,反向操作按表名小写(一定要记住)

    为java这本书绑定两个作者: 大锤,尼玛(正向绑定):
    添加方式一
    java = models.Book.objects.filter(title="java").first()
    dachui = models.Author.objects.filter(name="王大锤").first()
    nima =  models.Author.objects.filter(name="王尼玛").first()
    print(java.price)
    print(dachui.name)
    print(nima.name)
    java.authors.add(dachui,nima)

    添加方式二
    java.authors.add(2)
    java.authors.add(*[3,2])   #添加的另外一种方式,较常用,[]内为对应作者的ID,*用于打散

    移除两个作者与java的绑定关系
    java.authors.remove(dachui, nima) # 将某个特定的对象从被关联对象集合中去除。== book_obj.authors.remove(*[])

    java.authors.clear() #清空被关联对象集合

    重新赋值关系
    java.authors.set([3,])  #重新设置值,先clear,在赋值


    给王大锤作者绑定两本书籍: PHP,Go(反向绑定)
    dachui = models.Author.objects.filter(name="王大锤").first()
    PHP = models.Book.objects.filter(title="PHP").first()
    Go = models.Book.objects.filter(title="Go").first()
    方式一:
    dachui.book_set.add(PHP, Go)   ###此处因为是反向绑定采用的是 表名_set
    方式二
    dachui.book_set.add(*[3,4])

View Code

2.2多表操作之跨表查询

2.2.1基于对象的跨表查询

  总的查询思路

  一 基于对象的跨表查询( 子查询:以上一次的查询结果作为下一次的查询条件)
       (1)一对多
                         正向查询:按字段 book.publish
         Book对象    ---------------------------------- >  Publish 对象
                      <---------------------------------
                        反向查询:按表名小写_set.all()


        (2)多对多
                       正向查询:按字段 book.authors.all()
         Book对象    ---------------------------------- >  Author 对象
                      <---------------------------------
                        反向查询:按表名小写_set.all()


        (2)一对一
                        正向查询:按字段 book.ad
         Author 对象   ---------------------------------- >  AuthorDetail 对象
                      <---------------------------------
                        反向查询:按表名小写

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

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

(1)一对多

    1 查询PHP这本书籍的出版社的地址(正向查询)
    addr = models.Book.objects.filter(title="PHP").first().publish.city
    print(addr)


    2 查询香蕉出版社出版的所有书籍(反向查询)
    queryset = models.Publish.objects.filter(name="西瓜出版社").first().book_set.all()
    print(queryset)

View Code

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

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

(2)多对多

    1 查询java书籍的所有作者
    queryset = models.Book.objects.filter(title="java").first().authors.all()
    print(queryset)

    2 查询王大锤作者出版过得所有书籍
    queryset = models.Author.objects.filter(name="王大锤").first().book_set.all()
    print(queryset)

View Code

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

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

(3)一对一
    1  查询王大锤的手机号
    phone = models.Author.objects.filter(name="王大锤").first().authorDetail.phone
    print(phone)

    2 查询手机号为123的作者的名字
    name = models.AuthorDetail.objects.filter(phone="123").first().author.name
    print(name)

View Code

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

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

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

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

################基于双下划线的跨表查询(join查询)##########################
    1 查询PHP这本书籍的出版社的地址
    '''
     SELECT app01_publish.city from app01_book INNER JOIN app01_publish 
                                  ON app01_book.publish_id = app01_publish.id 
                                  WHERE app01_book.title ="PHP"
    '''
方式1
    queryset_addr = models.Book.objects.filter(title="PHP").values("publish__city")
    print(queryset_addr)

    方式2
    queryset_addr = models.Publish.objects.filter(book__title="PHP").values("city")
    print(queryset_addr)


    2 查询java书籍的所有作者
    queryset_author = models.Book.objects.filter(title="java").values("authors__name")
    queryset_author = models.Book.objects.filter(title__startswith="P").values("authors__name")
    print(queryset_author)

    3  查询唐马儒的手机号
    queryset_tel = models.Author.objects.filter(name="唐马儒").values("authorDetail__phone")
    queryset_tel = models.AuthorDetail.objects.filter(author__name="唐马儒").values("phone")
    print(queryset_tel)

View Code

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

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

连续跨表
    4 查询西瓜出版社出版过的所有书籍的名字以及作者的姓名
    queryset_info = models.Book.objects.filter(publish__name="西瓜出版社").values("title","authors__name")
    queryset_info = models.Author.objects.filter(book__publish__name="西瓜出版社").values("book__title","name")
    print(queryset_info)

    5 手机号以151开头的作者出版过的所有书籍名称以及出版社名称
    queryset_info = models.Book.objects.filter(authors__authorDetail__phone__startswith="1").values("title","publish__name")
    print(queryset_info

View Code

2.2.3  聚合查询:

1 ######################聚合查询#############################3
2     aggregate()
3 
4     from django.db.models import Avg,Max,Min,Count
5     1.计算所有人的平均工资
6     ret = models.Emp.objects.all().aggregate(平均工资=Avg("salary"))
7     print(re

2.2.4  单表分组查询:

############## 单表分组查询  ###############
查询每一个部门的人数
    ret = models.Emp.objects.values("dep").annotate(Count("id"))

查询省份名字有东的部门的人数
    ret = models.Emp.objects.filter(province__contains="东").values("dep").annotate(c = Count("id"))
    print(ret)

# 查询每一个省份的平均薪水
    ret = models.Emp.objects.values("province").annotate(avg_salary=Avg("salary"))
    print(ret)

2.2.4  多表分组查询:

############## 多表分组查询  ###############

    1 查询每一个出版社的名字和出版过的书籍的平均价格
    querryset = models.Publish.objects.values("name").annotate(avg_salary=Avg("book__price"))
    querryset = models.Publish.objects.annotate(avg_salary=Avg("book__price")).values("name","avg_salary")
    print(querryset)

    2 查询每一个作者的名字以及出版书籍的个数
    querryset = models.Author.objects.values("name").annotate(c = Count("book__id"))
    querryset = models.Author.objects.annotate(c = Count("book__id")).values("name","c")
    print(querryset)

    3 查询每一个书籍的名称以及作者的个数
    querryset = models.Book.objects.values("title").annotate(c = Count("authors__id"))
    print(querryset)


    4 查询作者个数大于1 的每一本书籍的名称和作者个数

    querryset = models.Book.objects.annotate(c = Count("authors__id")).filter(c__gt=1).values("title","c")
    print(querryset)

    5 查询书籍名称包含"h"的书籍名称和作者个数
    querryset = models.Book.objects.filter(title__contains="P").annotate(c = Count("authors__id")).values("title","c")
    querryset = models.Book.objects.annotate(c=Count("authors__id")).filter(title__contains="P").values("title", "c")
    print(querryset)

2.2.4  F与Q查询:

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

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

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

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

##################################### F查询与Q查询

     F查询
    from django.db.models import F,Q,Avg
    1 查询评论数大于100的文章
    ret = models.Article.objects.filter(comment_num__gt=300)
    print(ret)

    2 查询评论数大于点赞数的文章
    ret = models.Article.objects.filter(comment_num__gt=F("poll_num"))
    print(ret)


    3 查询评论数大于两倍点赞数
    ret = models.Article.objects.filter(comment_num__gt = F("poll_num")*2)
    print(ret)

    4 将所有的书籍的价格提高100元
    ret = models.Book.objects.update(price = F("price")+10)
    print(ret)


    Q查询
    5 查询价格大于300或者名称以p开头的书籍
    Q : & | ~
    ret = models.Book.objects.filter(Q(price__gt=150)|Q(title__startswith="P"))
    print(ret)

    # 5 查询价格大于300或者不是2012年2月份的书籍
    ret = models.Book.objects.filter(Q(price__gt=140) | Q(Q(pub_date__year=2012)&Q(pub_date__month=2)))
    ret = models.Book.objects.filter(Q(price__gt=140) | Q(pub_date__year=2012) & Q(pub_date__month=2))
    ret = models.Book.objects.filter(Q(price__gt=140) | Q(pub_date__year=2012,pub_date__month=2))
    print(ret)

View Code

详细请参考:ORM多表查询

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
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
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
ThinkPHP 根据关联数据查询 hasWhere 的使用实例
很多时候,模型关联后需要根据关联的模型做查询。场景:广告表(ad),广告类型表(ad\_type),现在需要筛选出广告类型表中id字段为1且广告表中status为1的列表先看关联的设置部分 publicfunctionadType(){return$thisbelongsTo('A
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
京东云开发者 京东云开发者
4个月前
直播预告 | 大模型时代 “应用变了”:看大模型如何跑进零售电商应用
走进零售电商,大模型能做什么?今年11.11,应用大模型带来成效显著今天下午2:00,京东云视频号准时直播看京东零售如何破题新解法,大小模型协同大模型将走向多模态,走向具身智能
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这