Django ORM多表操作

时间:2021-08-18 00:34:03

多表操作

创建模型

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

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

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

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

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

模型建立如下:

from django.db import models

# Create your models here.

# 出版社表

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 AuthorDetail(models.Model):
uid = models.AutoField(primary_key=True)
name= models.CharField(max_length=32)
tel = models.BigIntegerField()
addr = models.CharField(max_length=255) # 作者表 class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
# 建立外键关联(一对一关系:建立在哪张表都可以,一对一要使用onetoone)
# AuthorDetail = models.OneToOneField(to='AuthorDetail',to_field='nid') 如果不添加一个on_delete,会在迁移数据库时报错
AuthorDetail = models.OneToOneField(to='AuthorDetail',to_field='uid',on_delete=models.CASCADE) #书籍表 class Book(models.Model):
bid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2) # 建立外键关联(一对多关系:一个出版社可以出版多本书籍,关联要建在多的那张表中(book表))
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE) # 多对多关系:manytomany,只需要to另外一张表就OK了, author = models.ManyToManyField(to="Author") '''
上面的author语句相当于执行下面的sql语句:
create table book2author(
id int auto_increment,
book_id int ,
author_id int,
foreign key (book_id) references book(id),
foreign key (author_id) refernces author(id) ) '''

表字段模型

然后通过 python manage.py makemigrations和 python manage.py migrate来迁移数据库(记得要导入pymysql和在settings中设置DATABASE)

注意事项:

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

添加表记录

一对一

 # publish = Publish.objects.create(name='人民出版社',city="北京",email="people@people.com")
# print(publish)
#--------------------------------添加一对多关联记录------------------------------------
# 添加书籍和出版社信息
# 方式一:
# book_obj = Book.objects.create(name="三国演义",price=85.5,publish_id=1)
# print(book_obj)
# print(book_obj.publish) # 注意:这个publish是与这本书籍相关联的出版社对象
# 方式二:
# pub_obj = Publish.objects.filter(name='人民出版社').first()
# orm会自动把最后一个参数pub_obj的主键取出
# book_obj = Book.objects.create(name="三国演义2", price=85.5, publish=pub_obj)
# print(book_obj.name)
'''
在添加书籍时,无论是是以publish_id=1,还是publish=pub_obj,最终都会生成一个publish对象 ''' # print(book_obj.publish) #注意:book_obj.publish是与这本书籍相关联的出版社对象
# print(book_obj.publish.email) #取书籍对应的email

多对多

# --------------------------------添加多对多关联记录------------------------------------
# book_obj = Book.objects.create(name='白雪公主',price=99,publish_id=1) # 取作者对象,注意,这里要取的是一个obj,而不是一个queryset对象,如果是qset对象,则会报错.如果用qset对象来添加的话,可以使用book_obj.author.add(nick.first().id,joseph.first().id)
# nick = Author.objects.filter(name='nick').first()
# joseph = Author.objects.filter(name='joseph').first()
# print(nick.first().id)
# 取obj对象方法二:
# nick = Author.objects.get(name='nick')
# joseph = Author.objects.get(name='joseph')
# print(nick)
#
# book_obj.author.add(nick,joseph)
# book_obj.author.add(1,2,3)
# book_obj.author.add(*[1,2,3])
# book_obj.author.add(nick.first().id,joseph.first().id)
# # 移除对应关系
# book_obj = Book.objects.filter(name='追风筝的人').first()
# book_obj.author.remove(2) # 移除书籍所有的作者对应信息 # book_obj.author.clear() # 查询与书籍相关的所有作者对象,qset对象,book_obj.author.all()是一个作者集合的queryset对象
book_obj = Book.objects.filter(name='白雪公主').first()
ret = book_obj.author.all()
print(ret.values_list('name'))

基于对象的跨表查询

'''
两张有关系的表,A和B,关联字段在A表中.
正向查询:从A表查询B表中的内容,正向查询按 字段
反向查询:从B表查询A表中的内容,反向查询按 表名小写_set.all() 一对多查询:
正向查询:从A表查询B表中的内容,正向查询按 字段
反向查询:从B表查询A表中的内容,反向查询按 表名小写_set.all()
正向查询: book_obj.publish.email:关联属性在book表中是publish,所以查email用publish.email,也就是关联属性(对象)的属性
book(关联对象:publish)------------------------------------>publish
反向查询:book_obj.book_set.all()
publish--------------------------------->book 多对多查询:
正向查询:从A表查询B表中的内容,正向查询按 字段
反向查询:从B表查询A表中的内容,反向查询按 表名小写_set.all()
正向查询(查书籍作者): book_obj.author.all()
book(关联对象:author)-------------------------------------------------------------->author
反向查询(查作者所有书籍):author.book_set.all()
author------------------------------------------------------------>book 一对一查询:
正向查询:从A表查询B表中的内容,正向查询按 字段
反向查询:从B表查询A表中的内容,反向查询按 表名小写
正向查询(查作者详细信息): author.AuthorDetail.tel
author(关联对象:authorDetail)-------------------------------------------->authorDetail
反向查询(查作者所有书籍):auth.name
authorDetail------------------------------------------------------------>author '''

一对多表记录查询

    # 一对多的正向查询: 1 查询白雪公主这本书的出版的邮箱

    ret =Book.objects.filter(name='白雪公主').first().publish.email
print('<白雪公主>的出版社email:',ret)
# 一对多的反向查询:2 查询人民出版社出版的所有书籍 # ret = Publish.objects.filter(name='人民出版社').first().book_set.all()
book_obj = Publish.objects.filter(name='人民出版社').first()
book_obj.book_set.all()
print(book_obj.book_set.all())
for obj in ret:
print(obj.name,obj.publish.name)

查询语法:

'''
两张有关系的表,A和B,关联字段在A表中.
正向查询:从A表查询B表中的内容,正向查询按 字段
反向查询:从B表查询A表中的内容,反向查询按 表名小写_set.all() 一对多查询:
正向查询:从A表查询B表中的内容,正向查询按 字段
反向查询:从B表查询A表中的内容,反向查询按 表名小写_set.all()
正向查询: book_obj.publish.email:关联属性在book表中是publish,所以查email用publish.email,也就是关联属性(对象)的属性
book(关联对象:publish)------------------------------------>publish
反向查询:book_obj.book_set.all()
publish--------------------------------->book '''

多对多正反向查询

   # 1.正向查询:查询白雪公主这本书的作者
book_obj = Book.objects.filter(name='白雪公主').first()
book_obj.author.all() #书籍的所有作者信息,qset对象
for obj in book_obj.author.all():
print(obj.name) # 2.反向查询:查询nick出版的所有书籍 author = Author.objects.filter(name='nick').first()
ret = author.book_set.all()
for obj in ret:
print(obj.name)

语法:

'''
多对多查询:
正向查询:从A表查询B表中的内容,正向查询按 字段
反向查询:从B表查询A表中的内容,反向查询按 表名小写_set.all()
正向查询(查书籍作者): book_obj.author.all()
book(关联对象:author)-------------------------------------------------------------->author
反向查询(查作者所有书籍):author.book_set.all()
author------------------------------------------------------------>book '''

一对一正反向查询

# 1.正向查询:查询作者nick的详细信息
author = Author.objects.filter(name='nick').first()
print(author.AuthorDetail.tel) # 2.反向查询:查询作者id=2的作者名称
auth = Author.objects.filter(id=2).first() #拿到的是一个obj对象,可以直接通过点语法获取属性
print(auth.name)

语法:

'''
一对一查询:
正向查询:从A表查询B表中的内容,正向查询按 字段
反向查询:从B表查询A表中的内容,反向查询按 表名小写
正向查询(查作者详细信息): author.AuthorDetail.tel
author(关联对象:authorDetail)-------------------------------------------->authorDetail
反向查询(查作者所有书籍):auth.name
authorDetail------------------------------------------------------------>author '''

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

'''

