Django之ORM相关操作

Django之ORM相关操作

ORM执行SQL语句

有时因为ORM的操作效率偏低,可以自己编写SQL提升效率。
在Django中使用原生Sql主要有以下几种方式:
1.extra:结果集修改器,一种提供额外查询参数的机制
2.raw:执行原始sql并返回模型实例
3.直接执行自定义Sql
 # 这种方式完全不依赖model,前两种还是要依赖于model

代码示例:
# extra:
1:Book.objects.filter(publisher__name='北方出版社').extra(where=['price>50'])
Book.objects.filter(publisher__name='北方出版社',price__gt=50)
 
2:Book.objects.extra(select={'count':'select count(*) from hello_Book'})
 
# raw:
Book.objects.raw('select * from hello_Book')
 
自定义sql:
Book.objects.raw("insert into hello_author(name) values('测试')")
rawQuerySet为惰性查询,只有在使用时生会真正执行
 
# 执行自定义sql:
from django.db import connection
cursor=connection.cursor()
#插入操作
cursor.execute("insert into hello_author(name) values('郭敬明')")
#更新操作
cursor.execute('update hello_author set name='abc' where name='bcd'')
#删除操作
cursor.execute('delete from hello_author where name='abc'')
#查询操作
cursor.execute('select * from hello_author')
raw=cursor.fetchone() #返回结果行游标直读向前,读取一条
cursor.fetchall() #读取所有

神奇的双下划线查询

# 查询价格大于200的书籍
res = models.Book.objects.filter(price__gt=200)
print(res)

# 查询价格小于200的书籍
res = models.Book.objects.filter(price__lt=200)
print(res)

# 查询价格大于等于200.22的书籍
res = models.Book.objects.filter(price__gte=200.22)
print(res)

# 查询价格小于等于200.22的书籍
res = models.Book.objects.filter(price__lte=200.22)
print(res)

# 查询价格要么是200,要么是300,要么是666.66
res = models.Book.objects.filter(price__in=[200,300,666.66]) 
# 都包含
print(res)

# 查询价格在200到800之间的
res = models.Book.objects.filter(price__range=(200,800))  
# 顾头不顾尾
print(res)

# 查询书籍名字中包含p的
res = models.Book.objects.filter(title__contains='p')  
# 区分大小写,仅仅只能拿小写p
res1 = models.Book.objects.filter(title__icontains='p')  
# 忽略大小写
print(res)
print(res1)
	
# 查询书籍是以三开头的
res = models.Book.objects.filter(title__startswith='三') 
# 查询以三开头的
res1 = models.Book.objects.filter(title__endswith='P')  
# 查询以P结尾的,区分大小写
print(res)
print(res1)

# 查询出版日期是2019年的书籍(******)
res = models.Book.objects.filter(publish_date__year='2019')
print(res)
# 查询出版日期是10月的书籍
res = models.Book.objects.filter(publish_date__month='10')
print(res)

ORM外键字段的创建

外键名 = models.ForeignKey("类名",to_field="关联字段",default=默认值,on_delete=models.CASCADE,)  
#关联字段必须是唯一的,这个to_field不加也可以,默认用的就是主键


1.django orm创建表关系
图书表
出版社表
作者表
作者详情表
2.关系判断
	书与出版社
  	一本书不能对应多个出版社
    一个出版社可以对应多本书
    # 一对多关系.书是多,出版社是一.		
    ForeignKey
'''django orm外键字段针对一对多关系也是建在多的一方 '''
    
	书与作者
  	一本书可以对应多个作者
    一个作者可以对应多本书
    # 多对多关系
    ManyToManyField
'''django orm外键字段针对多对多关系 可以不用自己创建第三张表'''
  
    作者与作者详情
  	一个作者不能对应多个作者详情
    一个作者详情不能对个多个作者
    # 一对一关系
    OneToOneField
'''django orm外键字段针对一对一关系 建在查询频率较高的表中'''
 
"""	
	ManyToManyField不会在表中创建实际的字段,而是告诉django orm自动创建第三张关系表
	ForeignKey、OneToOneField会在字段的后面自动添加_id后缀,如果你在定义模型类的时候自己添加了该后缀,那么迁移的时候还会再次添加_id后缀。所以不要自己加_id后缀。
"""

外键字段相关操作

# 一对多,插入数据可以直接填写表中的实际字段
	models.Book.objects.create(title='三国演义', price=888.88, publish_id=1)
	models.Book.objects.create(title='人性的弱点', price=777.55, publish_id=1)
# 一对多 插入数据也可以填写表中的类中字段名
	publish_obj = models.Publish.objects.filter(pk=1).first()
	models.Book.objects.create(title='水浒传', price=555.66, publish=publish_obj)

    '''一对一与一对多一致,既可以传数字也可以传对象。'''

# 针对多对多关系绑定
增加字段关系add()
book_obj = models.Book.objects.filter(pk=1).first()
bool_obj.authors.add(1)# 在第三张关系表中给当前书籍绑定作者
bool_obj.authors.add(2, 3) # 给主键为3的书籍添加主键为2和3的作者

author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj)  # 可以直接添加作者对象
book_obj.authors.add(author_obj,author_obj1)
"add()括号内既可以直接传数字也可以传数据对象,并且支持传多个"

