Q查询进阶
import os
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoday07.settings')
import django
django.setup()
from app01 import models
# Q查询进阶操作
"""左边的查询条件依次写入 字段名,变量名"""
from django.db.models import Q
q_obj = Q() # 1.产生一个对象
q_obj.connector = 'or' # 默认添加的多个查询条件是and关系,如此将其变为or关系
q_obj.children.append(('pk',1)) # 2.添加查询条件
q_obj.children.append(('price__gt',200))
q_obj.children.append('title_contains','三') # 模糊查询
res = models.Book.objects.filter(q_obj) # 查询直接支持填写q对象
print(res)
main()
ORM查询优化
# 1.orm查询默认都是惰性查询
- orm的查询语句在用一个变量接收,但是不打印结果就不会执行该语句,叫惰性查询
# 2.orm查询自带分页处理
- orm的查询语句在查询到结果数量很大时,就会自己分页以保证安全
- orm查询后台的sql语句:
SELECT `app01_book`.`id`, `app01_book`.`title`,
`app01_book`.`price`, `app01_book`.`publish_time`,
`app01_book`.`publish_id` FROM `app01_book` LIMIT 21; args=()
"""orm查询的sql语句自带limit分页"""
# 3.only与defer
# orm查询优化
'''拿所有数据对象'''
res = models.Book.objects.all() # 结果是queryset [数据对象,数据对象]
for obj in res:
print(obj.title) # 三国演义
print(obj.price) # 998.00
'''拿到的数据对象是列表包字典的形式'''
res = models.Book.objects.all().values('title','price') # 结果是queryset [{},{}]
for i in res:
print(i) # 结果是{'title': '三国演义', 'price': Decimal('998.00')}
"""结果是数据对象+含有指定字段对应的数据"""
'''
only查询,可以将括号中列举的字段封装到数据对象里面,
使用括号里面的字段时不会再走数据库查询,
括号里面没有的字段会走数据库查询,也可以获取到
'''
# 1.only
res = models.Book.objects.only('title','price')
# print(res) # queryset [数据对象,数据对象]
for i in res:
print(i.title) # 三国演义
print(i.price) # 998.00
print(i.publish_time) # 2022-12-07
'''
defer查询与only相反,
点击括号里存在的字段名走数据库查询,
点击括号里不存在的不走数据库查询
'''
# 2.defer
res = models.Book.objects.defer('title', 'price')
# print(res) # queryset [数据对象,数据对象]
for i in res:
print(i.title) # 三国演义
print(i.price) # 998.00
print(i.publish_time) # 2022-12-07
# 4.select_related与prefetch_related
'''select_related底层是连表操作,可以支持先连表后在进行查询封装'''
# 1.select_related
res = models.Book.objects.select_related('authors')
print(res)
"""
底层sql语句:
SELECT `app01_book`.`id`, `app01_book`.`title`, `app01_book`.`price`,
`app01_book`.`publish_time`, `app01_book`.`publish_id`, `app01_publish`.`id`,
`app01_publish`.`name`,`app01_publish`.`address` FROM `app01_book`
INNER JOIN `app01_publish` ON (`app01_book`.`publish_id` = `app01_publish`.`id`)
LIMIT 21; args=()
"""
'''括号内仅仅支持一对一,一对多的字段'''
res1 = models.Author.objects.select_related('author_detail')
print(res1)
res2 = models.Book.objects.select_related('publish')
# 底层先连表后查询封装
for obj in res2:
print(obj.publish.name) # 结果:北京出版社 南京出版社 西京出版社
'''prefetch_related底层是子查询,会把一条sql当作另一个查询的条件,'''
# 2.prefetch_related
res = models.Book.objects.prefetch_related(('publish'))
for obj in res:
print(obj.publish.name) # 结果:北京出版社 南京出版社
orm事务操作
# 1.事务的四大特性(ACID)
原子性,一致性,隔离性,持久性
# 2.相关SQL关键字
start transaction; # 开启事务
rollback; # 状态回退
commit; # 提交
savepoint # 保存状态
# 3.相关重要概念
脏读,幻读,不可重复度读,MVCC多版本控制
https://www.cnblogs.com/juzijunjun/p/16936590.html
# 4.orm开启事务的方式
# django orm提供了至少三种开启事务的方式
# 方式一:全局开启(配置文件数据库相关添加键值对)
当有请求过来时,Django会在调用视图方法前开启一个事务。如果请求却正确处理并正确返回了结果,
Django就会提交该事务。否则,Django会回滚该事务
在数据库配置文件处添加 : "ATOMIC_REQUESTS": True
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mxshop',
'HOST': '127.0.0.1',
'PORT': '3306',
'USER': 'root',
'PASSWORD': '123',
'OPTIONS': {
"init_command": "SET
default_storage_engine='INNODB'",
#'init_command': "SET
sql_mode='STRICT_TRANS_TABLES'", #配置开启严格sql模式
}
"ATOMIC_REQUESTS": True, #全局开启事务,绑定的是http请求响应整个过程
"AUTOCOMMIT":False, #全局取消自动提交,慎用
},
'other':{
'ENGINE': 'django.db.backends.mysql',
......
} # 还可以配置其他数据
# 方式2:局部使用(用视图函数装饰器)
from django.db import transaction
@transaction.atomic
def view_func(request):
# This code executes inside a transaction.
orm语句
return 返回值
# 方式3:局部使用(with上下文管理)
from django.db import transaction
def view_func(request):
# This code executes in autocommit mode (Django's default).
print('66666')
with transaction.atomic(): #保存点
# This code executes inside a transaction.
orm语句
return 返回值
orm常用字段类型
# 1.AutoField: 主键自增
primary_key=Ture # 如果没有主键自增,则会创建一个主键id
# 2.IntegerField: 整型类型
Big,Small也是整型
# 3.CharField: 字符类型
max_length # 表示字符长度
verbose_name # 别名
# 4.DecimalField 小数相关类型
max_digits # 数字允许的最大位数有几位
decimal_places # 小数点后面有几位
# 5.DateField: 日期字段
auto_now # 每次数据更新都会更新时间字段
auto_now_add # 数据只会在第一次创建时记录时间
# 6.DateTimeField: 日期时间字段
auto_now # 每次数据更新都会更新时间字段
auto_now_add # 数据只会在第一次创建时记录时间
# 7.BooleanField:
传入布尔值自动存0或1
# 8.TextField:
可以存储一大段文本
# 9.EmailField:
存储邮箱格式数据
# 10.FileField:
传入文件对象,自动保存到提前配置好的路径下并存储该路径信息
"""ORM还支持用户自定义字段类型"""
# 定义阶段
class MyCharField(models.Model):
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
# 使用阶段
class User(models.Model):
name = models.CharField(max_length=32)
info = MyCharField(max_length=64)
ORM常用字段参数
# 1.primary_key 主键
# 2.verbose_name 注释
# 3.max_length 字段长度
# 4.max_digits 小数总共有多少位
# 5.decimal_places 小数点后面的位数
# 6.auto_now 每次操作数据自动更新事件
# 7.auto_now_add 首次创建自动更新事件后续不自动更新
# 8.null 允许字段为空
# 9.default 字段默认值
# 10.unique 唯一值
# 11.db_index 给字段添加索引
# 12.choices 当某个字段的可能性能够被六局完全的情况下使用
性别、学历、工作状态
class User(models.Model):
name = models.CharField(max_length=32)
info = MyCharField(max_length=64)
# 提前列举好对应关系
gender_choice = (
(1, '男性'),
(2, '女性'),
(3, '其他'),
)
gender = models.IntegerField(choices=gender_choice,null=True)
user_obj = User.objects.filter(pk=1).first()
user_obj.gender
user_obj.get_gender_display()
# 13.to 关联表
# 14.to_field 关联字段(不写默认关联数据主键)
# 15.on_delete 当删除关联表中的数据,与此表关联的其他表也会更新
"""级联删除参数"""
-1. models.CASCADE
级联操作,当主表中被连接的一条数据删除时,从表中所有与其有所关联的数据同时也会被删除
-2. models.SET_NULL
当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空
-3. models.PROTECT
当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
-4.models.SET_DEFAULT
当主表中的一行数据删除时,从表中所以相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
-5.models.SET()
当主表中的一条数据删除时,从表中所有的关联数据字段设置SET()中设置的值,与models.SET_DEFAULT类似,只不过此时从表中相关字段不需要设置default参数
-6.models.DO_NOTHING
什么都不做,一切都看数据库几倍的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似