基于双下划线的多表查询
正向查询按字段
反向查询按表名小写,按表名小写是告诉ORM用来join哪个表 1.正向查询白雪公主这本书的出版社名称
SQL语句:
select app01_publish.name from app01_book inner join app01_publish
on app01_book.publish_id = app01_publish.nid
where app01_book.name='白雪公主'; ORM语句: ret = book.objects.filter(name='白雪公主').values('publish__name')
注意,这是正向查询,所以这里是publish是指的book表中的publish字段(其实拿到的还是Publish表)
,而不是Publish表 filter(name='白雪公主'):相当于sql中的where语句 values():则相当于select的内容 1.反向查询白雪公主这本书的出版社名称 SQL:
select app01_publish.name from app01_publish inner join app01_book
on app01_publish.nid = app01_book.publish_id
where app01_book.name='白雪公主'; ORM语句:
ret =Publish.objects.filter(book__name='白雪公主').values('name') filter(book__name='白雪公主'):告诉ORM引擎,inner join book表,然后查询name=白雪公主的书籍
values('name'):拿到和白雪公主这本书籍相对应的出版社的名字 '''

跨表查询的本质:把多个表join成一张表,然后进行分组查询!

跨表查询总结:
每个后表模型.objects.values('基表主键 pk').annotate(聚合函数(关联表__查询字段)).values('表模型的所拥有的字段','聚合函数字段')
例如:查询每个作者的名字以及出版过的书籍的最高价格
这里每个后面的字符,就是基表,这个基表就是作者表

一对多正向查询

  # 正向查询:查白雪公主这本书籍的出版社名称
ret = Book.objects.filter(name='白雪公主').values('publish__name')
print(ret)
for name in ret:
print(name.get('publish__name'))
'''
正向查询按字段
反向查询按表名小写,按表名小写是告诉ORM用来join哪个表 1.正向查询白雪公主这本书的出版社名称
SQL语句:
select app01_publish.name from app01_book inner join app01_publish
on app01_book.publish_id = app01_publish.nid
where app01_book.name='白雪公主'; ORM语句: ret = book.objects.filter(name='白雪公主').values('publish__name')
注意,这是正向查询,所以这里是publish是指的book表中的publish字段(其实拿到的还是Publish表)
,而不是Publish表 filter(name='白雪公主'):相当于sql中的where语句 values():则相当于select的内容
'''
 

一对多反向查询

 # 反向查询:查白雪公主这本书籍的出版社名称
ret =Publish.objects.filter(book__name='白雪公主').values('name')
print(ret)
'''
1.反向查询白雪公主这本书的出版社名称 SQL:
select app01_publish.name from app01_publish inner join app01_book
on app01_publish.nid = app01_book.publish_id
where app01_book.name='白雪公主'; ORM语句:
ret =Publish.objects.filter(book__name='白雪公主').values('name') filter(book__name='白雪公主'):告诉ORM引擎,inner join book表,然后查询name=白雪公主的书籍
values('name'):拿到和白雪公主这本书籍相对应的出版社的名字 '''

多对多正向查询

#--------------多对多跨表查询

    # 正向多表查询:查询白雪公主这本书的所有作者的名字
'''正向查询按关联表的字段,下面是SQL语句
select app01_author.name
from app01_book inner join app01_book_author on app01_book.bid = app01_book_author.book_id
inner join app01_author on app01_book_author.author_id=app01_author.id
where app01_book.name='白雪公主';
'''
ret = Book.objects.filter(name='白雪公主').values('author__name')#这里的author是Book表中关联的字段
print(ret)

多对多反向查询

 # 反向多表查询:查询白雪公主这本书的所有作者的名字
'''
SQL:
select app01_author.name from app01_author inner join app01_book_author
on app01_author.id = app01_book_author.author_id
inner join app01_book
on app01_book.bid = app01_book_author.book_id
where app01_book.name='白雪公主';
  反向查询按表名__字段值
