ORM数据库查询操作(单表,多表)(day64)
脚本测试:想在django中对某一个py文件进行测试,可以直接在项目文件中写一个测试脚本文件,一般在test.py文件中,也可以自己创建一个py文件
#先在manage.py文件中将前四行代码拷贝过来,并且加上两句代码,然后书写自己要测试的代码,运行。本章节在这里进行ORM操作 import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day64.settings") import django django.setup()
单表操作
#增 #方式1 res=models.User.objects.create(name='jack',age=18,register_time='2002-10-16') #拿到一个用户空对象,在空对象里面对字段名进行添加 方式2 #import datetime #ctime = datetime.datetime.now() user_obj = models.User(name='Tom',age=20,register_time=ctime) user_obj.save() #相当于直接对类属性进行修改,注意修改完之后需要进行.save操作,将结果进行保存 #删 #方式1 res = models.User.objects.filter(pk=2).delete()#批量删除 """ pk就表示主键,任意一个表的主键都能用pk指代,自己设置的主键字段名可能会被修改,使用pk防止出错 """ 方式2 user_obj = models.User.objects.filter(pk=1).first() user_obj.delete()#针对性删除 #改 #方式1:使用了update方法进行修改 models.User.objects.filter(pk=4).update(name='egonDSB') #方式2:也相当于是对类属性进行修改吧,所以需要保存 # user_obj = models.User.objects.get(pk=4)#找不到就报错,不建议使用user_obj = models.User.objects.filter(pk=6)#不报错,推荐使用user_obj.name = 'egonPPP'user_obj.save()#一定要记得.save()保存
必知必会13条:ORM操作中很重要的13条基本语法,常用,其他的语法可以用到、看到的时候自己积累
# 1.all() 查询所有数据 # 2.filter() 带有过滤条件的查询 # 3.get() 直接拿数据对象 但是条件不存在直接报错 # 4.first() 拿queryset里面第一个元素 res = models.User.objects.all().first() print(res) # 5.last() res = models.User.objects.all().last() print(res) # 6.values() 可以指定获取的数据字段 select name,age from ... 列表套字典 res = models.User.objects.values('name','age') # <QuerySet [{'name': 'jason', 'age': 18}, {'name': 'egonPPP', 'age': 84}]> print(res) # 7.values_list() 列表套元祖 res = models.User.objects.values_list('name','age') # <QuerySet [('jason', 18), ('egonPPP', 84)]> print(res) # """ # 查看内部封装的sql语句 # 上述查看sql语句的方式 只能用于queryset对象 # 只有queryset对象才能够点击query查看内部的sql语句 # # """ # 8.distinct() 去重 res = models.User.objects.values('name','age').distinct() print(res) """ 去重一定要是一模一样的数据,如果带有主键那么肯定不一样,你在往后的查询中一定不要忽略主键 """ # 9.order_by() res = models.User.objects.order_by('age') # 默认升序 res = models.User.objects.order_by('-age') # 降序 print(res) # 10.reverse() 反转的前提是 数据已经排过序了 order_by() res = models.User.objects.all() res1 = models.User.objects.order_by('age').reverse() print(res,res1) # 11.count() 统计当前数据的个数 res = models.User.objects.count() print(res) # 12.exclude() 排除在外 res = models.User.objects.exclude(name='jason') print(res) # 13.exists() 基本用不到因为数据本身就自带布尔值 返回的是布尔值 res = models.User.objects.filter(pk=10).exists() print(res)
在第七条中讲到了有关查看ORM内部sql语句的使用,那么在这里说明一下:
# 方式1 res = models.User.objects.values_list('name','age') # <QuerySet [('jason', 18), ('egonPPP', 84)]> print(res.query) queryset对象才能够点击query查看内部的sql语句 # 方式2:所有的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', }, } } #那么所有的数据库查询语句都能通过.query的方式来找到对应的sql语法
神奇的双下划线查询(在查询中使用,使用方式:字段名__条件)
#1.查询年龄大于20岁的数据 res = models.User.objects.filter(age__gt=20)#grater than print(res) #2.询年龄小于20岁的数据 res = models.User.objects.filter(age__lt=20)#lower than print(res) #大于等于 小于等于 #在gt或者lt后面加上e(equal) lte gte #年龄是18 20 或者25 res = models.User.objects.filter(age__in=[18,20,25]) print(res) #年龄在18到30岁之间 首尾都包括 res = models.User.objects.filter(age__range = [18,30]) print(res) #查询出名字里面含有s的数据 模糊查询(区分大小写) res = models.User.objects.filter(name__contains='s') print(res) #在contains前面加上一个i(ignore),不区分大小写 #以什么什么开头 以什么什么结尾 res = models.User.objects.filter(name__startswith='j') es1 = models.User.objects.filter(name__endswith='j') print(res,res1)
在讲多表查询之前,先讲一个概念:正向与反向查询,理解了这个之后再去理解多表查询会好很多
正向查询:通过外键字段所在表去查对应外键指向表(ps:外键一般设置在多的一方)
反向查询:通过外键字段所指向的表去查外键字段所在表
一对一、一对多、多对多表的正反向查询均是如此
一对多外键的增删改查
#增(Book表中含有一个publish外键字段关联Publish表) #方式1:直接写对应表中的字段,外键字段需要加_id(查看数据库Book表中所录入的字段明)。 models.Book.objects.create(title='python',price=899.23,publish_id=1) #方式2:虚拟字段+对象 publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.object.filter(title='java',price=123.34,publish=publish_obj) #删 models.Publish.objects.filter(pk=1).delete() # 级联删除 #改 #方式一:虚拟字段+对象 通过Book表中录入字段名publish_id models.Book.objects.filter(pk=1).update(publish_id=2) 方式2:publish_obj = models.Publish.objects.filter(pk=1).first()#先查到需要修改的字段的对象 models.Book.objects.filter(pk=1).update(publish=publish_obj)
多对多外键增删改查
#增
#如何给书籍添加作者:(书籍与作者关系是多对多) #方式1:通过id添加 #首先找到要添加作者的书籍对象 book_obj = models.Book.objects.filter(pk=1).first() #将该书籍对象通过Book表中的author字段关联到作者表中 book_obj.author book_obj.authors.add(1)#添加一个id值为1的作者 book_obj.authors.add(2,3)#同时添加id值为2,3的作者
#如果add之后的id值不存在就会报错
#方式2:通过对象添加 #首先找到要添加作者的书籍对象 book_obj = models.Book.objects.filter(pk=1).first() #找到给书籍添加作者的作者对象author_obj1 = models.Author.objects.filter(pk=2).first() author_obj2 = models.Author.objects.filter(pk=3).first() #通过对象的方法给书籍加上作者信息book_obj.authors.add(author_obj) book_obj.authors.add(author_obj1,author_obj2)
#删 方式1:#通过id值删除 book_obj.authors.remove(2) book_obj.authors.remove(1,3) #删除的是author表中对应的作者的id值,如果没有的话也不报错 方式2:通过对象删除 author_obj = models.Author.objects.filter(pk=2).first() author_obj1 = models.Author.objects.filter(pk=3).first()
#改 方式1:通过id值或者主键值 book_obj.authors.set([1,2]) # 括号内必须给一个可迭代对象 book_obj.authors.set([3]) # 括号内必须给一个可迭代对象 方式2:通过对象 author_obj = models.Author.objects.filter(pk=2).first() author_obj1 = models.Author.objects.filter(pk=3).first() book_obj.authors.set([author_obj,author_obj1]) # 括号内必须给一个可迭代对象
"""
set
括号内必须传一个可迭代对象,该对象内既可以数字也可以对象 并且都支持多个
"""
# 清空 # 在第三张关系表中清空某个书籍与作者的绑定关系 book_obj.authors.clear() """ clear 括号内不要加任何参数 """
多表查询:
先记住两句口诀:
正向查询按字段
反向查询按表名小写(可能会加_set等) 很重要!请记住
子查询(基于对象的跨表查询)
1.查询书籍主键为1的出版社 #找到主键为1的书籍对象 book_obj = models.Book.objects.filter(pk=1).first() #直接查询该书籍对象的出版社(Book表下面的publish字段含有外键,所以是正向查询) book_obj.publish print(res)# print(res.name)# print(res.addr) 2.查询书籍主键为2的作者 #找到主键为1的书籍对象 book_obj = models.Book.objects.filter(pk=2).first() #查找作者(Book表下面有的author字段含有外键,所以是正向查询) res = book_obj.authors.all()#是一个QuerySet集合 print(res) 3.查询作者新新子的电话号码 #查找出作者为新新子的作者对象 author_obj = models.Author.objects.filter(name='新新子').first() #找出该作者对象的所有详细信息 res = author_obj.author_detail #点出需要查找的详细信息 print(res.phone) print(res.addr)
正向什么时候需要加.all()?当你的结果可能有多个的时候就需要加.all()
如果是一个则直接拿到该数据对象
book_obj.publish
book_obj.authors.all()
author_obj.author_detail
4.查询出版社是东方出版社出版的书 #先找出东方出版社 publish_obj = models.Publish.objects.filter(name='东方出版社').first() #再找出东方出版社出版的所有的书(出版社于书存在外键关系,但是外键字段再书籍表中,所以是反向查询) res = publish_obj.book_set.all() print(res) 5.查询作者是新新子写过的书 #先将作者新新子对象找出 author_obj = models.Author.objects.filter(name='新新子').first() #然后找出该作者写的所有的书(作者表跟书籍表有外键关系,但是外间字段在书籍中,所以是反向查询) res = author_obj.book_set.all() print(res) 6.查询手机号是110的作者姓名 #先找出手机号码为110的作者详细信息对象 author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first() #查找该详细信息的作者姓名(同样作者详细信息与作者表有外间关系。但是外键字段在作者表中,故也是反向查询) res = author_detail_obj.author print(res.name)
"""
基于对象查询时:
反向查询的时候,当你的查询结果可以有多个的时候 就必须加_set.all()
当你的结果只有一个的时候,不需要加_set.all(),直接就是表明小写
自己总结出 自己方便记忆的即可 每个人都可以不一样
"""
联表查询(基于双下划线的跨表查询)
1.查询新新子的手机号和作者姓名 #方式1:先拿出姓名为新新子的作者对象,通过这个对象去找他的手机号。由于作者表中有一个作者详细信息的外键字段,所以直接结合前面所说的正向查询通过字段查,再通过__跨到详细信息表中去查手机号 res=models.Author.objects.filter(name='新新子').values('author_detail__phone','name') print(res) #方式2: 先拿到作者为新新子的所有详细信息,再找出需要的信息。由于是先从详细信息表中找作者信息,属于反向查询,按照口诀:反向查询按表明小写所以是:author__name='新新子',同过__跨到作者表中去找name
res = models.AuthorDetail.objects.filter(author__name='新新子') # 拿作者姓名是新新子的作者详情 res=models.AuthorDetail.objects.filter(author__name='新新子').values('phone','author__name') print(res)
2.查询书籍主键为1的出版社名称和书的名称
#正向:直接找主键为1的书籍,由于书籍中含有出版社主键,要找出版社的名称,书籍中没有出版社名称,所以要通过__来跨表,跨到Publish中去查找name res=models.Book.objects.filter(pk=1).values('title','publish__name') print(res) # 反向:先在Publish中找,Publish中没有书籍的有关信息,所以要在Publish中跨到书籍中去找,外键在Book中,所以是反向查找,通过表明小写关联,再通过__跨表过去,找title也是一样 res=models.Publish.objects.filter(book__id=1).values('name','book__title') print(res)
3.查询书籍主键为1的作者姓名 res = models.Book.objects.filter(pk=1).values('author__name') print(res) # 反向 res = models.Author.objects.filter(book__id=1).values('name') print(res)
4.查询书籍主键是1的作者的手机号 # book author authordetail 一共有三张表,上来直接找出主键为1的书籍,然后根据要求,先去找作者。从书中找作者,正向,所以直接通过author字段,然后__跨到作者表中,然后从作者表中跨表寻找作者的手机号。作者表查到作者详情表正向,所以是通过作者表中的
#author_detail来关联,再通过__跨到作者详情表中寻找phone。所以一工进行了两次跨表
res=models.Book.objects.filter(pk=1).values('author__author_detail__phone') print(res)
联表查询 总结:先看通过正向查还是反相查,根据口诀来寻找跨表的关联对象,正向通过字段关联,反向通过表名小写关联。然后通过__表示跨表,跨到需要查找的那张表中去寻找需要的字段信息。你只要掌握了正反向的概念以及双下划线,就能无限制的跨表查询。