ORM(下)
内容概要
- Q查询进阶操作
- ORM查询优化
- ORM事务操作
- ORM常用字段类型
- ORM常用字段参数
- ORM三种创建多对多方式
Q查询进阶操作
"""
Q查询的进阶操作
"""
from django.db.models import Q
# 先产生Q对象
q_obj = Q()
# 确认条件之间的连接关系
q_obj.connector = 'or' # 以 or连接
# 添加条件 pk=1
q_obj.children.append(('pk', 1))
# 在添加 一个 条件 name= '西游记'
q_obj.children.append(('name', '西游记'))
# 现在相当于 pk=1 or name='西游记'
res = models.Book.objects.filter(q_obj)
res1 = models.Book.objects.filter(Q(pk=1) | Q(name='西游记'))
print(res)
print(res1)
ORM查询优化
-
ORM查询默认都是惰性查询
就是如果你这行代码后续没有用到 那么我就不会执行
-
ORM查询自带分页
-
only
"""数据对象 + 含有指定字段对应的数据"""
一条SQL
还是一条SQL
但是在点一个
only
括号外的数据的时候res = models.Book.objects.only('name', 'price') for obj in res: print(obj.register_time)
每一次循环都会产生一条
SQL
语句总结:如果是
only
括号内的字段不走SQL,括号外的走SQL -
defer
res = models.Book.objects.defer('name', 'price') for obj in res: print(obj.name)
res = models.Book.objects.defer('name', 'price') for obj in res: print(obj.register_time)
总结:
defer
在查询括号内的字段的时候做走SQL
,括号外的不走SQL
-
select_related
res = models.Book.objects.select_related('publish') print(res)
-
prefetch_related
res = models.Book.objects.prefetch_related('publish') print(res)
总结:select_related
是连表操作,perfetch_related
是子查询
ORM事务操作
-
事务的四大特性(ACID)
原子性、一致性、隔离性、持久性
-
相关SQL关键字
""" start transaction; 启动事务 rollback; 回滚 commint; 确认 直接刷进内存了 savepoint; # 保存点 """
-
相关重要概念
脏读、幻读、不可重复读、MVCC多版本控制....
-
django orm提供了至少三种开启事务的方式
全局有效
方式一:配置文件数据库添加相关键值对 全局有效
"ATOMIC_REQUESTS": True 每次请求所涉及到的ORM操作属于同一个事物
然后再视图函数里面写ORM的操作,如果遇到报错则回滚,返回的不是一个
HttpResponse
对象的报错不算def index_func(request): models.Book.objects.create(name='石头记', price='19.9', publish_id=1) paa return HttpResponse('嘿嘿')
执行之前
执行后
因为在执行的过程中报错了,所以事务回滚到执行前了所以没有添加进去。
def index_func(request): models.Book.objects.create(name='石头记', price='19.9', publish_id=1) return HttpResponse('嘿嘿')
这样就添加进去,虽然事务回滚了,但是主键记录了,它是添加过数据的。
def index_func(request): models.Book.objects.create(name='射雕英雄传', price='19.9', publish_id=1) return 111
返回的不是一个
HttpResponse
对象 的报错不影响事务,也是添加成功的
-
方式二:装饰器 局部有效
from django.db import transaction @transaction.atomic def index():pass
-
方式三:
with
上下文管理 局部有效from django.db import transaction def reg(): with transaction.atomic(): pass
-
ORM常用字段
-
AutoField
int自增列,必须要填入参数
primary_key=True
。如果model
中没有自增列,则会自动创建一个列名为id
的列 -
IntegerField
一个整数类型,范围在
-2147483648 to 2147483647
。(一般不用它来存手机号(位数也不够),直接用字符串存)
-
CharField
字符串类型,必须提供
max_length
参数,max_length
表示字符长度。这里需要直到的是Django中的CharField对应的MySQL数据库中的varchar类型,没有设置对应char类型的字段,但是Django允许我们自定义新的字段
自定义字段写法
class MyCharField(models.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
应用
class UserInfo(models.Model): name = MyCharField(max_length=32) phone = models.CharField(max_length=32)
-
DateField
日期字段,日期格式
YYYY-MMM-DD
,相当于Python中的datetime.date()
实例。 -
DateTimeField
日期时间字段,相当于Python的
datetime.datetime()
实例 -
BigIntegerField
MySQL的bigint
-
SmallIntegerField
MySQL的samllint
-
BooleanField
传布尔值自动存0或1
-
TextField
存储大段文本
-
EmailField
存储邮箱格式数据
-
FileField
传文件对象 自动保存到提前配置好的路径下并存储该路径信息
ORM常用字段参数
primary_key 主键
verbose_name 注释
max_length 字段长度
max_digits 数值的总长度
decimal_places 小数点后面的位数
auto_now 每次操作数据自动更新时间
auto_now_add 首次创建数据的时间
null 允许字段为空
default 字段默认值
unique 唯一值
db_index 给字段添加索引
choices 当某个字段的可能性能够完全列举出来出来的情况下使用
比如:性别、学历、工作状态...
实操
class UserInfo(models.Model):
name = MyCharField(max_length=32)
phone = models.CharField(max_length=32)
# 列举好对应关系
gender_choice = (
(1, '男'),
(2, '女'),
(3, '其他')
)
gender = models.IntegerField(choices=gender_choice, verbose_name='性别', default=1)
取出来
# res = models.UserInfo.objects.create(name='jason', phone=140, gender=1)
res = models.UserInfo.objects.filter(name='jason').first()
print(res.gender)
print(res.get_gender_display())
to 关联表
to_field 关联字段(不写默认关联数据主键)
on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。
-
models.CASCADE
级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时删除
-
models.SET_NULL
级联操作,当主表中被连接的一条数据删除时,从表中所有与之相关联的数据的相关字段设置为
null
,此时注意外键时,这个字段必须可以为空 -
models.PROTECT
当主表中的一行数据删除时,由于从表中相关字段时受保护的外键,所以都不允许删除
-
models.SET_DEFAULT
当主表的一行数据删除时,从表中所有相关数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
-
models.SET()
当主表中的一条数据删除时,从表所有的关联数据字段设置为SET()中设置的值,与
models.SET_DEFAULT
相似,只不过此时从表中的相关字段不需要设置default
参数 -
models.DO_NOTHING
什么都不做,一切都看数据库级别的约束,
注:数据库级别的默认约束为
RESTRICT
,这个约束与django
中的models.PROTECT
相似
多对多三种创建方式
-
全自动创建
class Book(models.Model): title = models.CharField(max_length=32, verbose_name='书名') authors = models.ManyToManyField(to='Author') class Author(models.Model): name = models.CharField(max_length=32, verbose_name='姓名')
优势:自动创建第三张表, 并且提供了add、remove、set、clear以及正反向概念
劣势第三张表无法创建更多的字段 扩展性较差
-
全手动
class Book(models.Model): title = models.CharField(max_length=32, verbose_name='书名') class Author(models.Model): name = models.CharField(max_length=32, verbose_name='姓名') class Book2Author(models.Field): book = models.ForeignKey(to=Book, on_delete=models.CASCADE) author = models.ForeignKey(to=Author, on_delete=models.CASCADE) others = models.CharField(max_length=32, verbose_name='其他') join_time = models.DateField(auto_now_add=True, verbose_name='绑定时间')
优势:第三张表完全由自己创建,扩展性强
劣势:编写繁琐 并且不在支持add、remove、set、clear以及正方向概念
-
半自动
class Book1(models.Model): title = models.CharField(max_length=32) authors = models.ManyToManyField(to='Author1', through='Book1ToAuthor1', through_fields=('book', 'author')) # 在哪个表就先填那个字段 class Author1(models.Model): name = models.CharField(max_length=32) class Book1ToAuthor1(models.Model): book = models.ForeignKey(to=Book1, on_delete=models.CASCADE) author = models.ForeignKey(to=Author1, on_delete=models.CASCADE) join_time = models.DateField(auto_now_add=True)
优势:第三张表完全由自己创建 扩展性强 正反向概念依然可见
劣势:编写繁琐 不在支持 add、set、remove、clear