'''
ret = Author.objects.filter(book__name='白雪公主').values('name')
print(ret)

一对一正向查询

 #1.正向查询:查询作者nick的电话号码
'''正向是按照字段名称(必须和对应的字段名称大小写一致)
流程:通过author表join与其关联的authordetail表,按照字段AuthorDetail(我在author表中设置的字段就是大写开头的),告诉ORM引擎
inner join authordetail 表,使用'表名__tel'来取出所需要的电话号码
'''
ret =Author.objects.filter(name='nick').values('AuthorDetail__tel')
print(ret)

一对一反向查询

    #2.反向查询:查询作者nick的电话号码
'''反向查询:按照表名小写.values('tel'),相当于select tel,filter() 相当于 where
流程:通过authordetail表join与其关联的author表,按照表名小写(author__name),告诉ORM引擎来inner join author表 '''
ret=AuthorDetail.objects.filter(author__name='nick').values('tel')
print(ret)

跨多表查询

#1.查询手机号码以133开头的作者姓名,出版过的书籍,以及出版社名称
'''
SQL:
select app01_book.name as book_name,app01_publish.name as publish_name,app01_author.name as author_name
from app01_book inner join app01_book_author
on app01_book.bid = app01_book_author.book_id
inner join app01_author
on app01_book_author.author_id = app01_author.id
inner join app01_publish
on app01_book.publish_id = app01_publish.nid
inner join app01_authordetail
on app01_authordetail.uid = app01_author.id
where app01_authordetail.tel like "%133%"; ''' ret = Book.objects.filter(author__AuthorDetail__tel__startswith='').values('publish__name','author__name')
print(ret)

Django ORM多表操作的更多相关文章

  1. django ORM单表操作

    1.ORM介绍 ORM是“对象-关系-映射”的简称 映射关系: mysql---------Python 表名----------类名 字段----------属性 表记录--------实例化对象 ...

  2. django框架基础-ORM单表操作-长期维护

    ###############    单表操作-添加数据    ################ import os if __name__ == '__main__': os.environ.set ...

  3. Django框架06 &sol;orm多表操作

    Django框架06 /orm多表操作 目录 Django框架06 /orm多表操作 1. admin相关操作 2. 创建模型 3. 增加 4. 删除 5. 修改 6. 基于对象的跨表查询 7. 基于 ...

  4. Django框架05 &sol;orm单表操作

    Django框架05 /orm单表操作 目录 Django框架05 /orm单表操作 1. orm使用流程 2. orm字段 3. orm参数 4. orm单表简单增/删/改 5. orm单表查询 5 ...

  5. day53&colon;django&colon;URL别名&sol;反向解析&amp&semi;URL分发&amp&semi;命名空间&amp&semi;ORM多表操作修改&sol;查询

    目录 1.URL别名&反向解析 2.URL分发&命名空间 3.ORM多表操作-修改 4.ORM多表操作-查询 4.1 基于对象的跨表查询 4.2 基于双下划线的跨表查询 4.3 聚合查 ...

  6. Django ORM那些相关操作zi

    Django ORM那些相关操作   一般操作 看专业的官网文档,做专业的程序员! 必知必会13条 <1> all(): 查询所有结果 <2> filter(**kwargs) ...

  7. Django ORM 那些相关操作

    Django ORM 那些相关操作 一般操作 必知必会13条 <> all(): #查询所有的结果 <> filter(**kwargs) # 它包含了与所给筛选条件相匹配的对 ...

  8. day59——orm单表操作

    day59 orm单表操作 对象关系映射(object relational mapping) orm语句 -- sql -- 调用pymysql客户端发送sql -- mysql服务端接收到指令并执 ...

  9. 17-2 orm单表操作和多表操作

    参考:https://www.cnblogs.com/liwenzhou/p/8660826.html 一  ORM单表操作 1 增删改查 1. 查询 1. 查所有 models.Publisher. ...

随机推荐

  1. caffe初试(一)happynear的caffe-windows版本的配置及遇到的问题

    之前已经配置过一次caffe环境了: Caffe初试(一)win7_64bit+VS2013+Opencv2.4.10+CUDA6.5配置Caffe环境 但其中也提到,编译时,用到了cuda6.5,但 ...

  2. Web Service数据源

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  3. Python之if语句

    计算机之所以能做很多自动化的任务,因为它可以自己做条件判断. 比如,输入用户年龄,根据年龄打印不同的内容,在Python程序中,可以用if语句实现: age = 20 if age >= 18: ...

  4. xenserver

    Citrix XenServer is the complete server virtualization platform from Citrix. citrix xenserver是来自citr ...

  5. C单链表实现

    /* * LinkNode.c * * Created on: Jan 14, 2014 * Author: root */ #include <stdlib.h> #include &l ...

  6. Xah Lee Web 李杀网

    Xah Lee Web 李杀网 ∑ Xah Lee Web 李杀网

  7. 使用git克隆指定分支的代码

    今天想学习一下开源中国Android客户端的app源码,源码的Git地址:http://git.oschina.net/oschina/android-app,如下图所示: 由于Master主分支上没 ...

  8. Java NIO 之 Buffer

    Java NIO 之 Buffer Java NIO (Non Blocking IO 或者 New IO)是一种非阻塞IO的实现.NIO通过Channel.Buffer.Selector几个组件的协 ...

  9. 从ranknet到lamdarank,再到lamdamart

    learn2rank目前基本两个分支,1是神经网络学派ranknet,lamdarank,另一个是决策树学派如gbrank,lamdamart 05年提出ranknet,算分模块是简单的全连接网络,l ...

  10. Python2 处理 Unicode 字符串的规则

    在 Python2 中处理 Unicode 字符串,需遵循如下规则: 1. 程序中的字符串要加前缀 u 2. 不要用 str(),而应该用 unicode() 作为字符串转换函数.不要使用 chr() ...