Django----模型层(ORM)
Django----模型层(ORM)
配置测试脚本
再要测试的app文件夹下,建一个tests文件
需要注意的是,导入models时,一定要把导入语句放在main方法内部
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
import django
django.setup()
# 一定要等待测试脚本搭建完毕之后 才能导入django文件进行测试
from app01 import models
单表操作
- all() 查询所有数据
res = models.Books.objects.all()
==># <QuerySet [<Books: 假如给我三天光明>, <Books: 鲁滨逊漂流记>]>
-
filter() 筛选
该筛选方法,类似于原生sql语句中的where关键字,如有多个值,关系为and,返回的值是queryset对象
res = models.Books.objects.filter(pk=2,title='鲁滨逊漂流记')#支持传多个参数
==># <QuerySet [<Books: 鲁滨逊漂流记>]>
-
get() 筛选
该筛选方法,获取的是数据对象本身,如果匹配的条件不存在,会直接报错
并且,要求查询到的结果只能是唯一的,如果有两条及以上,会报错
res = models.Books.objects.get(title='鲁滨逊漂流记')
- first() 通过该方法,可以取queryset对象的第一个数据对象
res = models.Books.objects.filter(title='鲁滨逊漂流记').first()
- last() 通过该方法,可以取queryset对象的最后一个数据对象
res = models.Books.objects.filter(title='鲁滨逊漂流记').last()
- count() 通过该方法,可以统计数据个数
num = models.Books.objects.count()
-
values() 通过该方法,可以获取数据对象中指定字段的值,可以取多个
返回的值以列表套字典的形式返回
res = models.Books.objects.values('title','price')
-
values_list() 通过该方法,可以获取数据对象中指定字段的值,可以取多个
返回的值以列表套元祖的形式返回
res = models.Books.objects.values_list('title','price')
- order_by() 通过该方法,让查询结果按照指定的字段排序
res = models.Books.objects.order_by('price') #默认是升序,在字段前加'-'号,变成降序
-
reverse() 通过该方法,可以是查询结果的顺序颠倒
但是该方法有一个前提条件,颠倒的对象必须是已经排序过的结果,否则没有效果
res3 = models.Books.objects.all().order_by('price').reverse()
- exclude() 通过该方法,可以剔除指定数据
res = models.Books.objects.all().exclude(title='假如给我三天光明')
- exists() 通过该方法,可以判断查询到的结果,是否为空,结果返回一个布尔值
res = models.Books.objects.filter(pk=1).exists()
-
distinct() 通过该方法,可以对查询到的结果进行去重操作
该方法,需要数据必须是完全一样的条件下,才能生效
res = models.Books.objects.values('title','price').distinct()
双下划綫查询
查询价格大于80的书籍 __gt
res = models.Books.objects.filter(price__gt=80)
查询价格小于400 的书籍 __lt
res = models.Books.objects.filter(price__lt=80)
查询价格大于等于80 __gte
res = models.Books.objects.filter(price__gte=80)
查询价格小于等于80 __lte
res = models.Books.objects.filter(price__lte=80)
查询价格是77或者88的书籍 price__in
res = models.Books.objects.filter(price__in=[77,88])
查询价格在90到100之间的书籍 price__range
头尾兼顾
res = models.Books.objects.filter(price__range=(90,100))
查询出版日期是2019年的书籍 __year
res = models.Books.objects.filter(publish_date__year='2019')
查询出版日期是1月份的书籍 __month
res = models.Books.objects.filter(publish_date__month='1')
模糊查询
查询书籍是以三开头的书 title__startswith
res = models.Books.objects.filter(title__startswith='假')
查询书籍是以义结尾的书 title__endswith
res = models.Books.objects.filter(title__endswith='记')
查询书籍名称中包含游字的书籍 title__contains
__contains
默认区别字母大小写,通过使用__icontains
,该方法不区分大小写
res = models.Books.objects.filter(title__contains='游')
图书管理表设计
创建图书表
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
publish_date = models.DateField(auto_now=True)
publish = models.ForeignKey(to='Publish')
authors = models.ManyToManyField(to='Author')
#auto_now:每次修改的数据的时候 都会自动更新修改书籍(展示最新的一次修改时间)
#auto_now_add:当数据创建出来的时候 会自动将创建时间记录下来
创建出版社表
class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
创建作者表
class Author(models.Model):
name = models.CharField(max_length=32)
email = models.EmailField()
author_detail = models.OneToOneField(to = 'AuthorDetail')
创建作者详细表
class AuthorDetail(models.Model):
phone = models.BigIntegerField()
addr = models.CharField(max_length=64)
外键字段(一对多)的增删改查
增
第一种方式
models.Book.objects.create(title='狂人日记',price=888,publish_id=1)
第二种方法
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='狂人日记2',price=333,publish=publish_obj) # 传虚拟字段 跟数据对象即可
改
第一种方式
models.Book.objects.filter(pk=1).update(publish_id=2)
第二种方式
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
删
models.Publish.objects.filter(pk=1).delete() # 默认就是级联删除 级联更新
外键字段(多对多)的增删改查
增
第一种方式
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(2)
#book_obj通过.authors就能跨到第三张表,在通过add()添加作者id
第二种方式
book_obj = models.Book.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.add(author_obj,author_obj1)
#add()方法可以接受对象
add方法 能够朝第三张关系表添加数据
即支持传数字,也支持传对象,并且两者都可以是多个
改
第一种方法
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.set((1,3))
第二种方法
通过传入对象
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.set((author_obj,author_obj1))
通过set修改多对多关系表中的数据
该方法既可以传数字也可以传对象,但是需要注意的是括号内必须是可迭代对象,都支持多个
删
第一种方式
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.remove(2,3)
第二种方式
author_obj = models.Author.objects.filter(pk=3).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.remove(author_obj,author_obj1)
通过remove方法删除,既可以传数字,也可以穿对象
并且都支持传多个,不需要迭代
清空数据
#删除某个数据在第三张表中的所有记录
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.clear()
跨表查询
正反向查询
关键字段所在的表----->关联表 为正向查找
通过对象查找(子查询)
语法:
对象.关联字段.字段
通过字段查找(联表查询)
语法:
关联字段__字段
关联表-------->关键字段所在表 为反向查找
通过对象查找(子查询)
语法:
obj.表名_set
通过字段查找(联表查询)
语法:
表名__字段
子查询(分步操作)
查询书籍主键为2的出版社名称
book_obj = models.Book.objects.filter(pk=2).first() # 出版社对象
publish_name = book_obj.publish.name
查询书籍主键为4的作者姓名
book_obj = models.Book.objects.filter(pk=4).first()
name_list = book_obj.authors.all() #若查询结果不止一个,需要用all()方法
#当正向查询 ' . ' 外键字段数据有多个的情况下 需要.all()来接受所有数据
查询作者是鲁迅的手机号码
author_obj = models.Author.objects.filter(name='鲁迅').first()
author_phone = author_obj.author_detail.phone
查询出版社是东方出版社出版过的书籍 (反向查找) obj.表名_set
publish_obj = models.Publish.objects.filter(name='哈哈出版社').first()
book_obj_list = publish_obj.book_set.all()
查询手机号是111的作者姓名 (一对一反向查找)
author_detail_obj = models.AuthorDetail.objects.filter(phone=222).first()
author_name = author_detail_obj.author.name
一对多,多对多反向查找时,对象 . 表名 后需要加_set
一对一反向查找则不需要_set
联表查询
类似于sql中inner join , left join , right join , union
查询书籍pk为2的出版社名称
正向查找
models.Book.objects.filter(pk=2).values('publish__name')
反向查找
models.Publish.objects.filter(book__pk = 2).values('name')
查询书籍pk为2的作者姓名和邮箱
models.Author.objects.filter(book__pk=2).values('name','email')
#models后面跟哪张表,就以那张表为基表
查询书籍pk是2的作者的手机号 (三表联查)
models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
models.Author.objects.filter(book__pk=2).values('author_detail__phone')
聚合查询( aggregate() )
聚合函数的方法不是内置的,需要导入模块
from django.db.models import Avg, Sum, Max, Min, Count
筛选出价格最高的书籍的
models.Book.objects.aggregate(name = Max('price'))
#name可以自定义名字,不定名字,会自定义名字格式 字段名_函数名
求书籍平均价格
models.Book.objects.aggregate(Avg('price'))
支持所有函数一起使用
models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('price'),Avg('price'))
分组查询( annotate() )
统计每一本书的书名和对应的作者人数
models.Book.objects.annotate(author_count=Count('authors__id')).values('title','author_count')
#models后面跟分组的表
统计出每个出版社卖的最便宜的书的价格 出版社的名字 价格
models.Publish.objects.annotate(price_min=Min('book__price')).values('name','price_min')
统计不止一个作者的图书的书名和作者个数
models.Book.objects.annotate(author_count=Count('authors__id')).filter(author_count__gt=1).values('title','author_count')
F与Q查询
F和Q查询也需要导入模块
from django.db.models import F,Q
查询库存数大于卖出数的书籍
models.Book.objects.filter(stock__gt=F('sale')).values('title')
所有书的价格上涨100块
models.Book.objects.all().update(price=F('price')+10)
将所有书的名称后面全部加上 "爆款" 后缀 操作字符串数据需要借助于Concat方法
from django.db.models.functions import Concat
from django.db.models import Value
res = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
Q查询
Q包裹之后如果是逗号,那么还是and关系
如果使用 | ,那么是or关系
~就是not关系
查询书籍名称是阿Q正传 或者 作者手机号是111的书籍
models.Book.objects.filter(Q(title='阿Q正传')|Q(authors__author_detail__phone='111')).values('title')
Q对象高级用法
q = Q()
q.connector = 'or' # 默认是and 可以改成or
涉及知识点
通过模型表建表
- create方法
book_obj = models.Books.objects.create(
title='假如给我三天光明',price='99',publish_date = datetime.datetime.now()
)
- 利用对象的绑定方法
book_obj = models.Books(
title='鲁滨逊漂流记',price='77',publish_date = '2011-1-1'
)
book_obj.save()
通过模型表修改数据
res = models.Books.objects.filter(pk=1)
#pk会自动识别当前标的主键字段,可以使用pk指代主键字段
filter查询出来的结果是一个Queryset对象
1.只要是queryset对象就可以一直调用queryset的方法
2.只要是queryset对象,就可以通过 . query查看当前结果内部对应的sql语句
方式一:利用queryset方法
models.Books.objects.filter(pk=1).update(price=444)
方式二:通过对象的绑定方法
book_obj = models.Books.objects.get(pk=1)
book_obj.price = 222
book_obj.save()
get和filter区别
1.filter获取到的是一个queryset对象 类似于一个列表
2.get获取到的直接就是数据对象本身
当条件不存在的情况下
使用filter不报错直接返回一个空
使用get直接报错
删除数据
方式一:利用queryset方法 delete()
models.Books.objects.filter(pk=3).delete()
方式二:通过对象的绑定方法
book_obj = models.Books.objects.get(pk=3)
book_obj.delete()
MySQL中的模糊查询
关键字 like
模糊匹配的符号
%:匹配任何个数的任意字符
_:匹配一位任意的字符
聚合函数
mysql中聚合函数必须用在分组之后,如果没有分组,默认整体就是一组
聚合函数:Max(), Min(), Sum(), Avg(), Count()
级联更新,级联删除
操作外键字段管理数据的时候,书跟出版社是一对多关系
如果要删除的数据所在的表里有外键字段,此时删除该表中字段,会把外键对应的数据也一同删除
如果是修改数据,则外键关联的表中数据,也会一同修改