day55-Django配置测试脚本、ORM查询、跨表正反向查询
目录
配置测试脚本
当你想单独测试django中某一个py文件,需要手动配置测试脚本
#在manage.py中拷贝前四行代码,可以直接写在应用名下的test.py中
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE','day55.seetings')
import django
django.setup()
from app01 import models
ORM普通查询
创建数据
create
#字段值可以是对象
obj = models.Table.objects.create(key=value,)
对象绑定方法
obj = models.Table(key=value,)
obj.save()
修改数据
Queryset方法
#py会自动查找到当前表的主键字段
models.Table.objects.filter(pk=1).update(key=value,)
-
filter查询出来的结果都是一个Queryset对象
-
只要是queryset对象就可以无限制的调用queryset方法
-
只要是queryset对象就可以.query查看当前结果内部对应的sql语句
res = models.Table.objects.filter(pk=1) print(res.query)
对象方法
#不推荐使用,利用对象的修改,实质是重写记录的所有字段,效率低 book_obj = models.Books.objects.get(pk=1) book_obj.price = 222.66 book_obj.save()
get和filter的区别
- filter获取到的是一个Queryset对象,类似于一个列表
- get获取到的是数据对象本身
- 当条件不存在的情况下,filter返回空,get直接报错
删除数据
queryset方法
models.Table.objects.filter(pk=1).delete()
对象方法
obj = models.Table.objects.get(pk=1)
obj.delete()
查找数据
orm语句的查询默认都是惰性查询,只有真正要使用数据的时候才会执行orm语句
夺命13条
-
# all() 查询所有 返回Queryset对象 res = models.Table.objects.all()
-
# filter() 筛选 相当于sql中的where关键字 res = models.Table.objects.filter(pk=1,)
-
# get() 筛选 获取到的是对象本身 条件不存在直接报错 res = models.Table.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() print(type(num))
-
# values() 获取数据对象中指定的字段的值 返回queryset对象 列表套字典 res = models.Books.objects.values('title','price') print(res) # <QuerySet [{'title': '三国演义', 'price': Decimal('222.66')}, {'title': '红楼梦', 'price': Decimal('888.99')}, {'title': '西游记', 'price': Decimal('444.66')}, {'title': '西游记', 'price': Decimal('666.22')}]>
-
# values_list() 获取数据对象中指定的字段的值 返回queryset对象 列表套元祖 res = models.Books.objects.values_list('title','price') print(res) #<QuerySet [('三国演义', Decimal('222.66')), ('红楼梦', Decimal('888.99')), ('西游记', Decimal('444.66')), ('西游记', Decimal('666.22'))]>
-
# order_by() 按照指定的字段排序 res = models.Books.objects.order_by('price') # 默认是升序 res1 = models.Books.objects.all().order_by('price') # 默认是升序 两者等价 下面的方式 语义更明确 # 降序 字段前面加负号 res1 = models.Books.objects.all().order_by('-price') print(res1)
-
# reverse() 颠倒顺序 前提是跌倒的对象必须有顺序(提前排序之后才能跌倒) res = models.Books.objects.all() res1 = models.Books.objects.all().reverse() res2 = models.Books.objects.all().order_by('price') res3 = models.Books.objects.all().order_by('price').reverse() print(res2,res3)
-
# exclude() 排除什么什么之外 queryset对象 res = models.Books.objects.all().exclude(title='三国演义') print(res) <QuerySet [<Books: 红楼梦>, <Books: 西游记1>, <Books: 西游记2>]>
-
# exists() 判断查询结果是否有值 返回结果是一个布尔值 鸡肋 res = models.Books.objects.filter(pk=1).exists() print(res)
-
# distinct() 对查询结果进行去重操作 去重的前提:数据必须是完全想要的情况下 才能# 够去重(容易忽略主键),多和values()连用 res = models.Books.objects.values('title','price') res = models.Books.objects.values('title','price').distinct() print(res)
#values和values_list
# 查询价格小于400 的书籍
res = models.Book.objects.filter(price__lt=400).values_list()
res1 = models.Book.objects.filter(price__lt=400).values()
print(res)
print(res1)
'''
<QuerySet [(4, '西游记', Decimal('333.00'), datetime.date(2019, 10, 29), 3)]>
<QuerySet [{'id': 4, 'title': '西游记', 'price': Decimal('333.00'), 'publish_date': datetime.date(2019, 10, 29), 'publish_id': 3}]>
'''
# values_list是列表套元组,只返回值;
# values是列表套字典,返回字段名和值的键值对
双下划线查询
# modls.py
from django.db import models
# Create your models here.
class Books(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
publish_date = models.DateField()
def __str__(self):
return self.title
# 表查询 以图书管理系统为例
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_add=True)
"""
auto_now:每次修改的数据的时候 都会自动更新修改书籍(展示最新的一次修改时间)
auto_now_add:当数据创建出来的时候 会自动将创建时间记录下来
"""
publish = models.ForeignKey(to='Publish')
authors = models.ManyToManyField(to='Author')
class Publish(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=32)
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
# test.py 查询脚本
# 查询价格大于500的书籍
# res = models.Books.objects.filter(price__gt=500).value_list()
# print(res)
# 查询价格小于400 的书籍
# res = models.Books.objects.filter(price__lt=400)
# print(res)
# 查询价格大于等于500
# res = models.Books.objects.filter(price__gte=444.66) 对数字精确度不敏感
# res = models.Books.objects.filter(price__gte=500)
# print(res)
# 查询价格小于等于500的书籍
# res = models.Books.objects.filter(price__lte=500)
# print(res)
# 查询价格是222.66或者444.22或者500的书籍
# res = models.Books.objects.filter(price__in=[222,444,500])
# print(res)
# 查询价格在200到800之间的书籍
# res = models.Books.objects.filter(price__range=(200,800)) # 顾头顾尾
# print(res)
# 查询出版日期是2019年的书籍
# res = models.Books.objects.filter(publish_date__year='2019')
# print(res)
# 查询出版日期是1月份的书籍
# res = models.Books.objects.filter(publish_date__month='1')
# print(res)
# 模糊查询
"""
MySQL中的模糊查询
关键字 like
模糊匹配的符号
%:匹配任何个数的任意字符
_:匹配一位任意的字符
"""
# 查询书籍是以三开头的书
# res = models.Books.objects.filter(title__startswith='三')
# print(res)
# 查询书籍是以义结尾的书
# res = models.Books.objects.filter(title__endswith='1')
# print(res)
# 查询书籍名称中包含游字的书籍
# res = models.Books.objects.filter(title__contains='游')
# print(res)
# 查询书籍名称中包含字母p的书籍
# res = models.Books.objects.filter(title__contains='p') # 默认区分大小写
# res = models.Books.objects.filter(title__icontains='p') # 忽略大小写 加i
# print(res)
# 一对多字段数据的增删改查
# 增
# 第一种
# models.Book.objects.create(title='三国演义',price=222.33,publish_id=1) # 直接传表里面的实际字段 跟数据主键值 publish_id
# 第二种
# publish_obj = models.Publish.objects.filter(pk=2).first()
# models.Book.objects.create(title='红楼梦',price=444.33,publish=publish_obj) # 传虚拟字段 跟数据对象即可
# 查
# 改
# 第一种
# models.Book.objects.filter(pk=1).update(publish_id=2)
# 第二种
# publish_obj = models.Publish.objects.filter(pk=1).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=2).first()
# print(book_obj.publish) # 点外键字段 可能会直接获取到外键关联的数据对象
# 给当前这一本书绑定作者
# 麻瓜做法 自己直接去操作第三张表
# print(book_obj.authors) # 已经跨到第三张表了
# book_obj.authors.add(1) # 在第三张表里面给书籍绑定一个主键为1的作者
# book_obj.authors.add(1,2) # 在第三张表里面给书籍绑定一个主键为1的作者
# author_obj = models.Author.objects.filter(pk=1).first()
# author_obj1 = models.Author.objects.filter(pk=2).first()
# # book_obj.authors.add(author_obj)
# book_obj.authors.add(author_obj,author_obj1)
"""
add方法 能够朝第三张关系表添加数据
即支持传数字
add(1,2)
也支持传对象
add(author_obj,author_obj1)
并且两者都可以是多个
"""
# 改
# book_obj = models.Book.objects.filter(pk=2).first()
# # book_obj.authors.set((1,3))
# # 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))
"""
set修改多对多关系表中的数据
既可以传数字也可以传对象
但是需要注意的是括号内必须是可迭代对象
都支持多个
set((1,3))
set((author_obj,author_obj1))
"""
# 删
# book_obj = models.Book.objects.filter(pk=2).first()
# book_obj.authors.remove(100)
# book_obj.authors.remove(1,2)
# 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)
"""
remove既可以传数字 也可以穿对象
并且都支持传多个 不需要迭代
remove(1,2)
remove(author_obj,author_obj1)
"""
# 清空 删除某个数据在第三张表中的所有记录
# book_obj = models.Book.objects.filter(pk=2).first()
# book_obj.authors.clear()
"""
clear清空书籍相关所有记录 括号内不需要传递参数
"""
# 跨表查询(******)
"""
正反向查询
关系字段在谁哪 由谁查谁就是正向
如果关系字段 就是反向
正向查询按字段
反向查询按表名小写 + _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) # app01.Author.None
# print(book_obj.authors.all())
# 3.查询作者是jason的手机号码
# author_obj = models.Author.objects.filter(name='jason').first()
# print(author_obj.author_detail)
# print(author_obj.author_detail.phone)
"""
什么时候需要加all
当正向查询点击外键字段数据有多个的情况下 需要.all()
app01.Author.None 一旦看到该结果 只需要加.all()即可
在写orm语句的时候跟你写sql语句一样 不要想着一次性写完
写一点查一点再写一点
"""
# 4.查询出版社是东方出版社出版过的书籍
# publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# # print(publish_obj.book_set) # app01.Book.None
# print(publish_obj.book_set.all())
# 5.查询作者是jason写过的书籍
# author_obj = models.Author.objects.filter(name='jason').first()
# # print(author_obj.book_set) # app01.Book.None
# print(author_obj.book_set.all()) # app01.Book.None
# 6.查询手机号是120的作者姓名
# author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
# print(author_detail_obj.author)
# print(author_detail_obj.author.email)
"""
什么时候反向查询的时候表名小写需要加_set
一对多
多对多
一对一不需要加_set
"""
# 基于双下滑线的跨表查询 联表操作
"""
inner join
left join
right join
union
"""
# 1.查询书籍pk为2的出版社名称
# 正向
# res = models.Book.objects.filter(pk=2).values('publish__name') # 写外键字段就相当于已经跨到外键字段所关联的表
# 你想要改表的哪个字段信息 你只需要加__获取即可
# print(res)
# 反向
# res = models.Publish.objects.filter(book__pk=2).values('name')
# print(res)
# 2.查询书籍pk为2的作者姓名和邮箱
# res = models.Book.objects.filter(pk=2).values('authors__name','authors__email')
# print(res)
# res = models.Author.objects.filter(book__pk=2).values('name','email')
# print(res)
"""
models后面点的谁 就以谁为基表
"""
# 3.查询作者是egon的家庭地址
# res = models.Author.objects.filter(name='egon').values('author_detail__addr')
# print(res)
# res = models.AuthorDetail.objects.filter(author__name='egon').values('addr')
# print(res)
# 4.查询出版社是东方出版社出版过的书的名字
# res = models.Publish.objects.filter(name='东方出版社').values('book__title')
# print(res)
# res = models.Book.objects.filter(publish__name='东方出版社').values('title')
# print(res)
# 查询书籍pk是2的作者的手机号
# res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
# print(res)
# res = models.Author.objects.filter(book__pk=2).values('author_detail__phone')
# print(res)
-
大于/小于
filed__gt = xxx filed__lt = xxx
-
大于等于/小于等于
#对数字精确度不敏感 filed__gte = xxx filed__lte = xxx
-
或
field__in=[x,y,z]
-
之间
filed__range(x,y) # 包含x,y
-
模糊查询
-
以。。。开头
field__startswith='xxx'
-
以。。。结尾
field__endswith = 'xxx'
-
包含。。。
field__contains = 'xxx' # 默认区分大小写 field__icontains = 'xxx' # 忽略大小写
-
-
一对多字段数据的操作
-
增/改:可以直接出传实际字段的值,虚拟字段传对象
-
删:
models.Publish.objects.filter(pk=1).delete() # 默认就是级联删除 级联更新
-
-
多对多字数数据的操作
-
增:
book_obj = models.Book.objects.filter(pk=2).first() print(book_obj.publish) # 点外键字段 可能会直接获取到外键关联的数据对象 book_obj.authors.add(1,) # 在第三张表里面给书籍绑定一个主键为1的作者,可多个 author_obj = models.Author.objects.filter(pk=1).first() book_obj.authors.add(author_obj) # add也支持传对象
-
改:
book_obj = models.Book.objects.filter(pk=2).first() #set会删除authors中所有book_obj的记录,并重新添加 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))
-
删:
book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.remove(1,) author_obj = models.Author.objects.filter(pk=1).first() book_obj.authors.remove(author_obj)
-
清空:
# 清空 删除某个数据在第三张表中的所有记录 book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.clear()
-
跨表查询
正向查询:包含关系字段的表,查关联表;按字段查询
反向查询,不含关系字段的表,查关联表;按表名小写_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) # app01.Author.None
print(book_obj.authors.all()) # 当查询结果有多个值时,使用all()
反向查询
在一对多和多对多的情况下,使用**_ set ;一对一情况下不需要加_ set **
基于双下划线的跨表查询
两表
# 1.查询书籍pk为2的出版社名称
# 正向
res = models.Book.objects.filter(pk=2).values('publish__name') # 写外键字段就相当于已经跨到外键字段所关联的表
# 你想要改表的哪个字段信息 你只需要加__获取即可
print(res)
# 反向
res1 = models.Publish.objects.filter(book__pk=2).values('name')
print(res1)
多表
# 查询书籍pk是2的作者的手机号
res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
print(res)
#可以有不同的基准
res1 = models.Author.objects.filter(book__pk=2).values('author_detail__phone')
print(res1)