Django基础之模型层(02)
# 多表查询 """ 正向查询 反向查询 当前查询对象是否含有外键字段 如果有就是正向 没有无则是反向 口诀: 正向查询按外键字段 多对多需要额外再加一个.all() 一对多和一对一不需要加 反向查询按表名小写 一对多与多对多 _set.all() 一对一 不需要加 """
2 多表查询
#####################基于对象的跨表查询##################### # 子查询:将一张表的查询结果当做另外一条SQL语句的条件(括号括起来) # 1.查询书籍主键为4的出版社名称 # 先查询书籍对象 # book_obj = models.Book.objects.filter(pk=4).first() # 外键字段在书这里 所以是正向查询 # res = book_obj.publish # print(res) # print(res.title) # print(res.addr) # 2.查询书籍主键为3的作者姓名 # 先查询书籍对象 # book_obj = models.Book.objects.filter(pk=3).first() # 外键字段在书这里 所以是正向查询 # res = book_obj.authors # print(res) # app01.Author.None # res = book_obj.authors.all() # print(res) # <QuerySet [<Author: 作者对象:oscar>, <Author: 作者对象:egon>]> # 3.查询作者jason的地址 # 先查询jason数据对象 # author_obj = models.Author.objects.filter(name='jason').first() # 外键字段在作者这里 所以是正向查询 # res = author_obj.author_detail # print(res) # print(res.addr) # print(res.phone) # 4.查询东方出版社出版的书籍 # 先查询出版社对象 # publish_obj = models.Publish.objects.filter(title='东方出版社').first() # 外键字段在书那里自己没有 所以是反向 # res = publish_obj.book_set # print(res) # app01.Book.None # res = publish_obj.book_set.all() # print(res) # 5.查询jason写过的书籍 # 先查询jason数据对象 # author_obj = models.Author.objects.filter(name='jason').first() # 外键字段在书那里自己没有 所以是反向 # res = author_obj.book_set # print(res) # app01.Book.None # res = author_obj.book_set # print(res) # app01.Book.None # res = author_obj.book_set.all() # print(res) # app01.Book.None # 6.查询电话是120的作者 # 先查询120数据对象 # author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first() # 外键字段在作者那里本身没有 所以是反向 # res = author_detail_obj.author # print(res) # print(res.name) # print(res.age) ########################基于双下滑线的跨表查询 # 1.查询书籍主键为4的出版社名称 # res = models.Book.objects.filter(pk=4).values('publish__title','publish__addr','title') # print(res) # 2.查询书籍主键为3的作者姓名 # res = models.Book.objects.filter(pk=3).values('authors__name') # print(res) # 3.查询作者jason的地址 # res = models.Author.objects.filter(name='jason').values('author_detail__addr','name','age') # print(res) # 4.查询北方出版社出版的书籍名称 # res = models.Publish.objects.filter(title='北方出版社').values('book__title') # print(res) # 5.查询jason写过的书籍 # res = models.Author.objects.filter(name='jason').values('book__title','name','age') # print(res) # 6.查询电话是120的作者 # res = models.AuthorDetail.objects.filter(phone=120).values('author__name','author__age','addr') # print(res) ############进阶操作############# # 1.查询书籍主键为4的出版社名称 # res = models.Book.objects.filter(pk=4).values('publish__title','publish__addr','title') # print(res) # 反向查询高阶部分 # res = models.Publish.objects.filter(book__pk=4) # print(res) # 2.查询书籍主键为3的作者姓名 # res = models.Book.objects.filter(pk=3).values('authors__name') # print(res) # 反向查询高阶部分 # res = models.Author.objects.filter(book__pk=3) # print(res) # 3.查询作者jason的地址 # res = models.Author.objects.filter(name='jason').values('author_detail__addr','name','age') # print(res) # 反向查询高阶部分 # res = models.AuthorDetail.objects.filter(author__name='jason') # print(res) # 查询书籍主键为3的作者的电话号码 # res = models.Book.objects.filter(pk=3).values('authors__author_detail__phone') # print(res) # res = models.AuthorDetail.objects.filter(author__book__pk=3).values('phone') # print(res) # res = models.Author.objects.filter(book__pk=3).values('author_detail__phone') # print(res)
3 F查询
# F查询 from django.db.models import F # 1.查询库存数大于卖出数的书籍 # res = models.Book.objects.filter(kucun__gt=F('maichu')) # print(res) # 2.将所有的书籍价格上涨100块 # res = models.Book.objects.update(price=F('price') + 100) # print(res) # 3.将所有的书籍名称加上"爆款"后缀 '''针对字符串不能直接拼接 需要额外导入模块操作''' # models.Book.objects.update(title=F('title') + '爆款') # from django.db.models.functions import Concat # from django.db.models import Value # ret3 = models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
4 Q查询
# 1.查询书名是三国演义爆款或者库存是100的书籍 '''filter()括号内可以写多个参数 逗号隔开 默认只支持and连接''' from django.db.models import Q # res = models.Book.objects.filter(title='三国演义爆款',kucun=100) # print(res) # res1 = models.Book.objects.filter(Q(title='三国演义爆款'),Q(kucun=100)) # and # res1 = models.Book.objects.filter(Q(title='三国演义爆款')|Q(kucun=100)) # or # res1 = models.Book.objects.filter(~Q(title='三国演义爆款')|Q(kucun=100)) # not # print(res1.query) '''Q进阶用法''' # condition = input('请输入你需要按照什么字段查询数据>>>:') # data = input('请输入你需要查询的数据名称>>>:') # q = Q() # 生成一个Q对象 # q.children.append((condition,data)) # res = models.Book.objects.filter(q) # print(res) q = Q() q.connector = 'or' # 可以修改连接条件 q.children.append(('title__contains','三')) q.children.append(('price__gt',200)) # 可以添加多个条件 并且也是and关系 res = models.Book.objects.filter(q) print(res) print(res.query)
5 事务
""" 1.事务四大特性 ACID 原子性 一致性 独立性 持久性 2.数据库设计三大范式 课下百度搜索自己概括 MySQL start transcation commit rollback """ from django.db import transaction try: with transaction.atomic(): # 创建一条订单数据 models.Order.objects.create(num="110110111", product_id=1, count=1) # 能执行成功 models.Product.objects.filter(id=1).update(kucun=F("kucun") - 1, maichu=F("maichu") + 1) except Exception as e: print(e)
6 执行原生SQL语句
res = models.Book.objects.raw('select * from app01_book') for i in res: print(i)
7 模型层字段及参数
models.AutoField(primary_key=True) models.CharField(max_length=32) # varchar(32) models.IntergeField() # int() models.DateField() # date models.DateTimeField() # datetime auto_now auto_now_add models.DecimalField() # float() models.BooleanField() 给这个字段传布尔值会自动转换成数字0或1 一般用在状态二选一 TextField() 存储大段文本(bbs项目会使用) EmailField() 存储邮箱格式数据 FileField() 存储数据路径(bbs项目会使用) """自定义字段""" from django.db.models import Field class MyCharField(Field): def __init__(self,max_length,*args,**kwargs): self.max_length = max_length super().__init__(max_length=max_length,*args,**kwargs) def db_type(self, connection): return 'char(%s)'%self.max_length
8 常见参数
max_length varbose_name default null auto_now auto_now_add to unique db_index choices # choices参数 创建用户表 性别 两到三种状态 学历 也是有限个 在职状态 也是有限个 婚姻 也是有限个 ... """针对某个字段可以列举完全的情况 一般都是使用choices参数""" class Server(models.Model): host = models.CharField(max_length=32) status_choices = ( (1,'在线'), (2,'待上线'), (3,'宕机'), (4,'待上架') ) status = models.IntegerField(choices=status_choices) desc_choices = ( ('哈哈','哈哈哈哈哈哈'), ('呵呵','呵呵呵呵呵呵'), ('嘿嘿','嘿嘿嘿嘿嘿嘿'), ('嘻嘻','嘻嘻嘻嘻嘻嘻'), ) desc = models.CharField(max_length=32,choices=desc_choices) # 获取对应关系 .get_字段名_display()
9 ORM查询优化
# 惰性查询 用不到的数据即使写了orm语句也不会执行 1.only与defer 2.select_related与prefech_related # 1.only与defer # res = models.Book.objects.values('title') # 列表套字典 # res1 = models.Book.objects.only('title') # 列表套对象 # print(res1) # for i in res1: # # print(i.title) # print(i.price) """ only括号内写什么字段 生成的对象就含有对应的属性 在查找该属性的时候不再走数据库查询 但是一旦查找括号内没有的字段属性 则每次都会走数据库查询 """ # res1 = models.Book.objects.defer('title') # # print(res1) # 列表套对象 # for i in res1: # # print(i.title) # print(i.title) """ defer与only刚好相反 生成的对象就不含有对应的属性 在查找该属性的时候需要每次走数据库查询 但是一旦查找括号内没有的字段属性 则不需要走数据库查询 """ # res = models.Book.objects.filter(pk=3).first() # print(res.publish.title) # res = models.Book.objects.select_related('publish') # for i in res: # print(i.publish.title) """ select_related相当于连表操作 先将models后面的表和括号内外键字段关联的表连接起来 之后一次性把所有的数据封装到数据对象中 """ res = models.Book.objects.prefetch_related('publish') for i in res: print(i.publish.title) """ prefetch_related相当于子查询 先查询models后面的表的所有的数据 然后将括号内关联的表的数据全部查询出来 之后整合到一起 """
愿君前程似锦,归来仍是少年