CSIC_716_2020108【Django入门---模型层】
时间格式的字段
publish_time = models.DateField() # 年月日
publish_time = models.DateTimeField() # 年月日 时分秒
publish_time = models.DateField() # 年月日 publish_time = models.DateTimeField() # 年月日 时分秒 """ auto_now:每次修改数据的时候 都会自动将最新的更新时间记录下来 auto_now_add:只在创建数据的时候将创建时间自动记录下来 之后不会自动改变 """ 用法示例 publish_time = models.DateField(auto_now=True) publish_time = models.DateTimeField(auto_now_add=True)
单表查询
queryset对象可以通过 queryset对象.query 可以查看orm语句对应的sql语句
也可以在django的settings配置文件中加入以下配置,即可查看所有orm操作对应的sql语句
在Django项目的settings.py文件中,增加的配置内容 :
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
必知必会16条 1.create() 返回值:对象本身 2.all() 返回值:queryset对象 3.filter() 返回值:queryset对象 4.update() 返回值:影响的行数 5.delete() 返回值:影响的行数 6.first() 返回值:queryset结果中的对象 7.last() 返回值:queryset结果中的对象 8.get() 返回值:对象本身,如果get的对象不存在,就报错 9.values('field') 返回值:queryset对象,对象中包着{field:value}字典 10.values_list('field') 返回值:queryset对象,对象中包着(value,)元组 11.order_by() 返回值:queryset对象; order_by('name')升序;和order_by('-name')降序 12.count() 返回值:整型,统计queryset中元素的数量 13.exclude() 返回值:queryset对象 14.exists() 返回值:布尔型, 用于判断能否根据条件查出queryset对象 15.reverse() 返回值:queryset对象 ,order_by('name').reverse()等价于order_by('-name') 16.distinct() 返回值:queryset对象, 去重务必要保证value()中所列的字段完全一致,才能去重
双下划线查询
****************大于(等于)******* __gt= __lt= __gte= # greater than equal __lte= ****************范围******* __in=[ ,,,] __range=( ,) #包含边界 ***************模糊查询******* __contains=‘F’ #严格大小写 __icontains=‘F’ #忽略大小写 ignorecontains
****************对于时间格式的字段**************** fieldname__year=2020 #查询年份是2020的记录 fieldname__month=12 #查询月份是12的记录
当表中有外键的时候,通过ORM增删改查的方法
这里要知道一个前提条件,外键字段在模型类中如果叫field,到数据库中会自动加一个尾缀_id变成field_id
在多对多的表关系中,外键虽然建在使用频率较高的表上,但是数据库中,使用频率较高的表中没有外键字段,外键字段实际是出现在多对多生成的第三张表中。
故在初始化使用频率较高的那张表时,不需要输入多对多外键的值,多对多外键值及其绑定关系需要单独在第三张表中建立。
模型类中定义的表的操作
字段以数据库中的为准 进行新增(多对多外键字段不在此新增)
#操作数据库对应的字段,一句话直接创建,此时字段以数据库中的为准 models.Book.objects.create(title='鬼谷子',press_id=4,book_detail_id=2)
以模型类中的字段名为准 进行新增(多对多外键字段不在此新增)
#先获取对象(两种方式获取对象) press_obj = models.Company.objects.filter(pk=3).first() # 一定要从queryset中通过例如 .first()取到对象 press_obj = models.Company.objects.get(pk=2) # 或者通过get直接取到对象 book_detail_obj = models.BookDetail.objects.filter(pk=1).last() 外键直接等于对象即可,此时的外键不用加尾缀_id,以模型类中的字段名为准 res1 = models.Book.objects.create(title='诗经', press=press_obj, book_detail=book_detail_obj)
查用filter、改用update,方法与上面增类似,也有两种方式。
多对多的情况下衍生出的第三张表的增删改查
增
方式一
author_obj1 = models.Author.objects.get(pk=1) #取出外键关联的对象 author_obj2 = models.Author.objects.get(pk=2) #取出外键关联的对象 book_obj = models.Book.objects.get(pk=1) # 取出外键所在的对象 book_obj.author.add(author_obj1, author_obj2) #建立绑定关系
方式二
book_obj = models.Book.objects.get(pk=2) book_obj.author.add(3, 4) # 直接与作者的id建立绑定关系
add专门给第三张关系表添加数据,括号内即可以传数字也可以传对象 并且都支持传多个
移除绑定关系用remove( , )
更新绑定关系用set( ) 括号内一定要构造成可迭代对象(列表或元组)。
清除某个对象外键的绑定关系用 .clear( ) ,括号内不需要任何参数
多(跨)表查询
跨表查询的方式
1.子查询 将一张表的查询结果当做另外一张表的查询条件
正常解决问题的思路 分步操作
2.链表查询
inner join
left join
right join
union
建议:在写sql语句或者orm语句的时候 千万不要想着一次性将语句写完 一定要写一点查一点再写一点
正向查询反向查询的概念:
正向查询:跨表查询的时候,当外键在当前对象中,去查另一个表的数据时,就是正向查询,正向查询用字段名,
反向查询:跨表查询时,当外键在需要查询的表中时,就是反向查询,反向查询用表名小写,
反向查询时,需要以_set.all()结尾,因为会查到多个结果。
例如图书与出版社是一对多的关系,即一种图书只能是一个出版社,而一家出版社可以对应多种图书。
基于对象的跨表查询(正向查询):【子查询】
先获取对象,在通过外键的字段名,直接以句点符得到外键所在的对象,如果对象可能会有多个的话,要在对象结尾加上 .all()
基于对象的跨表查询(反向查询):【子查询】
如果是一对多或者多对多关系,先获取对象,通过外键所在的表名,通过 对象.小写表名_set.all( ) 即可查到结果。
如果是一对一关系,那么先获取对象,然后 对象.小写表名 就可以查到结果
基于双下划线的跨表查询:【链表查询】(非常重要)
models.Book.objects.filter(pk=1).values('publish__name') 正向查询
models.Publish.objects.filter(book__pk=1).values('name') 反向查询
__也可以连续跨越多张表,再通过__取值
查到的结果是queryset,即 [{'':''},{'':''}]
只要表之间有关系 ,就可以通过正向的外键字段或者反向的表名小写 连续跨表操作。
# 基于双下划线跨表查询(链表查询) # 1.查询书籍pk为1的出版社名称 # models.Book.objects.filter(pk=1).values('publish__name') # models.Publish.objects.filter(book__pk=1).values('name') # 正向 # res = models.Book.objects.filter(pk=1).values('publish__name') # 写外键字段 就意味着你已经在外键字段管理的那张表中 # print(res) # 反向 # res = models.Publish.objects.filter(book__pk=1) # 拿出版过pk为1的书籍对应的出版社 # res = models.Publish.objects.filter(book__pk=1).values('name') # print(res) # 2.查询书籍pk为1的作者姓名和年龄 # res = models.Author.objects.filter(book__pk=1).values(name,author_detail__age) # res = models.Book.objects.filter(pk=1).values(author__age,author__author_detail__age) # 正向 # res = models.Book.objects.filter(pk=1).values('title','authors__name','authors__age') # print(res) # 反向 # res = models.Author.objects.filter(book__pk=1) # 拿出出版过书籍pk为1的作者 # res = models.Author.objects.filter(book__pk=1).values('name','age','book__title') # print(res) # 3.查询作者是jason的年龄和手机号 # # models.Author.objects.filter(name='jason').values(age,detail__phone) # (models.Author_detail.objects.filter(author__name=jason).values(author__age, phone) # 正向 # res = models.Author.objects.filter(name='jason').values('age','author_detail__phone') # print(res) # 反向 # res = models.AuthorDetail.objects.filter(author__name='jason') # 拿到jason的个人详情 # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age') # print(res) # 查询书籍pk为的1的作者的手机号 # res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone') # print(res) # res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone') # print(res) """ 只要表之间有关系 你就可以通过正向的外键字段或者反向的表名小写 连续跨表操作 """
(务必掌握折叠的代码)
聚合查询
from django.db.models import Max,Min,Avg,Count,Sum
aggregate ( 聚合函数要给他起个名字 = 关键字(‘fieldname’),支持多个 )
res = models.Book.objects.aggregate(avg_num=Avg('price'))
分组查询
from django.db.models import Max,Min,Avg,Count,Sum
annotate ( 聚合函数要给他起个名字 = 关键字(‘fieldname’) )
分组的总结: 首先明确分组的依据是哪一个类模型,其次通过双下划线查询,结合聚合函数,加上filter筛选和values取值,查出结果。
1.统计每一本书的作者个数 res=models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num') 2.统计出每个出版社卖的最便宜的书的价格 res=models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price','book__title') 3.统计不止一个作者的图书 res=models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title') 4.查询各个作者出的书的总价格 res=models.Author.objects.annotate(price_sum=Sum('book__price')).values('name','price_sum')
自定义分组
5.如何按照表中的某一个指定字段分组 res = models.Book.objects.values('price').annotate() 就是以价格分组
F与Q查询
from django.db.models import F , Q
F('fieldname') 获取字段对应的值
models.Book.objects.update(price=F('price') + 100) # 全体价格+100 models.Book.objects.filter(kucun__gt=F('maichu')) #筛选库存大于卖出
Q能够改变查询的条件关系 and or not
# 名字是python入门and价格是1000的书籍 models.Book.objects.filter(title='python入门',price=1000) # 名字是python入门and价格是1000的书籍 models.Book.objects.filter(Q(title='python入门'),Q(price=1000)) # 名字是python入门or价格是1000的书籍 models.Book.objects.filter(Q(title='python入门')|Q(price=1000)) # 名字(not)不是python入门or价格是1000的书籍 models.Book.objects.filter(~Q(title='python入门')|Q(price=1000))
Q的高级用法
#先构造Q类的对象 q = Q() #其次定下q对象之间连接时的关系,默认是and,可以按照以下方法调整 q.connector = 'or' #然后给q对象增加内容 q.children.append(('fieldname1','value1')) # 括号内的元组都是字符串 q.children.append(('fieldname2','value2')) # 括号内的元组都是字符串 #写查询语句,筛选条件直接放q models.Book.objects.filter(q) #q类似于 fieldname1=‘value1’ or fieldname2=‘value2’