Django基础之模型层(02)
阅读原文时间:2023年07月09日阅读:5

1 重要概念

# 多表查询
"""
正向查询

反向查询

当前查询对象是否含有外键字段  
    如果有就是正向  
    没有无则是反向  
口诀:  
    正向查询按外键字段  
        多对多需要额外再加一个.all()  
        一对多和一对一不需要加  
    反向查询按表名小写  
        一对多与多对多  
            \_set.all()  
        一对一  
            不需要加  
"""

2 多表查询

#####################基于对象的跨表查询#####################
# 子查询:将一张表的查询结果当做另外一条SQL语句的条件(括号括起来)
# 1.查询书籍主键为4的出版社名称
# 先查询书籍对象
# book_obj = models.Book.objects.filter(pk=4).first()
# 外键字段在书这里 所以是正向查询
# res = book_obj.publish
# print(res)
# print(res.title)
# print(res.addr)

# 2.查询书籍主键为3的作者姓名
# 先查询书籍对象
# book_obj = models.Book.objects.filter(pk=3).first()
# 外键字段在书这里 所以是正向查询
# res = book_obj.authors
# print(res) # app01.Author.None
# res = book_obj.authors.all()
# print(res) # , ]>


# 3.查询作者jason的地址
# 先查询jason数据对象
# author_obj = models.Author.objects.filter(name='jason').first()
# 外键字段在作者这里 所以是正向查询
# res = author_obj.author_detail
# print(res)
# print(res.addr)
# print(res.phone)


# 4.查询东方出版社出版的书籍
# 先查询出版社对象
# publish_obj = models.Publish.objects.filter(title='东方出版社').first()
# 外键字段在书那里自己没有 所以是反向
# res = publish_obj.book_set
# print(res) # app01.Book.None
# res = publish_obj.book_set.all()
# print(res)


# 5.查询jason写过的书籍
# 先查询jason数据对象
# author_obj = models.Author.objects.filter(name='jason').first()
# 外键字段在书那里自己没有 所以是反向
# res = author_obj.book_set
# print(res) # app01.Book.None
# res = author_obj.book_set
# print(res) # app01.Book.None
# res = author_obj.book_set.all()
# print(res) # app01.Book.None


# 6.查询电话是120的作者
# 先查询120数据对象
# author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first()
# 外键字段在作者那里本身没有 所以是反向
# res = author_detail_obj.author
# print(res)
# print(res.name)
# print(res.age)

########################基于双下滑线的跨表查询  
# 1.查询书籍主键为4的出版社名称  
# res = models.Book.objects.filter(pk=4).values('publish\_\_title','publish\_\_addr','title')  
# print(res)  


# 2.查询书籍主键为3的作者姓名
# res = models.Book.objects.filter(pk=3).values('authors__name')
# print(res)

# 3.查询作者jason的地址
# res = models.Author.objects.filter(name='jason').values('author_detail__addr','name','age')
# print(res)

# 4.查询北方出版社出版的书籍名称
# res = models.Publish.objects.filter(title='北方出版社').values('book__title')
# print(res)

# 5.查询jason写过的书籍
# res = models.Author.objects.filter(name='jason').values('book__title','name','age')
# print(res)

# 6.查询电话是120的作者
# res = models.AuthorDetail.objects.filter(phone=120).values('author__name','author__age','addr')
# print(res)

############进阶操作#############  
# 1.查询书籍主键为4的出版社名称  
# res = models.Book.objects.filter(pk=4).values('publish\_\_title','publish\_\_addr','title')  
# print(res)  
# 反向查询高阶部分  
# res = models.Publish.objects.filter(book\_\_pk=4)  
# print(res)  


# 2.查询书籍主键为3的作者姓名
# res = models.Book.objects.filter(pk=3).values('authors__name')
# print(res)
# 反向查询高阶部分
# res = models.Author.objects.filter(book__pk=3)
# print(res)

# 3.查询作者jason的地址
# res = models.Author.objects.filter(name='jason').values('author_detail__addr','name','age')
# print(res)
# 反向查询高阶部分
# res = models.AuthorDetail.objects.filter(author__name='jason')
# print(res)


# 查询书籍主键为3的作者的电话号码
# res = models.Book.objects.filter(pk=3).values('authors__author_detail__phone')
# print(res)

# res = models.AuthorDetail.objects.filter(author__book__pk=3).values('phone')
# print(res)

# res = models.Author.objects.filter(book__pk=3).values('author_detail__phone')
# print(res)

3 F查询

   # F查询
from django.db.models import F
# 1.查询库存数大于卖出数的书籍
# res = models.Book.objects.filter(kucun__gt=F('maichu'))
# print(res)
# 2.将所有的书籍价格上涨100块
# res = models.Book.objects.update(price=F('price') + 100)
# print(res)
# 3.将所有的书籍名称加上"爆款"后缀
'''针对字符串不能直接拼接 需要额外导入模块操作'''
# models.Book.objects.update(title=F('title') + '爆款')
# from django.db.models.functions import Concat
# from django.db.models import Value
# ret3 = models.Book.objects.update(title=Concat(F('title'), Value('爆款')))

