django周复习二
1,模型层:
1单表操作:
13个必会操作总结
返回QuerySet对象的方法有
all()
filter()
exclude()
order_by()
reverse()
distinct()
特殊的QuerySet
values() 返回一个可迭代的字典序列
values_list() 返回一个可迭代的元祖序列
返回具体对象的
get()
first()
last()
返回布尔值的方法有:
exists()
返回数字的方法有
count()
1,模型层:
1单表操作:
13个必会操作总结
返回QuerySet对象的方法有
all()
filter()
exclude()
order_by()
reverse()
distinct()
特殊的QuerySet
values() 返回一个可迭代的字典序列
values_list() 返回一个可迭代的元祖序列
返回具体对象的
get()
first()
last()
返回布尔值的方法有:
exists()
返回数字的方法有
count()
增
# 方式1: create
# book_obj = models.Book.objects.create(title='三国',price=19.99,create_time='2019-11-11')
# print(book_obj.title)
# 方式2:对象点save()方法 效率极低,因为每执行一次,相当于从数据库从头到尾执行一遍
# from datetime import datetime
# ctime = datetime.now()
# book_obj = models.Book(title='西游记',price=96.66,create_time=ctime)
# book_obj.save()
# 方式1: create
# book_obj = models.Book.objects.create(title='三国',price=19.99,create_time='2019-11-11')
# print(book_obj.title)
# 方式2:对象点save()方法 效率极低,因为每执行一次,相当于从数据库从头到尾执行一遍
# from datetime import datetime
# ctime = datetime.now()
# book_obj = models.Book(title='西游记',price=96.66,create_time=ctime)
# book_obj.save()
查
# print(models.Book.objects.all())
# print(models.Book.objects.get(id=1))
# print(models.Book.objects.get(pk=1))
"""
pk会自动查找到当前数据的主键字段
"""
# print(models.Book.objects.filter(pk=2))
# print(models.Book.objects.all())
# print(models.Book.objects.get(id=1))
# print(models.Book.objects.get(pk=1))
"""
pk会自动查找到当前数据的主键字段
"""
# print(models.Book.objects.filter(pk=2))
改
# 1.update
# models.Book.objects.filter(pk=1).update(title='三国演义')
# 2.对象.save()
# book_obj = models.Book.objects.get(pk=1)
# book_obj.price = 666.66
# book_obj.save()
# 1.update
# models.Book.objects.filter(pk=1).update(title='三国演义')
# 2.对象.save()
# book_obj = models.Book.objects.get(pk=1)
# book_obj.price = 666.66
# book_obj.save()
删除 delete()
# models.Book.objects.filter(pk=2).delete()
# models.Book.objects.filter(pk=2).delete()
# < 1 > all(): 查询所有结果
# < 2 > filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
# < 3 > get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
# < 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
# print(models.Book.objects.exclude(pk=1)) # 只要pk不是1的数据全部查询出来
# < 3 > get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
# < 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
# print(models.Book.objects.exclude(pk=1)) # 只要pk不是1的数据全部查询出来
# < 5 > order_by(*field): 对查询结果排序('-id') / ('price')
# print(models.Book.objects.order_by('price')) # 默认是升序
# print(models.Book.objects.order_by('-price')) # 加负号就是降序
# < 6 > reverse(): 对查询结果反向排序 >> > 前面要先有排序才能反向
# print(models.Book.objects.order_by('price').reverse())
# < 7 > count(): 返回数据库中匹配查询(QuerySet)
# print(models.Book.objects.count()) # 对查询出来的结果进行一个计数
# print(models.Book.objects.count()) # 对查询出来的结果进行一个计数
# 的对象数量。
# < 8 > first(): 返回第一条记录
# print(models.Book.objects.filter(pk=1).first())
# < 9 > last(): 返回最后一条记录
# print(models.Book.objects.all())
# print(models.Book.objects.all().last())
# < 10 > exists(): 如果QuerySet包含数据,就返回True,否则返回False
# print(models.Book.objects.filter(pk=1000))
# print(models.Book.objects.filter(pk=1000).exists())
# print(models.Book.objects.filter(pk=1000))
# print(models.Book.objects.filter(pk=1000).exists())
# < 11 > values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
# model的实例化对象,而是一个可迭代的字典序列
# print(models.Book.objects.values('title','price')) # 得到的结果是列表套字典
# < 12 > values_list(*field): 它与values()
# print(models.Book.objects.values_list('title','price')) # 得到的结果是列表套元组
# print(models.Book.objects.values_list('title','price')) # 得到的结果是列表套元组
# 非常相似,它返回的是一个元组序列,values返回的是一个字典序列
# < 13 > distinct(): 从返回结果中剔除重复纪录
"""
去重的前提是 一定要有完全重复的数据 才能去重
"""
# print(models.Book.objects.filter(title='三国演义').distinct())
# print(models.Book.objects.values('title','price','create_time').distinct())
2,神奇的双下划线查询
字段__
__gt 大于
__lt 小于
__gte 大于等于
__lte 小于等于
__in[] 在不在里面
__range() 在不在某范围,两边都包含
__contains='p' 判断是否含有p 只能判断小写
__icontains='p' 判断是否含有p 忽略大小写
__startswith='三' 判断是否以三开头
__endswith='p' 判断是否以p结尾
__year='2017' 查看2017年的
models.Book.objects.filter(price__gte=200) 大于等于
models.Book.objects.filter(price__lte=200) 小于等于
models.Book.objects.filter(price__in=[200,300,666.66]) 查询价格要么是200,要么是300,要么是666.66
models.Book.objects.filter(price__range=(200,800)) # 两边都包含 查询价格在200到800之间的
models.Book.objects.filter(title__contains='p') # 仅仅只能拿小写p 查询书籍名字中包含p的
models.Book.objects.filter(title__icontains='p') # 忽略大小写
models.Book.objects.filter(title__startswith='三') 查询书籍是以三开头的
models.Book.objects.filter(title__endswith='p')
models.Book.objects.filter(create_time__year='2017') 查询出版日期是2017的年(******)
3,多表操作
一对多:ForeignKey
一对一:OnoToOneField 可以用ForeignKey代替ForeignKey(unique=True)
上面两个关键字所创建出来的字段会自动加上_id后缀
多对多:ManyToManyFiled
该字段并不会真正的在表中展示出来 它仅仅是一个虚拟字段
1.告诉orm自动创建第三张表
2.帮助orm跨表查询
2.一对多增删改查:
publish_id传数字
models.Book.objects.create(title='三国演义',price=189.99,publish_id=1)
publish直接传出版社对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦',price=999.99,publish=publish_obj)
改
传数字的
models.Book.objects.filter(pk=1).update(publish_id=3)
传对象的
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
删
models.Publish.objects.filter(pk=2).delete() # 默认都是级联更新 级联删除
3,多对多字段的增删改查
add() 增 传数字,对象
set() 改 传数字,对象 ,必须是可迭代对象
remove() 删 传数字,对象
以上可以传多个
clear() 删所有 括号内不要传参数
# 增
add()
1,add括号中传数字
# 主键为6的书籍增加一个作者
book_obj = models.Book.objects.filter(pk=6).first()
print(book_obj.authors) 此时为None,就是跳到了第三张表
#对象点击多对多虚拟字段时,会直接多对多的第三张表
#此时book_obj.authors就是直接跨到第三张表
book_obj.authors.add(1) # 此时就是给id为6的书籍添加一个作者
book_obj.authors.add(2,3)
# add括号中既可以传一个数字,又可以传多个数字
# 括号中一个数字,此时就是给id为6的书籍添加一个作者,
# 所以括号中有几个数字,就是添加几个作者,数字表示的是作者的id号
2,add括号中传对象
增加一条
book_obj = models.Book.objects.filter(pk=4).first()
aut_obj = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(aut_obj)
增加多条
book_obj = models.Book.objects.filter(pk=5).first()
book_obj1= models.Book.objects.filter(pk=5).first()
aut_obj = models.Author.objects.filter(pk=2).first()
aut_obj1= models.Author.objects.filter(pk=1).first()
aut_obj2 = models.Author.objects.filter(pk=9).first()
book_obj.authors.add(aut_obj,aut_obj1,aut_obj2)
book_obj1.authors.add(aut_obj1)
总结:
add是给书籍添加作者 括号内既可以传数字也可以传作者对象
并且支持一次性传多个 逗号隔开就可以
注意 :对象点虚拟字段就是跳到了第三张表
改:
将主键为5的书籍对象 作者修改为2,3
set()
括号中以列表的形式,是可迭代对象才可以传一个参数也要以列表的形式
1,传数字,
book_obj = models.Book.objects.filter(pk=5).first()
book_obj.authors.set([5,]) 传一个参数
book_obj.authors.set([2,3]) 传多个参数
本质就是修改,有点类似于删除,把不要的删除,把要的留下来
2,传作者对象
aut_obj = models.Author.objects.filter(pk=2).first()
aut_obj1= models.Author.objects.filter(pk=1).first()
aut_obj2 = models.Author.objects.filter(pk=9).first()
book_obj.authors.set([aut_obj,aut_obj1,aut_obj2])
总结:
set()括号内 需要传一个可迭代对象
可迭代对象 可以是多个数字组合
也可以是多个对象组合
但是不能混在一起使用,即不能既有数字,又有对象!!!
要么纯数字,要么纯对象
删:
remove()
1,传数字
book_obj = models.Book.objects.filter(pk=5).first()
book_obj.authors.remove(3)
2,传对象
aut_obj = models.Author.objects.filter(pk=2).first()
aut_obj1= models.Author.objects.filter(pk=1).first()
aut_obj2 = models.Author.objects.filter(pk=9).first()
book_obj.authors.remove(aut_obj)
book_obj.authors.remove(aut_obj,aut_obj1,aut_obj2)
总结:
remove()括号内既可以传数字 也可以传对象
并且支持传多个,逗号隔开即可
将某本书和作者的关系全部清空,用clear()
即清空当前这个作者与书籍的关系
book_obj = models.Book.objects.filter(pk=5).first()
book_obj.authors.clear()
跨表查询:
正向与反向的概念
# 一对一
# 正向:author---关联字段在author表里--->authordetail 按字段
# 反向:authordetail---关联字段在author表里--->author 按表名小写
# 一对多
# 正向:book---关联字段在book表里--->publish 按字段
# 反向:publish---关联字段在book表里--->book 按表名小写_set.all() 因为一个出版社对应着多个图书
# 多对多
# 正向:book---关联字段在book表里--->author 按字段
# 反向:author---关联字段在book表里--->book 按表名小写_set.all() 因为一个作者对应着多个图书
正向查询按外键字段
反向查询按表名小写
基于对象的跨表查询(子查询:将一张表的查询结果当做另外一个查询语句的条件)
强调:在书写orm语句的时候 跟写sql语句一样
不要尝试着 一次性写完 应该做到写一点看一点再一点
1,如果外键字段在你当前这张表中,那么如果由你当前这张表向另一张表查询就是正向
关系字段在你当前这张表,由你这张表去查,正向
关系字段不在你当前这张表,由你这张表去查,反向
正向查询按外键字段
反向查询按表名小写
# 基于对象的跨表查询(子查询:将一张表的查询结果当做另外一个查询语句的条件)
#查询书籍为4的出版社名称
book_obj = models.Book.objects.filter(pk=4).first()
print(book_obj.publish.name)
print(book_obj.publish.addr)
# 查询书籍id是5的作者姓名
book_obj = models.Book.objects.filter(pk=5).first()
print(book_obj.authors) # app01.Author.None
#书籍有多个作者,所以拿到为None
print(book_obj.authors.all()) 拿到的是对象,
当你外键字段对应的值有多个的时候就用all(),为一个的时候就不用all()
# 查询作者是jason的家庭住址
auth_obj = models.Author.objects.filter(name='jason').first()
print(auth_obj.author_detail.addr)
反向查询:
# 查询出版社是东方出版社出版的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
print(publish_obj.book_set.all())
# 查询作者是jason写过的所有书籍
# auth_obj = models.Author.objects.filter(name='jason').first()
# print(auth_obj.book_set)
# print(auth_obj.book_set.all())
# 查询作者号码是120的作者姓名
auth_obj = models.AuthorDetail.objects.filter(phone=120).first()
print(auth_obj.author.name)
print(auth_obj.author.age)
总结:
反向查询,当你反向查询的结果是多个的时候就需要加 _set
当你反向查询的结果是一个时就不需要加_set
即表名小写即可
跨表查询:可以连续的查询
# 基于双下划綫的跨表查询(连表查询)
models.Book.objects.filter().values('publish__name')
models.Publish.objects.filter(book__title='三').values('name')
models.Book.objects.filter().values('authors__author_detail__phone')
# 只要表中有外键字段 你可以通过__无限制的跨表
F与Q
F查询
从数据库中获取字段对应的数据
库存数大于卖出数
Q查询
与
filter(Q(),Q())
filter(Q()&Q())
或
filter(Q()|Q())
非
filter(~Q())
补充
q = Q()
q.connector = 'or'
q.children.append(('title','三'))
q.children.append(('price',666))
models.Book.objects.filter(q)
2,常见字段
AutoField() int primary key auto_increment
CharField() varchar()
IntegerField() int()
big....
EmailField() varchar(254)
DateField() date
DateTimeField() datetime
auto_now:每次修改数据都会更新时间
auto_now_add:只在第一次创建数据的时候才会更新一次
BooleanField(Field)
is_delete = BooleanField()
给该字段传值的时候 你只需要传布尔值即可
但是对应到数据库 它存的是0和1
TextField(Field)
- 文本类型
用来存大段文本
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 用户上传的文件会自动放到等号后面指定的文件路径中
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
自定义char字段
class MyChar(models.Field):
def __init__(self,max_length,*args,**kwargs):
self.max_length = max_length
super().__init__(max_length=max_length,*args,**kwargs)
关系字段不在你当前这张表,由你这张表去查,反向
正向查询按外键字段
反向查询按表名小写
# 基于对象的跨表查询(子查询:将一张表的查询结果当做另外一个查询语句的条件)
#查询书籍为4的出版社名称
book_obj = models.Book.objects.filter(pk=4).first()
print(book_obj.publish.name)
print(book_obj.publish.addr)
# 查询书籍id是5的作者姓名
book_obj = models.Book.objects.filter(pk=5).first()
print(book_obj.authors) # app01.Author.None
#书籍有多个作者,所以拿到为None
print(book_obj.authors.all()) 拿到的是对象,
当你外键字段对应的值有多个的时候就用all(),为一个的时候就不用all()
# 查询作者是jason的家庭住址
auth_obj = models.Author.objects.filter(name='jason').first()
print(auth_obj.author_detail.addr)
反向查询:
# 查询出版社是东方出版社出版的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
print(publish_obj.book_set.all())
# 查询作者是jason写过的所有书籍
# auth_obj = models.Author.objects.filter(name='jason').first()
# print(auth_obj.book_set)
# print(auth_obj.book_set.all())
# 查询作者号码是120的作者姓名
auth_obj = models.AuthorDetail.objects.filter(phone=120).first()
print(auth_obj.author.name)
print(auth_obj.author.age)
总结:
反向查询,当你反向查询的结果是多个的时候就需要加 _set
当你反向查询的结果是一个时就不需要加_set
即表名小写即可
跨表查询:可以连续的查询
# 基于双下划綫的跨表查询(连表查询)
models.Book.objects.filter().values('publish__name')
models.Publish.objects.filter(book__title='三').values('name')
models.Book.objects.filter().values('authors__author_detail__phone')
# 只要表中有外键字段 你可以通过__无限制的跨表
F与Q
F查询
从数据库中获取字段对应的数据
库存数大于卖出数
Q查询
与
filter(Q(),Q())
filter(Q()&Q())
或
filter(Q()|Q())
非
filter(~Q())
补充
q = Q()
q.connector = 'or'
q.children.append(('title','三'))
q.children.append(('price',666))
models.Book.objects.filter(q)
2,常见字段
AutoField() int primary key auto_increment
CharField() varchar()
IntegerField() int()
big....
EmailField() varchar(254)
DateField() date
DateTimeField() datetime
auto_now:每次修改数据都会更新时间
auto_now_add:只在第一次创建数据的时候才会更新一次
BooleanField(Field)
is_delete = BooleanField()
给该字段传值的时候 你只需要传布尔值即可
但是对应到数据库 它存的是0和1
TextField(Field)
- 文本类型
用来存大段文本
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 用户上传的文件会自动放到等号后面指定的文件路径中
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
自定义char字段
class MyChar(models.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
return 'char(%s)'%self.max_length
外键字段
当你在使用django2.X版本的时候 在建立外键关系时(*****)
需要你手动添加几个关键点参数
models.cascade
db_constraints
当你在使用django2.X版本的时候 在建立外键关系时(*****)
需要你手动添加几个关键点参数
models.cascade
db_constraints
3,数据库查询优化
only与defer
select_releated与prefect_releated
"""数据库查询优化"""
# orm内所有的语句操作 都是惰性查询:只会在你真正需要数据的时候才会走数据库,如果你单单只写orm语句时不会走数据库的
# 这样设计的好处 在于 减轻数据库的压力
# res = models.Book.objects.only('title')
# # print(res)
# for r in res:
# # print(r.title) # 只走一次数据库查询
# print(r.price) # 当你点击一个不是only括号内指定的字段的时候 不会报错 而是会频繁的走数据库查询
only与defer
select_releated与prefect_releated
"""数据库查询优化"""
# orm内所有的语句操作 都是惰性查询:只会在你真正需要数据的时候才会走数据库,如果你单单只写orm语句时不会走数据库的
# 这样设计的好处 在于 减轻数据库的压力
# res = models.Book.objects.only('title')
# # print(res)
# for r in res:
# # print(r.title) # 只走一次数据库查询
# print(r.price) # 当你点击一个不是only括号内指定的字段的时候 不会报错 而是会频繁的走数据库查询
# res1 = models.Book.objects.defer('title') # defer与only是相反的
# for r in res1: # defer会将不是括号内的所有的字段信息 全部查询出来封装对象中
# # 一旦你点击了括号内的字段 那么会频繁的走数据库查询
# print(r.price)
# for r in res1: # defer会将不是括号内的所有的字段信息 全部查询出来封装对象中
# # 一旦你点击了括号内的字段 那么会频繁的走数据库查询
# print(r.price)
# select_related与prefetch_related
# select_related帮你直接连表操作 查询数据 括号内只能放外键字段
# res = models.Book.objects.all().select_related('publish')
# for r in res:
# print(r.publish.name)
# res = models.Book.objects.all().select_related('publish__xxx__yyy__ttt')
# print(res)
# res = models.Book.objects.all()
"""
select_related:会将括号内外键字段所关联的那张表 直接全部拿过来(可以一次性拿多张表)跟当前表拼接操作
从而降低你跨表查询 数据库的压力
注意select_related括号只能放外键字段(一对一和一对多)
res = models.Book.objects.all().select_related('外键字段1__外键字段2__外键字段3__外键字段4')
"""
# prefetch_related 不主动连表
res = models.Book.objects.prefetch_related('publish')
"""
不主动连表操作(但是内部给你的感觉像是连表操作了) 而是将book表中的publish全部拿出来 在取publish表中将id对应的所有的数据取出
res = models.Book.objects.prefetch_related('publish')
括号内有几个外键字段 就会走几次数据库查询操作
"""
for r in res:
print(r.publish.name)
# select_related帮你直接连表操作 查询数据 括号内只能放外键字段
# res = models.Book.objects.all().select_related('publish')
# for r in res:
# print(r.publish.name)
# res = models.Book.objects.all().select_related('publish__xxx__yyy__ttt')
# print(res)
# res = models.Book.objects.all()
"""
select_related:会将括号内外键字段所关联的那张表 直接全部拿过来(可以一次性拿多张表)跟当前表拼接操作
从而降低你跨表查询 数据库的压力
注意select_related括号只能放外键字段(一对一和一对多)
res = models.Book.objects.all().select_related('外键字段1__外键字段2__外键字段3__外键字段4')
"""
# prefetch_related 不主动连表
res = models.Book.objects.prefetch_related('publish')
"""
不主动连表操作(但是内部给你的感觉像是连表操作了) 而是将book表中的publish全部拿出来 在取publish表中将id对应的所有的数据取出
res = models.Book.objects.prefetch_related('publish')
括号内有几个外键字段 就会走几次数据库查询操作
"""
for r in res:
print(r.publish.name)
4,事务
ACID
原子性
一致性
隔离性
持久性
from django.db import transaction
ACID
原子性
一致性
隔离性
持久性
from django.db import transaction
with transaction.atomic():
"""数据库操作
在该代码块中书写的操作 同属于一个事务
"""
models.Book.objects.create()
models.Publish.objects.create()
# 添加书籍和出版社 就是同一个事务 要么一起成功要么一起失败
print('出了 代码块 事务就结束')
"""数据库操作
在该代码块中书写的操作 同属于一个事务
"""
models.Book.objects.create()
models.Publish.objects.create()
# 添加书籍和出版社 就是同一个事务 要么一起成功要么一起失败
print('出了 代码块 事务就结束')
5,数据库连接:
1,在settings.py 文件中进行更改,添加
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'day56',
'HOST':'127.0.0.1',
'USER':'root',
'PORT':3306,
'PASSWORD':'123',
'CHARSET':'utf8'
}
}
2.在应用或者项目文件夹下的__init__文件中添加:
import pymysql
pymysql.install_as_MySQLdb()
3,orm对象关系映射
表 类
一条条记录 对象
记录中的字段 对象.属性
首先需要在应用下的models.py中书写模型类
class User(models.Model):
# 将id字段设置为User表主键字段 在django orm中 你可以不写主键字典 django会默认给你的表创建一个名为id的主键字段
# id = models.AutoField(primary_key=True) # 一旦你自己指定了主键字段 那么django就不会自动再帮你创建了
username = models.CharField(max_length=32) # username varchar(32) CharField必须要指定max_length参数
password = models.IntegerField() # password int
*************************需要执行数据库迁移(同步)命令******************************
python3 manage.py makemigrations # 仅仅是在小本本上(migrations文件夹)记录数据库的修改 并不会直接操作数据
python3 manage.py migrate # 将数据库修改记录 真正同步到数据库
注意:只要动了models中跟数据库相关的代码 就必须重新执行上面的两条命令 缺一不可(******)