django中如何开启事务
事务处理
提交commit,当所有的操作步骤都被完整执行后,称该事务被提交。
回滚rollback,由于某一操作步骤执行失败,导致所有步骤都没有被提交,则事务必须回滚,即回到事务执行前的状态。
事务ACID属性
事务处理的特性,每一个事务都有他们所共有的特性,叫做ACID特性,分别是:原子性atomicity,一致性consistency、隔离性Isolation,持久性Durability。
1、原子性,事务的原子性表示事务执行过程中,把事务作为一个工作单元处理,一个工作单元可能包括若干个操作步骤,每个操作步骤都必须完成才算完成,若因任何原因导致其中的一个步骤操作失败,则所有步骤操作失败,前面的步骤必须回滚。
2、一致性,事务的一致性保证数据处于一致状态。如果事务开始时系统处于一致状态,则事务结束时系统也应处于一致状态,不管事务成功还是失败。
3、隔离性,事务的隔离性保证事务访问的任何数据不会受到其他事务所做的任何改变的影响,直到该事务完成。
4、持久性,事务的持久性保证加入事务执行成功,则它在系统中产生的结果应该是持久的。
django开启事务
# 暂时只需掌握Django中如何开启事务 # mysql中通过start transaction开启事务 # django中通过导入transaction模块开启事务 from django.db import transaction try: #可以对事务捕获异常,当事务出错时进行另外的处理 with transaction.atomic(): # sql1 # sql2 ... # 在with代码快内书写的所有orm操作都是属于同一个事务 except Exception as e: print(e) print('执行其他操作')
数据库设计三大范式
参考博客:https://www.cnblogs.com/Tang-Yuan/p/14689514.html 这里不做详细介绍
ORM中常用字段及参数
AutoField
int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
IntegerField
一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)
CharField
字符类型,必须提供max_length参数, max_length表示字符长度。
这里需要知道的是Django中的CharField对应的MySQL数据库中的varchar类型,没有设置对应char类型的字段,但是Django允许我们自定义新的字段,下面我来自定义对应于数据库的char类型
自定义字段在实际项目应用中可能会经常用到,这里需要对他留个印象!
from django.db import models
# Create your models here.
#Django中没有对应的char类型字段,但是我们可以自己创建
class FixCharField(models.Field):
'''
自定义的char类型的字段类
'''
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):
'''
限定生成的数据库表字段类型char,长度为max_length指定的值
:param connection:
:return:
'''
return 'char(%s)'%self.max_length
#应用上面自定义的char类型
class Class(models.Model):
id=models.AutoField(primary_key=True)
title=models.CharField(max_length=32)
class_name=FixCharField(max_length=16)
gender_choice=((1,'男'),(2,'女'),(3,'保密'))
gender=models.SmallIntegerField(choices=gender_choice,default=3)
自定义及使用
DateField
日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
DateTimeField
日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
auto_now:每次修改数据的时候都会自动更新当前时间
auto_now_add:只在创建数据的时候记录创建时间后续不会自动修改了
EmailField
字符串类型,Django Admin以及ModelForm中提供验证机制
DecimalField
10进制小数 - 参数: max_digits,小数总长度 decimal_places,小数位长度
FloatField
浮点型
BooleanField
布尔值类型
该字段传布尔值(False/True) 数据库里面存0/1
TextField
文本类型
该字段可以用来存大段内容(文章、博客...) 没有字数限制
FileField
字符类型 upload_to = "/data"上传文件的保存路径
给该字段传一个文件对象,会自动将文件保存到/data目录下然后将文件路径保存到数据库中
/data/a.txt
ImageField
字符串,路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串)
DurationField
长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
更多字段参数:https://www.cnblogs.com/Dominic-Ji/p/9203990.html
ORM字段与MySQL字段对应关系
对应关系: 'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)',
# 外键字段及参数 unique=True ForeignKey(unique=True) === OneToOneField() # 你在用前面字段创建一对一 orm会有一个提示信息 orm推荐你使用后者但是前者也能用 db_index 如果db_index=True 则代表着为此字段设置索引 (复习索引是什么) to_field 设置要关联的表的字段 默认不写关联的就是另外一张的主键字段 on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。 """ django2.X及以上版本 需要你自己指定外键字段的级联更新级联删除 """
数据库查询优化
only与defer
""" orm语句的特点: 惰性查询:只有当后面用到了orm语句所查询出的参数时才会执行,否则orm就会自动识别不执行 """ # res = models.Book.objects.all() # print(res) # 要用数据了才会走数据库查询 # 想要获取书籍表中所有书的名字 res = models.Book.objects.values('title') for d in res: print(d.get('title')) # only与defer res = models.Book.objects.only('title') res = models.Book.objects.all() # all已经包含了所有的数据,因此直接点字段就不会走数据库 res = models.Book.objects.defer('title') # 与only的效果刚好相反 for d in res: print(d.title) # 点only括号内的字段不会走数据库 # 点defer括号内的字段会重新走数据库查询 print(d.price) # 点only括号外的字段,会重新走数据库查询 # 点defer括号外的字段,不会走数据库 ''' 总结: only括号外的字段不在查询出的对象里,查询该字段会重新走数据库 only括号内的字段就无需走数据库了 defer与only相反 defer括号内的字段不在查询出的对象里,查询该字段会重新走数据库 defer括号外的字段无需走数据库 '''
select_related与prefetch_related
# select_related与prefetch_related 都与跨表操作有关 # select_related res = models.Book.objects.all() # 每循环一次就要走一次数据库查询 res = models.Book.objects.select_related('publish') # INNER JOIN 是联表操作 res = models.Book.objects.prefetch_related('publish') # IN 子查询 for i in res: print(i.publish.name) ''' 总结: select_related内部就是连表操作,一次性将大表里的所有数据全部封装给查询出来的对象 select_related(外键字段1__外键字段2__外键字段3) 此时无论是点book表的字段还是点publish表的字段都无需再走数据库查询了 注意:select_related括号内只能放外键字段且只能是一对多、一对一的表间关系, 如果是多对多就会报错 prefetch_related内部就是子查询,会将查询出来的所有结果也给你封装到对象中 select_related与prefetch_related给用户的感觉是没有什么差距的, 但是这两个方法各有优缺点,必须结合实际情况来考虑用谁 '''