4 Q查询

   # 1.查询书名是三国演义爆款或者库存是100的书籍
'''filter()括号内可以写多个参数 逗号隔开 默认只支持and连接'''
from django.db.models import Q
# res = models.Book.objects.filter(title='三国演义爆款',kucun=100)
# print(res)
# res1 = models.Book.objects.filter(Q(title='三国演义爆款'),Q(kucun=100)) # and
# res1 = models.Book.objects.filter(Q(title='三国演义爆款')|Q(kucun=100)) # or
# res1 = models.Book.objects.filter(~Q(title='三国演义爆款')|Q(kucun=100)) # not
# print(res1.query)
'''Q进阶用法'''
# condition = input('请输入你需要按照什么字段查询数据>>>:')
# data = input('请输入你需要查询的数据名称>>>:')
# q = Q() # 生成一个Q对象
# q.children.append((condition,data))
# res = models.Book.objects.filter(q)
# print(res)
q = Q()
q.connector = 'or' # 可以修改连接条件
q.children.append(('title__contains','三'))
q.children.append(('price__gt',200)) # 可以添加多个条件 并且也是and关系
res = models.Book.objects.filter(q)
print(res)
print(res.query)

5 事务

"""
1.事务四大特性 ACID
原子性
一致性
独立性
持久性
2.数据库设计三大范式
课下百度搜索自己概括

MySQL
start transcation
commit
rollback
"""
from django.db import transaction
try:
with transaction.atomic():
# 创建一条订单数据
models.Order.objects.create(num="110110111", product_id=1, count=1)
# 能执行成功
models.Product.objects.filter(id=1).update(kucun=F("kucun") - 1, maichu=F("maichu") + 1)
except Exception as e:
print(e)

6 执行原生SQL语句

res = models.Book.objects.raw('select * from app01_book')
for i in res:
print(i)

7 模型层字段及参数

models.AutoField(primary_key=True)
models.CharField(max_length=32) # varchar(32)
models.IntergeField() # int()
models.DateField() # date
models.DateTimeField() # datetime
auto_now
auto_now_add
models.DecimalField() # float()
models.BooleanField()
给这个字段传布尔值会自动转换成数字0或1
一般用在状态二选一
TextField()
存储大段文本(bbs项目会使用)
EmailField()
存储邮箱格式数据
FileField()
存储数据路径(bbs项目会使用)

"""自定义字段"""
from django.db.models import Field


class MyCharField(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

8 常见参数

max_length
varbose_name
default
null
auto_now
auto_now_add
to
unique
db_index
choices

choices参数

创建用户表
性别
两到三种状态
学历
也是有限个
在职状态
也是有限个
婚姻
也是有限个

"""针对某个字段可以列举完全的情况 一般都是使用choices参数"""
class Server(models.Model):
host = models.CharField(max_length=32)

status_choices = (
(1,'在线'),
(2,'待上线'),
(3,'宕机'),
(4,'待上架')
)
status = models.IntegerField(choices=status_choices)

desc_choices = (
('哈哈','哈哈哈哈哈哈'),
('呵呵','呵呵呵呵呵呵'),
('嘿嘿','嘿嘿嘿嘿嘿嘿'),
('嘻嘻','嘻嘻嘻嘻嘻嘻'),
)
desc = models.CharField(max_length=32,choices=desc_choices)

获取对应关系

.get_字段名_display()

9 ORM查询优化

# 惰性查询
用不到的数据即使写了orm语句也不会执行
1.only与defer
2.select_related与prefech_related

1.only与defer


# res = models.Book.objects.values('title') # 列表套字典

# res1 = models.Book.objects.only('title') # 列表套对象
# print(res1)
# for i in res1:
# # print(i.title)
# print(i.price)
"""
only括号内写什么字段
生成的对象就含有对应的属性 在查找该属性的时候不再走数据库查询
但是一旦查找括号内没有的字段属性 则每次都会走数据库查询

"""
# res1 = models.Book.objects.defer('title')
# # print(res1) # 列表套对象
# for i in res1:
# # print(i.title)
# print(i.title)
"""
defer与only刚好相反
生成的对象就不含有对应的属性 在查找该属性的时候需要每次走数据库查询
但是一旦查找括号内没有的字段属性 则不需要走数据库查询
"""
# res = models.Book.objects.filter(pk=3).first()
# print(res.publish.title)


# res = models.Book.objects.select_related('publish')
# for i in res:
# print(i.publish.title)
"""
select_related相当于连表操作
先将models后面的表和括号内外键字段关联的表连接起来
之后一次性把所有的数据封装到数据对象中
"""
res = models.Book.objects.prefetch_related('publish')
for i in res:
print(i.publish.title)
"""
prefetch_related相当于子查询
先查询models后面的表的所有的数据
然后将括号内关联的表的数据全部查询出来
之后整合到一起
"""