ORM单表操作
单表操作演示表
class Book(models.Model): name = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_place=2) publish = models.CharField(max_length=32) author = models.CharField(max_length=32) create_time = models.DateField(null=True) # 配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。 # 配置上auto_now=True,每次更新数据记录的时候会更新该字段。
新增数据
# 第一种:有返回值,并且就是当前被创建的数据对象 modles.Book.objects.create(name='',price='',publish='',author='',create_time='2019-5-1') # 第二种:先实例化产生对象,然后调用save方法保存 book_obj = models.Book(name='',price='',publish='',author='',create_time='2019-5-1') book_obj.save() # 2.验证时间格式字段即可以传字符串也可以传时间对象 import datetime ctime = datetime.datetime.now() book = models.Book.objects.create(name='',price='',author='',create_time=ctime)
删除数据
"""删除数据""" # 1.删除书名为xxx的这本书 queryset方法 res = models.Book.objects.filter(name='').delete() print(res) # 2.删除书名为xxx的这本书 queryset方法 res = models.Book.objects.filter(name='').first() res.delete()
修改数据
# 1.queryset修改 models.Book.objects.filter(name='').update(price='') # 2.对象修改 book = models.Book.objects.filter(name='').first() book.price = 66.66 book.save() # 对象只有保存方法 这样也能实现修改需求
查询数据的13个方法
返回QuerySet对象的方法有:
all() 查询所有结果
filter() 它包含了与所给筛选条件相匹配的对象
exclude() 它包含了与所给筛选条件不匹配的对象
order_by() 对查询结果排序
reverse() 对查询结果反向排序>>>前提是要先有排序才能反向
distinct() 从返回结果中剔除重复记录(必须是完全相同的两条记录)
特殊的QuerySet:
values() 返回一个可迭代的字典序列
values_list() 返回一个可迭代的元组序列
返回具体对象的:
get() 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
first() 返回第一条记录
last() 返回最后一条记录
返回布尔值的方法有:
exists() 如果QuerySet包含数据,就返回True,否则返回False
返回数字的方法有:
count() 返回数据库中匹配查询
查看orm内部sql语句的方法有哪些
1.如果是queryset对象,那么可以点query直接查看该queryset的内部sql语句
2.在Django项目的配置文件中,配置以下参数即可实现所有的orm在查询的时候自动打印对应的sql语句
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}神奇的双下划线查询
# 价格 大于 小于 大于等于 小于等于 filter(price__gt='90') filter(price__lt='90') filter(price_gte='90') filter(price_lte='90') # 存在与某几个条件中 filter(price__in=['11','22','33']) # 在某个范围内 filter(price__range=[50,90]) # 模糊查询 filter(title__contains='西') filter(title__icontains='P') # 以什么开头 以什么结尾 filter(title__startswith='三') filter(title__endswith='p') # 按年查询 filter(create_time__year='2017')
多表操作
一对一查询,一对一关联其实就是外健关联再加一个唯一性约束
ForeignKey(unique=Ture) >>> OneToOneField() # 即一对一可以用ForeignKey来做,但是需要设唯一性约束并且会报警告信息,不建议使用,建议用OneToOneField # 用了OneToOneField和用ForeignKey会自动在字段后面加_id # 用了ManyToMany会自动创建第三张表
一对多增删改查
# 增:针对外键关联的字段 两种添加方式 # 第一种通过publish_id models.Book.objects.create(publish_id=1,) # 第二种通过publish传出版社对象 publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.create(publish=publish_obj,) # 删:删除书籍直接查询删除即可,删除出版社会级联删除 models.Publish.objects.filter(pk=2).delete() # 默认都是级联更新 级联删除 # 改:编辑数据也是两种对应的方式(对象点的方式(这里能点publish和publish_id)最后点save(),queryset方式update()) # 传数字的 models.Book.objects.filter(pk=1).update(publish_id=3) # 传对象的 publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.filter(pk=1).update(publish=publish_obj)
多对多增删改查
"""前提:先获取书籍对象,再通过书籍对象点authors来进行书籍作者的增删改查""" # 增:给书籍新增作者add # add可以传作者id,也可以直接传作者对象,并且支持传多个位置参数(不要混着用) # 删:给书籍删除作者remove # remove同样可以传id,对象,并且支持传多个位置参数(不要混着用) # 清空:直接清空书籍对象所有的作者数据 # clear()不用传任何参数 # 改修改书籍对象所关联的作者信息set,注意点set括号内必须传可迭代对象,里面可以传id,对象 """总结:一对多增删改,多对多add,remove,clear,set""" create() 创建一个关联对象,并自动写入数据库,且在第三张双方的关联表中自动新建上双方对应关系。 add() 把指定的model对象添加到第三张关联表中。 set() 更新某个对象在第三张表中的关联对象。不同于上面的add是添加,set相当于重置 remove() 从关联对象集中移除执行的model对象(移除对象在第三张表中与某个关联对象的关系) clear() 从关联对象集中移除一切对象。(移除所有与对象相关的关系信息) """ 注意:1.对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。 2.对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。 """
正向反向查找
# 正向与方向的概念解释 # 一对一 # 正向:author---关联字段在author表里--->authordetail 按字段 # 反向:authordetail---关联字段在author表里--->author 按表名小写 # 查询jason作者的手机号 正向查询 # 查询地址是 :山东 的作者名字 反向查询 # 一对多 # 正向:book---关联字段在book表里--->publish 按字段 # 反向:publish---关联字段在book表里--->book 按表名小写_set.all() 因为一个出版社对应着多个图书 # 多对多 # 正向:book---关联字段在book表里--->author 按字段 # 反向:author---关联字段在book表里--->book 按表名小写_set.all() 因为一个作者对应着多个图书 # 连续跨表 # 查询图书是三国演义的作者的手机号,先查书,再正向查到作者,在正向查手机号 """基于对象的跨表查询(子查询:将一张表的查询结果当做另外一个查询语句的条件)"""
多表查询
# 1.查询书籍id是1 的出版社名称 book_obj = models.Book.objects.filter(pk=1).first() print(book_obj.publish.name) 2.查询书籍id是2 的作者姓名 book_obj = models.Book.objects.filter(pk=2).first() # print(book_obj.authors) # app01.Author.None print(book_obj.authors.all()) res = book_obj.authors.all() for r in res: print(r.name) # 3.查询作者是jason的家庭住址 author_obj = models.Author.objects.filter(name='jason').first() print(author_obj.author_detail.addr) # 4.查询出版社是东方出版社出版的书籍 publish_obj = models.Publish.objects.filter(name='东方出版社').first() print(publish_obj.book_set.all()) # 5.查询作者是jason的写过的所有的书籍 author_obj = models.Author.objects.filter(name='jason').first() print(author_obj.book_set.all()) # 6.查询电话号码是130的作者姓名 author_detail_obj = models.AuthorDetail.objects.filter(phone=130).first() print(author_detail_obj.author.name) """ 当你反向查询的结果是多个的时候 就需要加_set 否则直接表明小写即可 """ # 7.查询书籍id为1 的作者的电话号码 book_obj = models.Book.objects.filter(pk=1).first() author_list = book_obj.authors.all() for author_obj in author_list: print(author_obj.author_detail.phone)
基于双下划线的跨表查询
"""基于双下划线的跨表查询(连表操作)
-连表查询
-一对一双下划线查询
-正向:按字段,跨表可以在filter,也可以在values中
-反向:按表名小写,跨表可以在filter,也可以在values中
"""
# 查询jason作者的手机号 正向查询 跨表的话,按字段
# ret=Author.objects.filter(name='jason').values('authordetail__phone')
# 以authordetail作为基表 反向查询,按表名小写 跨表的话,用表名小写
# ret=AuthorDetail.objects.filter(author__name='jason').values('phone')
# 查询jason这个作者的性别和手机号
# 正向
# ret=Author.objects.filter(name='jason').values('sex','authordetail__phone')
# 查询手机号是13888888的作者性别
# ret=Author.objects.filter(authordetail__phone='13888888').values('sex')
# ret=AuthorDetail.objects.filter(phone='13888888').values('author__sex')
"""
总结 其实你在查询的时候先把orm查询语句写出来,再看用到的条件是否在当前表内,在就直接获取,不在就按照正向按字段反向按表名来查即可
比如:
1.查询出版社为北方出版社的所有图书的名字和价格
res1 = Publish.objects.filter(name='').values('book__name','book__price')
res2 = Book.objects.filter(publish__name='').values('name','price')
2.查询北方出版社出版的价格大于19的书
res1 = Publish.objects.filter(name='',book__price__gt=19).values('book__name','book__price)
"""聚合查询(aggregate)
# 1.统计所有书的总价格
from django.db.models import Max,Min,Count,Avg,Sum
res = models.Book.objects.aggregate(Sum('price'))
res1 = models.Book.objects.aggregate(Avg('price'))
res2 = models.Book.objects.aggregate(Count('price'))
res3 = models.Book.objects.aggregate(Max('price'))
res4 = models.Book.objects.aggregate(Min('price'))
res5 = models.Book.objects.aggregate(Max('price'),Min('price'),Count('pk'),Avg('price'),Sum('price'))
print(res,res1,res2,res3,res4,res5)分组查询
# 统计每一本书的作者个数
from django.db.models import Max, Min, Count, Avg, Sum
res = models.Book.objects.annotate(author_num = Count('authors')).values('author_num','title')
print(res)
# 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(mmp = Min('book__price')).values('name','mmp')
print(res)
# 统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1)
print(res)
"""
只要是queryset对象 就可以无限制的调用queryset对象的方法!!!
最最常用的就是对一个已经filter过滤完的数据 再进行更细化的筛选
"""
# 查询各个作者出的书的总价格
res = models.Author.objects.annotate(sp=Sum('book__price')).values('name','sp')
print(res)F查询
#F查询的本质就是从数据库中获取某个字段的值
# 查询库存数大于卖出数的书籍
"""之前查询等号后面的条件都是我们认为输入的
现在变成了需要从数据库中获取数据放在等号后面
"""
from django.db.models import F
res = models.Book.objects.filter(kucun__gt=F('maichu'))
print(res)
# 将书籍库存数全部增加1000
models.Book.objects.update(kucun=F('kucun')+1000)
# 把所有书名后面加上'新款'
from django.db.models.functions import Concat
from django.db.models import Value
res = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
# models.Book.objects.update(title = F('title')+'新款') # 不能这么写Q查询
from django.db.models import Q
# 查询书籍名称是三国演义或者价格是444.44
res = models.Book.objects.filter(title='三国演义',price=444.44) # filter只支持and关系
res1 = models.Book.objects.filter(Q(title='三国演义'),Q(price=444)) # 如果用逗号 那么还是and关系
res2 = models.Book.objects.filter(Q(title='三国演义')|Q(price=444))
res3 = models.Book.objects.filter(~Q(title='三国演义')|Q(price=444))
print(res)
# Q高级用法
q = Q()
q.connector = 'or' # 修改查询条件的关系 默认是and
q.children.append(('title__contains','三国演义')) # 往列表中添加筛选条件
q.children.append(('price__gt',444)) # 往列表中添加筛选条件
res = models.Book.objects.filter(q) # filter支持你直接传q对象 但是默认还是and关系
print(res)