############################################## 单表操作 ############################################## 简单查: models.User.objects.filter(id=3) # queryset对象,相当于一个列表,放了一个或多个User对象 models.User.objects.filter(id=3).first() # User对象,相当于只去了queryset对象中的第一个 增: 第一种:# 先创建数据,再保存 user = models.User(username='alex',password='a654321') user.save() 第二种:# 直接保存或先创建再保存 1.方式一: models.User.objects.create(username='alex',password='a654321') 2.方式二: dic={"username":"alex","password":'a654321'} models.Book.object.create(**dic) 删: 方式一:# 删除所查出queryset对象中所有对象 models.User.objects.filter(id=3).delete() 方式二:# 删除所查出的user对象 user = models.User.objects.filter(id=3).first() user.delete() 改: 方式一:# 将修改所查到queryset对象中所有的对象 models.User.objects.filter(id=3).update(username='egon',password='aa123') 方式二:# 只修改所查到的user对象,一般在收集日志的时候用此方法,因为有save()动作 user = models.User.objects.filter(id=3).first() user.username='egon' user.password='aa123' user.save() 查: 查询相关API: <1>filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <2>all(): 查询所有结果 <3>get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 #---------下面的方法都是对查询的结果再进行处理:比如 objects.filter().values()-------- ''' **kwargs:代表以键值(字段=值)的方法传参 *field:代表只传键(字段),不传值 ''' <4>values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列 <5>exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 # 可直接用,也可用在filter之后 <6>order_by(*field): 对查询结果排序 # 只能用在queryset之后 <7>reverse(): 对查询结果反向排序 # 必须用在order_by之后 <8>distinct(): 从返回结果中剔除重复纪录 # 一般用在values之后,对某一字段进行去重 <9>values_list(*field): 它与values()非常相似,它返回的是一个元组序列 # 将values()字典中的值拿了出来,组成元组 <10>count(): 返回数据库中匹配查询(QuerySet)的对象数量。 # 只能用在queryset对象之后 <11>first(): 返回第一条记录 <12>last(): 返回最后一条记录 <13>exists(): 如果QuerySet包含数据,就返回True,否则返回False。 # 只能用在queryset之后 基于双下划线__的模糊查询: models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and models.Tb1.objects.filter(name__contains="ven") # name中包含ven的,对大小写敏感 models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 ....startswith(以什么开头) ....istartswith(返回Bool值) ....endswith(以什么结尾) ....iendswith(返回Bool值) # ****************小Tip*************** 1.user = models.User.objects.filter(id=3) print(user.query) # 打印其原生SQL 2.pk即id,pk指主键,一般id也作为主键 3.models中,在创建一对一和一对多关系时,需要添加约束:"on_delete=models.CASCADE",意为在删除被关联字段时,必须删除其关联的所有字段,称为“级联删除” 4.正向查询:关联字段在当前表中,从当前表向外查 反向查询:关联字段不在当前表中,从当前表向外查 # ************************************ ############################################## 多表操作 ############################################## 多表操作相对于单表来说只是多了约束条件,只要在操作时考虑到相关联的表就行了 例:''' author表:name detail表:age,sex,addr book表:name,pub_date publisher表:name,addr author和detail之间存在一对一关系,其关联字段'det_auth'写在detail中 book和publisher之间存在一对多关系,其关联字段'book_pub'写在book中 book和author之间存在多对多关系,其关联字段'book_auth'写在book中 ''' 增: # ********顺序为先创建被关联方,再创建关联方******** 一对一(OneToOne): models.Author.objects.create(name='alex') models.Detail.objects.create(age=38,sex='male',det_auth_id=1) # 其中det_auth_id为关联字段,必须得写,_id是django自己加上去的(也可换成pk) 或 author = models.Author.objects.create(name='alex') models.Detail.objects.create(age=38,sex='male',det_auth=author) # 传对象方式 一对多(ForeignKey):#与一对一相似 多对多(ManyToMany): book = models.Book.objects.filter(id=3).first() book.book_auth.add(1,2) # 在给id为3的书添加了id为1和2的两个作者 或 book = models.Book.objects.filter(id=3).first() author1 = models.Author.objects.get(id=1) author2 = models.Author.objects.get(id=2) book.book_auth.add(author1,author2) # 传对象方式 删: 一对一and一对多: # ********删除被关联方字段,其所有的关联方字段都会被删除******** models.Author.objests.filter(id=3).delete() models.Publisher.objests.filter(id=3).delete() 多对多: book = models.Book.objects.filter(id=3) 方式一: book.book_auth.clear() # 将book下关联的所有都删掉 方式二: book.book_auth.remove(1,2) # 传id方式 或 author1 = models.Author.objects.get(id=1) author2 = models.Author.objects.get(id=2) book.book_auth.remove(author1,author2) # 传对象方式 改: 一对一and一对多: models.Detail.objects.update(det_auth_id=3) 或 author = models.Author.objects.get(id=3) models.Detail.objects.update(det_auth=author) # 传对象方式 多对多: book = models.Book.objects.filter(id=3) 方式一: 全部clear,再add 方式二: book.book_auth.set([3,]) # 传id方式 或 author1 = models.Author.objects.get(id=1) author2 = models.Author.objects.get(id=2) book.book_auth.set(author1,author2) # 传对象方式 查: # ******************基于对象的跨表查询(子查询)********************* ''' 总结: 已知谁以谁为基表进行查询 一对一:正向查询按关联字段,反向查询按表名小写 一对多:正向查询按关联字段,反向查询按表名小写_set.all()(因为可能查到多条数据) 多对多:正向查询按关联字段.all(),反向查询按表名小写_set.all()(因为可能查到多条数据) ''' 一对一: 例1:查询地址为北京的人的名字 detial = models.Detail.objects.filter(addr='北京').first() print(detail.det_auth.name) # 正向查 例2:查询alex这个人的地址 author = models.Author.objects.filter(name='alex').first() print(author.detail.addr) # 反向查 一对多: 例1:查询红楼梦这本书的出版社地址 book = models.Book.objects.filter(name='红楼梦').first() print(book.book_pub.addr) # 正向查 例2:查询南京出版社出版的所有书的名字 publisher = models.Publisher.objects.filter(name='南京出版社').first() books = publisher.book_set.all() # 反向查,查到的是个queryset对象(可迭代) for book in books: print(book.name) 多对多: 例1:查询红楼梦这本书的所有作者 book = models.Book.objects.filter(name='红楼梦').first() authors = book.book_auth.all() # 正向查,查到的是个queryset对象(可迭代) for author in authors: print(author.name) 例2:查询作者为alex写的所有书 author = models.Author.objects.filter(name='alex').first() books = author.book_set.all() # 反向查,查到的是个queryset对象(可迭代) for book in books: print(book.name) # ******************基于双下划线__的跨表查询(子查询)********************* ''' 总结: 1.基表可以是已知方,也可以是未知方,但必须相关 2.基本上已经不区分一对一、一对多、多对多 3.本质就是用了sql中的join连表查 3.相比于基于对象查询:没有_set.all(),也不用关联字段.all() 优势:1.写起来比较方便,需要记得东西少 2.跨多表查询起来很方便 劣势:查询速度较慢,查询出来的是值,而不是对象,所以不能用.的方式进行连表查 ''' 一对一: 例1:查询alex这个人的地址 -以Author表作为基表: ret = models.Author.objects.filter(name='alex').values('name','detail__addr') # 反向查 print(ret) -以Detail表作为基表: ret = models.Detail.objects.filter(det_auth__name='alex').values('det_auth__name','addr') # 正向查 print(ret) 例2:查询地址为武汉的人的名字 -以Author表作为基表: ret = models.Author.objects.filter(detail__addr='武汉').values('name','detail__addr') # 反向查 print(ret) -以Detail表作为基表: ret = models.Detail.objects.filter(addr='武汉').values('det_auth__name','addr') # 正向查 print(ret) 一对多: 例1:查红楼梦这本书的出版社地址 -以Book作为基表: ret = models.Book.objects.filter(name='红楼梦').values('name','book_pub__addr') # 正向查 print(ret) -以Publisher作为基表: rets = models.Publisher.objects.filter(book__name='红楼梦').values('book__name','addr') # 反向查 print(ret) 例2:查询南京出版社出版的所有书的名字 -以Book作为基表: rets = models.Book.objects.filter(book_pub__name='南京出版社').values('name') # 正向查 for ret in rets: print(ret) -以Publisher作为基表: rets = models.Publisher.objects.filter(name='南京出版社').values('book__name') # 反向查 for ret in rets: print(ret) 多对多: 例1:查询红楼梦这本书的所有作者 -以Book作为基表: rets = models.Book.objects.filter(name='红楼梦').values('name','book_auth__name') # 正向查 for ret in rets: print(ret) -以Author作为基表: rets = models.Author.objects.filter(book__name='红楼梦').values('book__name','name') # 反向查 for ret in rets: print(ret) 例2:查询作者为alex写的所有书 -以Book作为基表: rets = models.Book.objects.filter(book_auth__name='alex').values('name') # 正向查 for ret in rets: print(ret) -以Author作为基表: rets = models.Author.objects.filter(name='alex').values('book__name') # 反向查 for ret in rets: print(ret) 终极练习(连跨多表查询): 例:查询人民出版社出版过的所有书籍的名字及作者的姓名 -以出版社作为基表 rets = models.Publisher.objects.filter(name='人民出版社').values('book__name','book__book_auth__name') -以书作为基表 rets = models.Book.objects.filter(book_pub='人民出版社').values('name','book_auth__name') print(rets) # 打印出来是一个queryset对象中包含多个字典 ################################## 聚合查询 ####################################### aggregate() # 返回结果是一个字典,键为django自动生成"字段名_函数名",值为所查询并计算的结果 from django.db.models import Count,Avg,Max,Min,Sum ret = models.Book.objects.aggregate(Avg('price')) ret = models.Book.objects.aggregate(Max('price')) ret = models.Book.objects.aggregate(Min('price'),Count('price'),Sum('price')) print(ret) >>:{'price__min':'25.5','price__count':'35.8','price__sum':'40.3'} ################################## 分组查询 ####################################### annotate() # 返回的值是queryset对象,在annotate中算出的结果可赋给一个新值,可以作为后续查询的条件,也可作为结果 ''' values在前,表示group by,在后,表示取值 filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤) ''' from django.db.models import Count,Avg,Max,Min,Sum 例1:统计每一本书的作者个数 book_list = models.Book.objects.all().annotate(author_num=Count(authors)).value('name','author_num') print(book_list) 例2:统计每一个出版社的最便宜的书 publishList=Publish.objects.annotate(MinPrice=Min("book__price")) for publish_obj in publishList: print(publish_obj.name,publish_obj.MinPrice) 例3:统计不止一个作者的图书:(作者数量大于1) ret=models.Book.objects.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num') 例4:根据一本图书作者数量的多少对查询集 QuerySet进行排序 ret = Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors') 例5:查询各个作者出的书的总价格 ret = models.Author.objects.annotate(sum_price=Sum("book__price")).values("name", "sum_price") 例6:查询每个出版社的名称和书籍个数 ret = models.Publish.objects.all().annotate(c=Count('book__name')).values('name','c') #################################F 查询和Q查询 ##################################### from django.db.models import F,Q F:取出表中字段对应的值 例1:查询评论数大于阅读数的书 ret = models.Book.objects.filter(commit_num__gt=F('read_num')) 例2:把所有书的评论数+1 ret = models.Book.objects.all().update(commit_num=F('commit_num')+1) Q:查询,构造出与"&"、或"|"、非"~"的关系 与: 例:查询出书名为红楼梦并且价格为20的书 ret = models.Book.objects.all().filter(Q(name='红楼梦')&Q(price=20)) 或: 例:查询出书名为红楼梦或价格为20的书 ret = models.Book.objects.all().filter(Q(name='红楼梦')|Q(price=20)) 非: 例:查询出书名为不为红楼梦的书 ret = models.Book.objects.all().filter(~Q(name='红楼梦'))