Django模型层1
Django模型层
一、如何配置测试脚本
-
直接在某一个应用下的tests文件中书写下面的内容:
# 搭建测试脚本,先去 manage.py 中copy下面的三行代码到test文件中 import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Books_Management_System.settings") # 下面自己写两行 import django django.setup() # 至此测试脚本搭建完毕 # 下面可以开始写测试代码 from app01 import models res = models.Book.objects.all() # 如果不写,会报错
-
直接新建一个任意名称的py文件,在里面写上面的配置。
二、单表操作
1. 创建数据
-
create方法
book_obj = models.Book.objects.create(title='大主宰',price=35.5,publisher_id=1)
-
利用对象的绑定方法save()
book_obj = models.Book(title='最初进化',price=666.6,publisher_id=1) book_obj.save()
2. 修改数据
-
update方法
先通过filter筛选出需要修改的对象。
filter选出的对象类型为queryset对象,可以无限制的调用queryset方法。
而且queryset对象可以通过‘对象.query’的方式查看操作内部对应的SQL语句。
models.Book.objects.filter(pk=8).update(publisher_id=3)
-
利用get获取到的对象的方法
book_obj =models.Book.objects.get(pk=9) print(book_obj) book_obj.publisher_id = 3 book_obj.save()
get和filter区别:
-
filter获取到的是一个queryset对象,类似于一个列表
-
get获取到的直接就是数据对象本身。
当条件不存在的情况下:
filter不报错直接返回一个空。推荐使用filter方法。
get直接报错。所以不推荐使用get方法。
3. 删除数据
-
利用queryset的delete方法
models.Book.objects.filter(pk=10).delete()
-
利用get获取到的对象的delete方法
book_obj = models.Book.objects.get(pk=9) book_obj.delete()
4. 查询数据(必知必会13条)
4.1 配置 终端打印所有SQL语句的方法
# settings 文件中 随便放下面的语句
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
4.2 必知必会13条
只可以直接用于queryset对象的方法。
-
all()
查询所有
返回queryset对象
res = models.Book.objects.all() print(res)
-
filter()
筛选,相当于原生sql语句的where关键字
返回queryset对象
res = models.Book.objects.filter(pk=2,title='王牌进化') print(res)
-
get()
获取数据对象本身,只能获取一个对象,并且查询条件必须是唯一的
res = models.Book.objects.get(title='最终进化') res1 = models.Book.objects.filter(title='最初进化') print(res,res1) # 最终进化 <QuerySet [<Book: 最初进化>]>
-
first()
取第一个数据对象
res = models.Book.objects.filter(title='最初进化').first() print(res)
-
last()
取最后一个数据对象
res = models.Book.objects.filter(title='最初进化').last() print(res)
-
count()
统计数据的个数,返回的是整形
num = models.Book.objects.count() print(num,type(num))
-
values()
获取数据对象中指定的字段的值,返回queryset列表套字典
res = models.Book.objects.values('title', 'price') print(res)
-
values_list()
获取数据对象中指定的字段的值,可以有多个,返回列表套元组,元祖中只有值。
res = models.Book.objects.values_list('title', 'price') print(res)
-
order_by()
所有数据按照指定字段排序,默认是升序。
如果字段名前面加负号就可以降序排列。
# 默认是升序 res = models.Book.objects.order_by('price') # 默认是升序,上下两者等价。下面的方式语义更明确 res1 = models.Book.objects.all().order_by('price') # 要降序,字段前面加负号 res2 = models.Book.objects.all().order_by('-price') print(res,res1,res2)
-
reverse()
颠倒顺序,前提是颠倒的对象必须有顺序。
也就是说必须提前排序之后才能颠倒。
res = models.Book.objects.all() print(res) res1 = models.Book.objects.all().reverse() print(res1) res2 = models.Book.objects.all().order_by('price') print(res2) res3 = models.Book.objects.all().order_by('price').reverse() print(res3)
-
exclude()
排除某一条记录,取反。
res = models.Book.objects.all().exclude(title='最初进化') print(res)
-
exists()
判断查询结果是否有值,返回结果是一个布尔值
res = models.Book.objects.filter(pk=11).exists() print(res)
-
distinct()
对查询结果进行去重,前提是数据必须完全相同,才能去重。id也会算在内。
res = models.Book.objects.values('title', 'price') res1 = models.Book.objects.values('title','price').distinct() print(res) print(res1)
三、神奇的双下划线查询
-
__gt:大于
# 查询价格大于50的书籍 res = models.Book.objects.filter(price__gt=50) print(res)
-
__lt:小于
# 查询价格小于40 的书籍 res = models.Book.objects.filter(price__lt=40) print(res)
-
__gte:大于等于
# 查询价格大于等于50 # 对数字精确度不敏感 res = models.Book.objects.filter(price__gte=222.2) res2 = models.Book.objects.filter(price__gte=50) print(res) print(res2)
-
__lte:小于等于
# 查询价格小于等于50的书籍 res = models.Book.objects.filter(price__lte=50) print(res)
-
__in=列表:或者,在列表中选择
# 查询价格是222.2或者66或者50的书籍 res = models.Book.objects.filter(price__in=[222.2,66,50]) print(res)
-
__range=元组:在元组的两个数之间,而且顾头顾尾
# 查询价格在200到800之间的书籍 res = models.Book.objects.filter(price__range=(200,800)) # 顾头顾尾 print(res)
-
__year:筛选年份
# 查询出版年份是2019年的书籍 res = models.Book.objects.filter(publish_date__year='2019') print(res)
-
__month:筛选月份
# 查询出版日期是11月份的书籍 res = models.Book.objects.filter(publish_date__month='11') print(res)
-
__day:筛选日期
# 查询出版日是1的书籍 res = models.Book.objects.filter(publish_date__day='27') print(res)
-
__startswith:以。。。开头
# 查询书籍是以王开头的书 res = models.Book.objects.filter(title__startswith='王') print(res)
-
__endswith:以。。。结尾
# 查询书籍是以化结尾的书 res = models.Book.objects.filter(title__endswith='化') print(res)
-
__contains:包含某个字符,区分大小写
# 查询书籍名称中包含主字的书籍 res = models.Book.objects.filter(title__contains='主') print(res)
-
__icontains:不包含某个字符,不区分大小写(ignore)
# 查询书籍名称中不包含字母进的书籍 res2 = models.Book.objects.filter(title__icontains='进') print(res2)
四、表设计特殊字段
1. DateField
年-月-日 格式的时间
- auto_now=True:每次修改数据的时候,都会自动更新修改数据(展示最新的一次修改数据)
- auto_now_add=True:当数据创建时,会自动将创建时间记录下来
2. DateTimeField
年-月-日-时-分-秒 格式的时间
五、外键字段(一对多)的增删改查
1. 增
-
实际真实字段,传数值
models.Book.objects.create(title='三国演义', price=222.33, publish_id=1)
-
类中你写的字段,直接放对象
publish_obj = models.Publisher.objects.filter(pk=2).first() models.Book.objects.create(title='红楼梦',price=444.33,publish=publish_obj)
2. 改
-
直接改实际字段
models.Book.objects.filter(pk=1).update(publish_id=2)
-
直接传对象
publish_obj = models.Publisher.objects.filter(pk=1).first() models.Book.objects.filter(pk=1).update(publish=publish_obj)
3. 删
特点:
级联删除,出版社删除,出版社对应的图书也被删除
models.Publisher.objects.filter(pk=1).delete()
六、外键字段(多对多)的增删改查
book_obj = models.Book.objects.filter(pk=2).first()
# 点外键字段 可能会直接获取到外键关联的数据对象
print(book_obj.publisher)
麻瓜式做法:自己直接去操作第三张表
1. 增
add():
通过obj.多对多外键字段.add()
增加第三张表的数据,既支持传数字,也支持传对象,并且都可以传多个。
print(book_obj.authors) # 已经跨到第三张表了
# 直接传值
book_obj.authors.add(4) # 在第三张表里面给书籍绑定一个主键为4的作者
book_obj.authors.add(1,2) # 在第三张表里添加多个作者
# 传对象
author_obj = models.Author.objects.filter(pk=12).first()
book_obj.authors.add(author_obj)
2. 改
set():
通过obj.多对多外键字段.set()
修改第三张表的数据,修改多对多关系表中的数据。
这里的改指的是重置,也就是先删再增。set括号内的参数为重置字段值后的数据。
同样支持传数字和对象,而且set括号内必须传可迭代对象:元组或列表。就算只有一个值,也必须要是一个列表或元组。(1,)
这样的才可以。传对象也是一样。
且都支持多个。
book_obj = models.Book.objects.filter(pk=2).first()
book_obj.authors.set((1,2))
book_obj.authors.set([1,])
# 或者先取出对象,在直接传对象
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))
3. 删
级联删除。
-
remove():既可以传参数,也可以传对象。也支持传多个参数,且传多个参数是时不需要传容器类参数。
# 删数值 book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.remove(1) book_obj.authors.remove(2,3) # book_obj.authors.remove(100) # 也不会报错 # 删对象 author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() book_obj.authors.remove(author_obj) book_obj.authors.remove(author_obj,author_obj1)
-
clear():清空。
删除某个对象在第三张表中的所有记录,括号内不需要传递参数。
book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.clear()
七、跨表查询
1. 正反向查询
关系字段(foreignkey)在谁那儿,由谁开始查就是正向。
如果关系字段不在谁那儿,由谁开始查就是反向。
1.1 正向查询
正向查询按字段.
1.2 反向查询
一对一按表名小写。
一对多或多对多按表名小写+_set
。
2. 子查询
基于对象的跨表层查询,分布操作。
# A表与B表为多对多的关系,外键在表A上
```正向查询```
# 先筛选出对象,在通过对象查询
a_obj = models.A.objects.filter()
# 通过 a_obj.b外键.b表中的要查询的字段 查询b中字段
print(a_obj.b.name)
```反向查询```
# 先筛选出对象,在通过对象查询
b_obj = models.B.objects.filter()
# 在通过“字段名+__set”反向查询出想要的字段值
print(b_obj.A.name__set)
实例:
# 1.查询书籍主键为2的出版社名称
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.publish) # 出版社对象
print(book_obj.publish.name)
# 2.查询书籍主键为4的作者姓名
book_obj = models.Book.objects.filter(pk=4).first()
print(book_obj.authors.all()) # queryset对象
for author in book_obj.authors.all():
print(author.name))
# 3.查询作者是唐家三少的手机号码
author_obj = models.Author.objects.filter(name='唐家三少').first()
print(author_obj.Author_detail,type(author_obj.Author_detail))
print(author_obj.Author_detail.phone_number)
# 4.查询出版社是进化出版社出版过的书籍
publisher_obj = models.Publisher.objects.filter(name='进化出版社').first()
book_queryset = publisher_obj.book_set.all()
print(book_queryset)
for book in book_queryset:
print(book.title)
# 5.查询作者是卷土的沙滩写过的书籍
author_obj = models.Author.objects.filter(name='卷土的沙滩').first()
book_queryset = author_obj.book_set.all()
print(book_queryset)
for book in book_queryset:
print(book.title)
# 6.查询手机号是12580的作者姓名
authdetail_obj = models.AuthorDetail.objects.filter(phone_number='12580').first()
# 一对一反向查询不需要加 “_set”
print(authdetail_obj.author.name)
什么时候需要加all:
当正向查询点击外键字段数据有多个的情况下,需要.all()
。
一旦看到app01.Author.None
只需要加.all()即可。
在写orm语句的时候跟你写sql语句一样,不要想着一次性写完写一点查一点再写一点。
3. 连表查询
基于双下划线的跨表查询 (mysql中的join)。一条语句就能查询。
models后面点的谁,就以谁为基表。
通过基表queryset对象.values()
的方法查询数据。
values()里面字段放什么,查出来的字典的键就是什么。
```正向查询```
# 在values()内写外键字段就相当于已经跨到外键字段所关联的表上,这时候在字段后面加上 ```__+关联表的字段```,就可以获取该外键外键关联表上的字段值。
```反向查询```
# 在filter()内写上 ‘表名小写+__条件’ 用来筛选对象,再在后面直接 '.values()' 获取值。
# values()括号内放字段名。
# 如果是需要跨多表,那就在values()的括号中不停地加'__+字段名',每加一个'__'就会跨一下表,最终跨到你需要差的那张表上。
实例:
# 1.查询书籍pk为2的出版社名称
# 正
res = models.Book.objects.filter(pk=2).values('publisher__name').first()
print(res)
# 反
res = models.Publisher.objects.filter(book__pk=2).values('name').first()
print(res)
# 2.查询书籍pk为2的作者姓名和邮箱
# 正
res1 = models.Book.objects.filter(pk=2).values('authors__name','authors__email')
print(res1)
# 反
res = models.Author.objects.filter(book__pk=2).values('name','email').first()
print(res)
# 3.查询作者是天蚕土豆的家庭地址
# 正
res = models.Author.objects.filter(name='天蚕土豆').values('Author_detail__addr').first()
print(res)
# 反
res = models.AuthorDetail.objects.filter(author__name='天蚕土豆').values('addr').first()
print(res)
# 4.查询出版社是天蚕出版社出版过的书的名字
# 正
res = models.Publisher.objects.filter(name='天蚕出版社').values('book__title')
for book in res:
print(book)
# 反
res = models.Book.objects.filter(publisher__name='天蚕出版社').values('title')
for book in res:
print(book)
# 跨多表
# 5.查询书籍pk是2的作者的手机号
# 正
res = models.Book.objects.filter(pk=2).values('authors__Author_detail__phone_number').first()
print(res)
# 反
res = models.Author.objects.filter(book__pk=2).values('Author_detail__phone_number').first()
print(res)
# 反2
res = models.AuthorDetail.objects.filter(author__book__pk=2).values('phone_number').first()
print(res)