模型层
ORM查询
如何配置测试脚本
第一种:
直接在某一个应用下的tests文件中书写下面内容,然后自己写两行
#当你想单独测试django中某个py文件,需要手动配置测试监本
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
import django
django.setup()
#一定要等待测试脚本搭建完毕之后,才能导入django文件进行测试
from app01 import models
第二种
直接新建一个任意名称的py文件,在里面写上配置
#当你想单独测试django中某个py文件,需要手动配置测试监本
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
import django
django.setup()
#一定要等待测试脚本搭建完毕之后,才能导入django文件进行测试
from app01 import models
如果想查看QuerySet里的SQL语句,在settings里面加上
"""
如果你想查看所有的orm语句内部对应的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',
},
}
}
1.单表操作
创建一张表
class Books(models.Model):
title=models.CharField(max_length=32)
price=models.DecimalField(max_digits=8,decimal_places=2)
publish_data=models.DateField()
创建数据
1.create方法
book_obj=models.Books.objects.create(title='西游记',price=123.23,publish_data='2019-12-12')
print(book_obj)
from datetime import date
ctime=date.today()
book_obj=models.Books.objects.create(title='红楼梦',price=888,publish_data=ctime)
2.利用对象的绑定方法
book_obj=models.Books(title='水浒传',price=56.33,publish_data='2000-1-21')
book_obj.save()
修改数据
res=models.Books.objects.filter(pk=2)
print(res)
print(res.query) # SELECT `app01_books`.`id`, `app01_books`.`title`, `app01_books`.`price`, `app01_books`.`publish_data` FROM `app01_books` WHERE `app01_books`.`id` = 2
'''
pk会自动帮你查找到当前表的主键字段,后期会用pk来指代主键字段
filter查询出来的结果是QuerySet对象
1.只要是QuerySet对象就可以无限制的调用QuerySet的方法
例如:fileter create delete
res=models.Books.objects.filter(pk=2).filter().filter()
2.只要是QuerySet对象就可以点query查看当前结果内部对应的sql语句'''
#方式1:利用QuerySet方法
models.Books.objects.filter(pk=2).update(price=333)
#方式2:利用对象
book_obj=models.Books.objects.get(pk=2)#该方法不推荐使用,推荐使用queryset方法
book_obj.price=2222
book_obj.save()
#利用对象的修改,内部其实是重头到尾将数据的所有字段都重写了一遍
'''
get和filter区别
1.filter获取的是一个QuerySet对象,类似于一个列表
2.get获取的是数据对象本身
当条件不存在的情况下:
filter不报错,直接返回一个空,推荐使用filter
get会直接报错,所有不推荐使用'''
删除数据
#1.利用QuerySet方法 delete()
models.Books.objects.filter(pk=3).delete()
#2.对象方法
book_obj=models.Books.objects.get(pk=2)
book_obj.delete()
查数据 必知必会13条
1.all() 查询所有 返回queryset对象
res=models.Books.objects.all()
print(res)
'''
orm语句的查询默认都是惰性查询
只有真正使用数据的时候才会执行orm语句''
2.filter() 筛选 返回的是queryset对象
# 相当于你原生SQL语句里面的where关键字
res=models.Books.objects.filter(pk=5)#支持多个参数,并且是and关系
print(res)
##### 3.get() 筛选 获取的数据对象本身
# 条件不存在直接报错 并且查询条件必须是唯一的
res=models.Books.objects.get(pk=4)
print(res)
4.first() 取queryset中第一个数据对象
res=models.Books.objects.filter(pk=4).first()
print(res)
##### 5.last() 取queryset中最后一个数据对象
res=models.Books.objects.filter(title='西游记').last()
print(res)
6.count()统计数据的个数 返回数字
num=models.Books.objects.count()
print(num)
7.values() 获取数据对象中指定的字段的值 queryset 列表套字典
#可以拿多个 res=models.Books.objects.values('title','price')
print(res)
8.values_list() 获取数据对象中指定的字段的值 queryset 列表套元组
# 可以拿多个
res=models.Books.objects.values_list('title','price') res=models.Books.objects.filter(pk=5).values_list('title','price')
print(res)
9.order_by() 指定字段排序 返回queryset
res=models.Books.objects.order_by('price')#默认是升序
res=models.Books.objects.all().order_by('price') #等价 语义更明确
res = models.Books.objects.order_by('-price')#加负号 降序
print(res)
10.reverse() 颠倒顺序 返回queryset
# 前提是颠倒的对象必须有顺序(提前排序之后才能颠倒)
res = models.Books.objects.all().order_by('price')
res=res.reverse()
print(res)
11.exclude() 排除什么什么之外 返回queryset
res=models.Books.objects.all().exclude(title='西游记')
print(res)
12.exists() 判断查询结果是否有值 返回结果是一个布尔值
res=models.Books.objects.filter(pk=5).exists()
print(res)
# 该方法其实不需要使用,因为数据本身自带布尔值
13.distinct() 查询结果进行去重操作 返回queryset
# 前提:数据必须是要完全相同的情况下 才能去重(容易忽略主键)
res=models.Books.objects.values_list('title','price').distinct()
print(res)
2.神奇的双下划线查询
#查询价格大于500的书籍
res=models.Books.objects.filter(price__gt=500)
#查询价格小于500的书籍
res=models.Books.objects.filter(price__lt=500)
#查询价格大于等于500的书籍
res=models.Books.objects.filter(price__gte=500)
#查询价格小于等于500的书籍
res=models.Books.objects.filter(price__lte=500)
#查询价格是222或者444或者500的书籍
res=models.Books.objects.filter(price__in=[222,444,500])
#查询价格在200到800之间的书籍
res=models.Books.objects.filter(price__range=(200,800))
#查询出版日期是2019年的书籍
res=models.Books.objects.filter(publish_data__year='2019')
#查询出版日期是1月份的书籍
res=models.Books.objects.filter(publish_data__month='1')
# 模糊查询
'''
mysql中的模糊查询
关键字 like
模糊匹配的符号
%:匹配任何个数的任意字符
_:匹配以为任意字符'''
#查看书籍是以西开头的书
res=models.Books.objects.filter(title__startswith='西')
#查询书籍是以记结尾的书
res=models.Books.objects.filter(title__endswith='记')
#查询书籍名称中包含游字的书籍
res=models.Books.objects.filter(title__contains='游')
#查询书籍名称包含字母p的书籍
res=models.Books.objects.filter(title__contains='p')#默认区分大小写
res=models.Books.objects.filter(title__icontains='p')#忽略区分大小写
3.图书管理系统表设计
class Book(models.Model):
title=models.CharField(max_length=32)
price=models.DecimalField(max_digits=8,decimal_places=2)
publish_data=models.DateField(auto_now_add=True)
'''
auto_now:每次修改数据的时候,都会更新修改数据时间(展示最新的依次修改时间)
auto_now_add:当数据创建出来的时候,会自动将创建时间记录下来
'''
publish=models.ForeignKey(to='Pbulish')
author=models.ManyToManyField(to='Author')
class Pbulish(models.Model):
name=models.CharField(max_length=32)
addr=models.CharField(max_length=64)
def __str__(self):
return self.name
class Author(models.Model):
name=models.CharField(max_length=64)
email=models.EmailField()#对应到数据库中仅仅是varchar(254),没有任何限制条件,该字段只要是字符串就行
#仅仅是为了表达语义,如何限制:后期需要借助于校验性组件
author_detail=models.OneToOneField(to='AuthorDetail')
def __str__(self):
return self.name
class AuthorDetail(models.Model):
phone=models.BigIntegerField()
addr=models.CharField(max_length=64)
def __str__(self):
return self.addr
4.外键字段(一对多)的增删改查
增
#第一种
models.Book.objects.create(title='西游记',price=233,publish_id=1)
# 直接传表里面的实际字段,跟数据主键值 publish_id
#第二种
publish_obj=models.Pbulish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦',price=555,publish=publish_obj)
# 传虚拟字段 跟数据对象即可
改
#第一种
models.Book.objects.filter(pk=1).update(publish_id=2)
#第二种
publish_obj=models.Pbulish.objects.filter(pk=1).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)
删除
#默认就是级联产出,级联更新
models.Pbulish.objects.filter(pk=1).delete()
5.外键字段(多对多)的增删改查
增
book_obj=models.Book.objects.filter(pk=3).first()
print(book_obj.publish)#点外键字段,可能会直接获取到外键关联的数据对象
#给当前这本书绑定作者
print(book_obj.author)#已经跨到第三张表
book_obj.author.add(2)#在第三种表里面给书籍绑定一个主键为2的作者
author_obj=models.Author.objects.filter(pk=1).first()
author_obj1=models.Author.objects.filter(pk=2).first()
book_obj.author.add(author_obj)
book_obj.author.add(author_obj,author_obj1)
'''
add方法 能够朝第三张关系表添加数据
既支持传数字:add(1,2)
也支持传对象:add(author_obj,author_obj1)
并且两者都可以传多个'''
改
book_obj=models.Book.objects.filter(pk=3).first()
book_obj.author.set((1,3))
book_obj.author.set([1,])
author_obj=models.Author.objects.filter(pk=1).first()
author_obj1=models.Author.objects.filter(pk=2).first()
book_obj.author.set((author_obj,author_obj1))
'''
set修改多对多关系表中的数据
既可以传数字也可以传对象
但是需要注意的是括号内必须是可迭代对象
都支持多个
set((1,3))
set((author_obj,author_obj1))'''
删
book_obj=models.Book.objects.filter(pk=3).first()
book_obj.author.remove(1,2)
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1=models.Author.objects.filter(pk=2).first()
book_obj.author.remove(author_obj)
book_obj.author.remove(author_obj,author_obj1)
'''
remove既可以传数字,也可以传对象
并且都支持多个,不需要迭代
remove(1,2)
remove(author_obj,author_obj1)'''
清空 删除某个数据在第三张表中的所有记录
book_obj=models.Book.objects.filter(pk=4).first()
book_obj.author.clear()
'''
clear清空书籍相关所有记录,括号内不需要传递参数'''
6.跨表查询、
正反向查询:
关系字段在谁那,由谁查,谁就是正向
如果关系字段不在,就是反向
正向查询按字段,反向查询按表名小写+_set
基于对象的跨表查询 子查询 分布操作
# 1.查询书籍主键为3的出版社名称
book_obj=models.Book.objects.filter(pk=3).first()
print(book_obj.publish)
print(book_obj.publish.name)
#2.查询书籍主键为3的作者姓名
book_obj=models.Book.objects.filter(pk=3).first()
print(book_obj.author)
print(book_obj.author.all())
# print(book_obj.author.all().first().name)
#3.查询作者是Jason的手机号码
author_obj=models.Author.objects.filter(name='json').first()
print(author_obj.author_detail)
print(author_obj.author_detail.phone)
'''
什么时候需要加all:
当正向查询点击外键字段数据有多个的情况下 需要,all()
app01.Author.None 一旦看到该结果 只需要加.all()即可'''
#4查询出版社是东方出版社出版过的书籍
publish_obj=models.Pbulish.objects.filter(name='西方出版社').first()
print(publish_obj.book_set)
print(publish_obj.book_set.all())
#5.查询作者是Jason写过的书籍
author_obj=models.Author.objects.filter(name='json').first()
print(author_obj.book_set)
print(author_obj.book_set.all())
#6.查询手机号是1210的作者姓名
author_detail_obj=models.AuthorDetail.objects.filter(phone=110110).first()
print(author_detail_obj.author)
'''
什么时候反向查询表名小写需要加_set
一对多 多对多
一对一不需要加_set'''
基于双下划线的跨表查询 联表操作
#1.查询书籍pk为3的出版社名称
#正向:
res=models.Book.objects.filter(pk=3).values('publish__name')
#写外键字段就相当于已经跨到外键字段所关联的表
#想要改表里的那个字段信息,只需加__获取即可
#models后面点谁,谁就是基表
print(res)
res=models.Pbulish.objects.filter(book__pk=3).values('name')
print(res)
#2.查询书籍pk为3的作者姓名和邮箱
#正向
res=models.Book.objects.filter(pk=3).values('author__name','author__email')
print(res)
#反向
res=models.Author.objects.filter(book__pk=3).values('name','email')
print(res)
#3.查询作者是json的家庭地址
#正向
res=models.Author.objects.filter(name='json').values('author_detail__addr')
print(res)
#反向
res=models.AuthorDetail.objects.filter(author__name='json').values('addr')
print(res)
#4.查询出版社是西方出版社初设过得书的名字
#反向
res=models.Pbulish.objects.filter(name='西方出版社').values('book__title')
print(res)
#正向
res=models.Book.objects.filter(publish__name='西方出版社').values('title')
print(res)
#5.查询书籍pk是3的作者的手机号
res=models.Book.objects.filter(pk=3).values('author__author_detail__phone')
print(res)
res=models.Author.objects.filter(book__pk=3).values('author_detail__phone')
print(res)