一 创建表模型
假设:
作者模型:一个作者有姓名和年龄。
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)
出版商模型:出版商有名称,所在城市以及email。
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to- many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
from django.db import models # Create your models here. class Publish(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) addr = models.CharField(max_length=32) email = models.EmailField() class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) sex = models.IntegerField() authordetail = models.OneToOneField(to='AuthorDetail', to_field='id') class AuthorDetail(models.Model): id = models.AutoField(primary_key=True) phone = models.CharField(max_length=32) addr = models.CharField(max_length=64) class Book(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish = models.ForeignKey(to=Publish, to_field='id') authors = models.ManyToManyField(to=Author) def __str__(self): return self.name
二 增删改查
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day77.settings") import django django.setup() from app01.models import * # 一对多新增数据 # 添加一本北京出版社出版的书 # 第一种方式 # ret=Book.objects.create(name='红楼梦',price=34.5,publish_id=1) # print(ret.name)
# 第二种方式,存对象publish=出版社的对象,存到数据库,是一个id # publish=Publish.objects.get(id=1) # pk是主键,通过主键查找 # publish=Publish.objects.get(pk=1) # publish = Publish.objects.filter(pk=2).first() # ret = Book.objects.create(name='西游记', price=34.5, publish=publish) # print(ret.name)
# 一对多修改数据 # book=Book.objects.get(pk=1) # # book.publish=出版社对象 # book.publish_id=2 # book.save()
# 方式二 # book=Book.objects.filter(pk=1).update(publish=出版社对象) # book=Book.objects.filter(pk=1).update(publish_id=1)
# 多对多新增 # 为红楼梦这本书新增一个叫lqz,egon的作者 # lqz=Author.objects.filter(name='lqz').first() # egon=Author.objects.filter(name='egon').first() # book=Book.objects.filter(name='红楼梦').first() # # add 添加多个对象 # book.authors.add(lqz,egon) # add添加作者id # book.authors.add(1,2)
#删除 remove,可以传对象,可以传id,可以传多个,不要混着用 # book.authors.remove(lqz) # book.authors.remove(2) # book.authors.remove(1,2)
# clear清空所有 # book.authors.clear() # set,先清空,在新增,要传一个列表,列表内可以是, id,也可以是对象 # book.authors.set([lqz,]) # ********这样不行,因为它打散了传过去了,相当于book.authors.set(lqz) # book.authors.set(*[lqz,])
三 基于对象的跨表查询
''' 一对一 正向 author---关联字段在author--->authordetail ------> 按字段 反向 authordetail------关联字段在author--->author -----> 按表名小写 ''' # 查询lqz作者的手机号 正向查询 # author=Author.objects.filter(name='lqz').first() # # author.authordetail 就是作者详情的对象 # authordetail=author.authordetail # print(authordetail.phone) # 查询地址是 :山东 的作者名字 反向查询 # authordetail=AuthorDetail.objects.filter(addr='山东').first() # # authordetail.author 这是作者对象 # author=authordetail.author # print(author.name) #一对多 ''' 一对多 正向 book---关联字段在book--->publish ------> 按字段 反向 publish------关联字段在book--->book -----> 按表名小写_set.all() ''' # 正向 查询红楼梦这本书的出版社邮箱 # book=Book.objects.filter(name='红楼梦').first() # # book.publish 就是出版社对象 # pulish=book.publish # print(pulish.email) # 反向 查询地址是北京 的出版社出版的图书 # publish=Publish.objects.filter(addr='北京').first() # # publish.book_set.all() 拿出所有的图书 # books=publish.book_set.all() # # 统计一下条数 # books=publish.book_set.all().count() # print(books) ''' 多对多 正向 book---关联字段在book--->author ------> 按字段.all() 反向 author------关联字段在book--->book -----> 按表名小写_set.all() ''' #查询红楼梦这本书所有的作者 # book=Book.objects.filter(name='红楼梦').first() # book.authors.all() #是所有的作者,是一个queryset对象,可以继续点 # print(book.authors.all()) # 查询lqz写的所有书 # lqz=Author.objects.filter(name='lqz').first() # books=lqz.book_set.all() # print(books) # 连续跨表 # 查询红楼梦这本书所有的作者的手机号 # book=Book.objects.filter(name='红楼梦').first() # authors=book.authors.all() # for author in authors: # authordetail=author.authordetail # print(authordetail.phone)
基于对象的查询---是子查询也就是多次查询
四 基于双下划线的查询
# 一对一 # 查询lqz作者的手机号 正向查询 跨表的话,按字段 # 以author表作为基表 # ret=Author.objects.filter(name='lqz').values('authordetail__phone') # print(ret)
# 以authordetail作为基表 反向查询,按表名小写 跨表的话,用表名小写 # ret=AuthorDetail.objects.filter(author__name='lqz').values('phone') # print(ret)
# 查询lqz这个作者的性别和手机号 # 正向 # ret=Author.objects.filter(name='lqz').values('sex','authordetail__phone') # print(ret) # 查询手机号是13888888的作者性别 # ret=Author.objects.filter(authordetail__phone='13888888').values('sex') # print(ret) # ret=AuthorDetail.objects.filter(phone='13888888').values('author__sex') # print(ret) # 基于双 下划线的一对多查询 # 查询出版社为北京出版社出版的所有图书的名字,价格 # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__price') # print(ret) # ret=Book.objects.filter(publish__name='北京出版社').values('name','price') # print(ret) # 查询北京出版社出版的价格大于19的书 # ret=Publish.objects.filter(name='北京出版社',book__price__gt=19).values('book__name','book__price') # print(ret)
# 多对多 # 查询红楼梦的所有作者名字 # ret=Book.objects.filter(name='红楼梦').values('authors__name') # print(ret) # ret=Author.objects.filter(book__name='红楼梦').values('name') # print(ret) # 查询图书价格大于30的所有作者名字 # ret=Book.objects.filter(price__gt=30).values('authors__name') # print(ret)
# 进阶练习--连续跨表 # 查询北京出版社出版过的所有书籍的名字以及作者的姓名 # ret=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name') # print(ret) # ret=Book.objects.filter(publish__name='北京出版社').values('name','authors__name') # print(ret) # 手机号以151开头的作者出版过的所有书籍名称以及出版社名称 # ret=AuthorDetail.objects.filter(phone__startswith='13').values('author__book__name','author__book__publish__name') # print(ret) # ret=Book.objects.filter(authors__authordetail__phone__startswith='13').values('name','publish__name') # print(ret)
五 聚合查询和分组查询
from django.db.models import Avg,Count,Max,Min,Sum
#聚合查询aggregate() # 计算所有图书的平均价格 # ret=Book.objects.all().aggregate(Avg('price')) # print(ret)
# 计算图书的最高价格 # ret=Book.objects.all().aggregate(Max('price')) # print(ret)
#aggregate是queryset的终止子句
# 计算图书的最高价格,最低价格,平均价格,总价 # ret=Book.objects.all().aggregate(Max('price'),Min('price'),Avg('price'),Sum('price')) # print(ret) #分组查询annotate() # 统计每一本书作者个数 # ret=Book.objects.all().annotate(c=Count('authors')) # print(ret) # for r in ret: # print(r.name,'---->',r.c) # ret=Book.objects.all().annotate(c=Count('authors')).values('name','c') # print(ret)
# 统计每一个出版社的最便宜的书(以谁group by 就以谁为基表) # ret=Publish.objects.all().annotate(m=Min('book__price')).values('name','m') # print(ret)
# 统计每一本以py开头的书籍的作者个数 # ret1=Book.objects.all().filter(name__startswith='py').annotate(c=Count('authors')).values('name','c') # print(ret1)
# 总结: group by 谁,就以谁做基表,filter过滤,annotate取分组,values取值
# 总结终极版本 # values在前,表示group by 在后,表示取值 # filter在前,表示where条件,在后表示having
# 统计每一本以py开头的书籍的作者个数--套用模板 # ret2=Book.objects.all().values('name').filter(name__startswith='py').annotate(c=Count('authors')).values('name','c') # print(ret2)
# 查询各个作者出的书的总价格 # ret=Author.objects.all().values('name').annotate(s=Sum('book__price')).values('name','s') # ret=Author.objects.all().annotate(s=Sum('book__price')).values('name','s') # print(ret)
#查询名字叫lqz作者书的总价格 # ret=Author.objects.all().values('pk').filter(name='lqz').annotate(s=Sum('book__price')).values('name','s') # print(ret)
# 查询所有作者写的书的总价格大于30 # ret=Author.objects.all().values('pk').annotate(s=Sum('book__price')).filter(s__gt=2).values('name','s') # ret=Author.objects.all().annotate(s=Sum('book__price')).filter(s__gt=30).values('name','s') # print(ret)
# 总结终极版本 # values在前,表示group by 在后,表示取值 # filter在前,表示where条件,在后表示having
# 统计不止一个作者的图书 ret=Book.objects.all().values('pk').annotate(c=Count('authors')).filter(c__gt=1).values('name','c') # ret = Book.objects.annotate(author_num=Count("authors")).filter(author_num__gt=1).values('name','author_num') print(ret)
六 F查询和Q查询
# F函数
from django.db.models import F # 查询评论数大于阅读数的书 # 这样不行,进行不下去了 # ret=Book.objects.all().filter(commit_num__gt=reat_num) # 这么来做 # ret=Book.objects.all().filter(commit_num__gt=F('reat_num')) # print(ret) # 把所有书的评论数加1 # 不行,进行不下去 # ret=Book.objects.all().update(commit_num+=1) # 不行,进行不下去 # ret=Book.objects.all().update(commit_num=commit_num+1) # 这样来做 # ret=Book.objects.all().update(commit_num=F('commit_num')+1) # print(ret) # 把python这本书的阅读数减5 # ret = Book.objects.all().filter(name='python').update(reat_num=F('reat_num') - 5) # print(ret) # Q函数 为了表示与& ,或 | ,非 ~, from django.db.models import Q
# 查询作者名字是lqz或者名字是egon的书 # 这样行不通 # ret=Book.objects.all().filter(authors__name='lqz',authors__name='egon') # 这样出来 # ret=Book.objects.all().filter(Q(authors__name='lqz')|Q(authors__name='egon')) # print(ret) # 没有意义 # ret = Book.objects.all().filter(Q(authors__name='lqz') & Q(authors__name='egon')) # print(ret)
# 查询作者不是lqz的书 # ret=Book.objects.filter(~Q(authors__name='lqz')) # print(ret) # 构建很复杂的逻辑,需要用括号来区分 # ret = Book.objects.filter((Q(name='红楼梦') & Q(price__gt=100)) | Q(pk__gt=2)) # print(ret)