# 修改关系set()
book_obj.author.set([2, ])
book_obj.author.set([2, 3])
book_obj.author.set([author_obj1, ])
book_obj.author.set([author_obj1, author_obj2])
"set()括号内必须是可迭代对象"

# 删除对象remove()
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.remove(2)
book_obj.authors.remove(1,2)

author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.remove(author_obj)  # 可以直接传作者对象
book_obj.authors.remove(author_obj,author_obj1)
"remove()括号内既可以直接传数字也可以传数据对象,并且支持传多个"

# 清空关系clear()
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.clear()
"clear()括号内不需要传任何参数,直接清空当前主键为3的书籍对象的所有记录"

ORM跨表查询

"""
复习MySQL跨表查询的思路
	子查询:
		分步操作:将一条SQL语句用括号括起来,当作另外一条SQL的条件
	连表操作:
		先整合多张表之后,基于单表查询
			inner join 内连接
			left join  左连接
			right join  右连接
"""

# 正反向的概念
正向查询(有外键字段的来查就是正向)
	eg:
        书籍对象查出版社,外键字段在书籍

反向查询(有外键字段的被查就是反向)
	eg:
        出版社查书籍,外键字段在书籍
ps:正反向的核心就看外键字段在不在当前数据所在的表中

# ORM跨表查询口诀:
    正向查询按外键字段 反向查询按表名小写

基于对象的跨表查询

	"正向查询按字段,当该字段所对应的数据有多个的时候,需要加.all(),否则点外键字段直接就能够拿到数据对象。"
# 1、查询书籍是python入门的出版社名称
book_obj = models.Book.objects.filter(title='python入门').first()
# 正向查询按字段
print(book_obj.publish.name)
print(book_obj.publish.addr)

# 2、查询主键是6的书籍的作者姓名
book_obj = models.Book.objects.filter(pk=6).first()
print(book_obj.authors)  # 结果是app01.Author.None
print(book_obj.authors.all())  # 结果是这本书的所有作者的Queryset对象

# 3、查询作者是jason的手机号
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail.phone) # 正向查询按字段
print(author_obj.author_detail.addr)

	"反向查询按表名小写,当查询的结果可以是多个的情况下需要在表名小写后面加_set.all();当查询的结果有且只有一个的情况下,不需要加任何东西,直接表名小写即可。"
# 1、查询出版社是北方出版社出版过的书籍
publish_obj = models.Publish.objects.filter(name='北方出版社').first()
print(publish_obj.book_set)  # 结果是app01.Book.None
print(publish_obj.book_set.all())  # 加.all()就能拿到该出版社出版的所有书

# 2、查询作者是jason写过的所有书
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.book_set.all())

# 3、查询手机号是110的作者
author_detail_obj =  models.AuthorDetail.objects.filter(phone=110).first()
print(author_detail_obj.author)  # 这个拿到作者对象
print(author_detail_obj.author.name) 
print(author_detail_obj.author.age) 


基于上下划线的跨表查询

# 1、查询书籍是python入门的出版社名称
res = models.Book.objects.filter(title='python入门').values('publish__name')
print(res)  # 正向查询按字段publish查

#2、查询作者是jason的手机号码
# 正向
res1 = models.Author.objects.filter(name='jason').values('author_detail__phone')
print(res1)  # 正向查询按字段查
# 反向
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')

# 3、查询手机号是120的作者姓名
# 正向
res2 = models.AuthorDetail.objects.filter(phone=120).values('author__name')  # 反向查询按表名小写查
print(res2)
# 反向
res3 =models.Author.objects.filter(author_detail__phone=120).values('name')

# 4、查询出版社是东方出版社出版的书籍名称和出版社地址
res = models.Publish.objects.filter(name='东方出版社').values('book__title','addr')  # 也是反向查询按表名小写


# 5、查询书籍是python入门的作者的手机号(连续跨表查询)
res = models.Book.objects.filter(title='python入门').values('authors__author_detail__phone')
print(res)

进阶操作

# 1.查询主键为1的书籍对应的出版社名称
res = models.Publish.objects.filter(book__pk=1).values('name')
print(res)
# 2.查询主键为4的书籍对应的作者姓名
res=models.Author.objects.filter(book__pk=4).values('name','book__title')
print(res)
# 3.查询jason的电话号码
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
print(res)
# 4.查询北方出版社出版过的书籍名称和价格
res = models.Book.objects.filter(publish__name='北方出版社').values('title','price')
print(res)
# 5.查询jason写过的书籍名称
res = models.Book.objects.filter(authors__name='jason').values('title')
print(res)
# 6.查询电话号码是110的作者姓名
res = models.Author.objects.filter(author_detail__phone=110).values('name')
print(res)
    

# 补充
1.查询主键为4的书籍对应的作者的电话号码
res = models.Book.objects.filter(pk=4).values('authors__author_detail__phone')
print(res)
res = models.AuthorDetail.objects.filter(author__book__pk=4).values('phone')
print(res)
res = models.Author.objects.filter(book__pk=4).values('author_detail__phone')
print(res)
posted @ 2022-12-15 22:29  知了了了了  阅读(27)  评论(0编辑  收藏  举报