Model模型
- Django的Models文件
- Models文件其实是包含了一大堆class类代码的文件,每个类名映射创建数据库表的表名,它包括的类代码通过迁移操作,在数据库生成对应的表。生成迁移文件是生成了ORM可以识别的语句,然后迁移文件,ORM会根据语句的内容,对应的在数据库中执行相应的数据库表的操作;
- model类的默认规则
- django会为表创建自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后django不会再创建自动增长的主键列。
- 创建完数据库表后,pk是主键的别名,fk是外键的别名,在使用过滤器的时候可以代替主键和外键的字段名称;
- 字段类型
- 常用字段类型
- IntegerField 整形
- AutoField 自动增长的IntegerField,通常会将主键字段设置为该字段类型;
- CharField 字符串字段,必须有(max_length=字符长度)参数
- BooleanField 布尔类型,不能为空,Blank=True或者False
- DateField 存储日期类型,
- 参数auto_now表示每次保存记录对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false。
- 参数auto_now_add表示当记录对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false。
- 参数auto_now_add和auto_now是相互排斥的,组合将会发生错误。生产中,这两个参数基本上不用
- FilePathField 文件字段(上传场景下才会使用)
- 图片字段,继承于FileField,对上传的内容进行校验,确保是有效的图片
- 和upload_to现象配合使用,表示通过admin来操作上传图片的时候,图片存储在服务器上的位置
- 其他时间字段类型
- DateTimeField 存储日期+时间类型,参数同DateField
- TimeField 存储时间类型,参数同DateField
- 其他数字相关字段类型
- ComaSeparatedIntegerField 用逗号分割的数字,必须有max_lenght参数
- DecimalFiled 十进制小数类型,必须指定整数位max_digits和小数位decimal_places
- 格式:DecimalField(max_digits=None, decimal_places=None)
- PositiveIntegerFiel 正Integer
- PositiveSmallIntegerField 正smallInteger
- SlugField 减号、下划线、字母、数字
- SmallIntegerField 数字,数据库中的字段有:tinyint、smallint、int、bigint
- 其他字符串类型
- EmailField 字符串类型(正则表达式邮箱)
- IPAddressField 字符串类型(ip4正则表达式)
- TextField 字符串 (大文本字段,一般超过4000个字符时使用。)
- URLField 字符串,地址正则表达式
- GenericIPAddressField 字符串类型(ip4和ip6是可选的),参数protocol可以是:both、ipv4、ipv6,验证时,会根据设置报错
- 其他不常用类型
- FloatField 浮点类型
- NullBooleanField 允许为空的布尔类型
- BigIntegerField 长整形
- BinaryField 二进制
- 常用选项
- 常用选项
- null 如果为True,表示允许为空,默认值是False
- 针对表设计,设置的为字段属性,为True时允许为空值,现象为如果该字段插入空数值会报错
- 使用orm对数据增删改查的时候有个特性,当我们没定义地段的内容的时候,会插入空字符串
- blank 如果为True,则该字段允许为空白,默认值是False。
- 针对表记录,操作数据表的时候,字段是否允许为空,适用于django的 Admin 中添加数据时是否可允许空值,现象为在admin中添加数据是否允许为空。
- default 默认值
- 当设置了default属性,null属性将变为False,但是不影响用户,还是可以不进行该字段的设置
- primary_key 主键,若为True,则该字段会成为模型的主键字段,将不会创建默认的主键id字段
- 默认值是False,一般作为AutoField的选项使用
- max_length 最大值,一般配合字符串进行使用
- unique 如果为True, 这个字段在表中必须有唯一值,默认值是False
- choice choice指定一个元组,该字段在元组提供的范围内进行选择
- 示例:
- order_status = models.SmallIntegerField(choices=((1,'已付款'),(2, '未付款')), default=1)
- order_status字段只能在提供的几个内容中选择,在前台使用数字,在后台使用字符串;
- 其他选项
- verbose_name Admin中字段的显示名称, 可以在第一个参数以非命名参数的形式进行传递
- upload_to 和ImageField字段配合使用,表示通过admin来操作上传图片的时候,图片存储在服务器上的位置
- auto_now 自动创建---无论添加或修改,都是当前操作的时间
- auto_now_add 自动创建---永远是创建时的时间
- db_column 字段的名称,如果未指定,则使用属性的名称
- unique 如果为True, 这个字段在表中必须有唯一值,默认值是False
- db_index 若值为True, 则在表中会为此字段创建索引,默认值是False
- editable=True 在Admin里是否可编辑
- error_messages=None 错误提示
- auto_created=False 自动创建
- help_text 在Admin中提示帮助信息
- Model的元选项
- 为什么使用元选项
- 可以通过设置元选项,来自定义一些模型类的对应表或者orm的一些属性,达到一些自己想要的效果
- 常用元选项(在Meta元类添加的属性)
- db_table 定义创建的数据库表的名字
- 示例:
- abstract 这个模型就不会被用来创建任何数据表。当它被用来作为一个其他model的基类时使用
- 示例:
- ording 强调查询集的结果按照什么规则进行排序
- 示例:
- verbose_name 更改admin中的模型类的名称
- verbose_name 更改模型类单数形式的名称
- verbose_name_plural 更改模型类复数形式的名称
- 然后生成迁移文件
- 执行迁移文件
Model-ORM
- ORM的简介
- Django框架中的Model内嵌了ORM的功能,全拼Object-Relation Mapping,中文意为对象-关系映射。它是随着面向对象的软件开发方法发展而产生的,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
- 对象和关系和ORM
- 对象:业务实体在内存中表现为对象,在数据库中表现为关系数据。
- 关系:内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。
- ORM:因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
- 对ORM的解析
- O -- object -- 对象 -- Models文件中的class类对象
- R -- relation -- 关系 -- mysql关系数据库中的表
- M -- mapping -- 映射 -- 对象和数据库表之间的一一对应
- 对映射的解释:
- 在model文件中,当我们创建数据库表的类对象的时候,存在下列的对应关系就叫映射
- 类名 对应 表名
- 类属性 对应 字段名
- 类属性方法 对应 字段类型
- 类属性方法参数 对应 字段的约束
- 类实例对象 对应 数据库表记录
- ORM的转换和QuerySet对象
- ORM操作的转换
- 我们数据操作的时候,操作的对象是类对象,但是真正执行的是什么呢,是转换后的具体的数据库sql语句
- 例如:
- 插入数据的操作:
- 面向对象的操作:
- book1 = BookInfo(btitle='倚天屠龙记', bpub_date='1990-08-23')
- ret = book1.save()
- 数据库的获取操作:(实际上是将对类对象的操作,转化为了对mysql数据库的操作)
- insert into book_app_bookinfo(id,btitle,bpub_date,bread,bcomment,isDelete) values('5',' 倚天屠龙记','1990-08-23',33,22,0);
- QuerySet对象
- 我们查询、插入数据库的记录对象的时候,这些语句返回的结果是一个jqeury_set对象
- print(type(ret))------》<class 'django.db.models.query.QuerySet'>
- 当我们调用QeurySet对象的时候,对象会执行方法并根据与sql语言的映射关系来执行sql语句
- 执行后返回的结果为模型类的实例对象,对应数据库中的记录对象
- 通过QuerySet对象.query的属性,可以获取转化后的sql语句
- ORM的作用
- 映射 -- 对象和表之间的映射,对象的属性和表的字段信息一一对应
- 转换 -- 对象操作命令和表操作命令之间的转换,通过操作类对象就能操作数据库
- 省事 -- 不用担心后端数据库更换的情况,因为用过ORM只需要直接对数据模型的类对象做操作,不用担心更换数据库,导致操作变化
管理器
- 什么是管理器
- 大家到现在应该看到 objects 应该知道他是什么了吧,对他是从Django的Model类中继承的一个默认对象管理器,通过他的方法可以获取模型类的实例对象;
- 默认的管理器
- 默认管理器
- 模型类对象的objects属性,就是默认管理器;
- 为什么称objects为默认管理器
- 当我们自己定义的类继承与Django的Model类,如果我们没有自定义管理器,那么Django会为我们定义的一个模型类生成一个名为objects的管理器,作为我们类对象自己的管理器。
- 更改默认管理器的名字
- 格式:
- 新管理器名称 = models.Manager() 定义模型类属性
- 例子:
- books = models.Manager()
- 步骤:
- 在模型类的中添加管理器属性名的属性
- books = models.Manager()
- 生成迁移
- 执行迁移
- 自定义管理器(重写功能)
- 自定义管理器
- 出了默认管理器外,我们还可以定义管理器,实现对默认管理器的功能的拓展或者有其他功能的默认管理器,Django支持自定义管理器类,继承自models.Manager
- 自定义管理器的使用场景
- 1.在原来的管理器基础上修改某些功能
- 2.在原来的管理器基础上添加某些功能
- 第一种使用个场景;给管理器添加新的方法
- 步骤:
- 1打开book_app/models.py文件,定义类BookInfoManager
- get_queryset() 方法名不能更改为获取orm生成的与sql语句存在影射关系的对象
- 2将我们继承的models.Manager,更改为BookInfoManager
- 注意:
- 要注意这两个类的顺序,因为代码是从上向下执行的,所以我们在重新定义管理器,所以必须让管理器的类在最前面
- 3执行迁移
- 第二种使用场景:修改管理器的原有方法
- 步骤:
- 1.修改继承的manager管理器的reate方法
- 2.将我们继承的models.Manager,更改为BookInfoManager
- 3执行迁移
ORM操作之增删改查---对Model类的实例对象操作(映射数据库表的记录)
- 增操作
- 第一种方法
- book1 = BookInfo(btitle='倚天屠龙记', bpub_date='1990-08-23')
- book1.save()
- 没有限制的字段内容可以不填
- 第二种方法--create
- BookInfo.objects.create(btitle="碧血剑",bpub_date="1990-02-02")
- 删除
- 获取想要删除的记录对象
- book=BookInfo.objects.get(id=1)
- 将对象进行删除
- book1.delete()
- 修改
- 第一种方法
- book=BookInfo.objects.get(id=1)
- book.btitle="射雕传"
- 通过BookInfo的实例对象.类属性名,可以取出来对应记录的字段信息,重新赋值可以直接进行修改
- book.save()
- 第二种方法
- BookInfo.objects.filter(id=1).update(btitle="射雕传")
- 通过updata方法可以实现一次对多个字段内容进行修改
- 查---后面会介绍过滤器,会介绍所有和查询相关的操作
- 查询所有数据
- BookInfo.objects.all()
- 后面有通过过滤器来选则
- 查询指定数据
- BookInfo.objects.get(id=1)
- 事物
- 导入tansaction对象
- from django.db import transaction
- 装饰view函数
- @transaction.atomic
- 创建保存点
- save_point = transaction.savepoint()
- 对事物进行回滚
- transaction.savepoint_commit(save_point)
- 对事物进行提交
- transaction.savepoint_rollback(save_point)
- 解释:
- 增删改查操作实质上是创建或者从数据库取出models的实例,对其进行增删改查的 操作,然后进行保存
ORM查询集
- 查询集
- 什么是查询集
- 查询集表示从数据库中获取的对象集合,在管理器上调用某些过滤器方法会返回查询集,查询集可以含有零个、一个或多个过滤器。过滤器基于所给的参数、条件、限制、查询后的结果;
- 查询集的两个含义
- 1、我们通过查询获取到的数据的集合(代表查询后的结果)
- 2、我们在获取查询数据的过程中,查询命令和过滤器方法的集合(代表整个查询语句)
- 过滤器
- 什么是过滤器
- 把从数据库中获取的数据进行过滤,返回过滤后的结果,它就是一个筛子,筛出我们想要的数据,主要是对类对象的对象管理工具中的对象进行筛选;
- 过滤器的种类
- 获取多对象过滤器
- all() 返回所有数据。
- filter() 返回满足条件的数据。
- exclude() 返回满足条件之外的数据,相当于sql语句中where部分的not关键字。
- order_by() 对结果进行排序。 加符号可以更改为从大到小排列
- 注意:
- 如果指定的字段是中文的话,那么他们排序的规则是根据中文对应的ASCII码大小进行排序的,取反的话,就是在字段前面加上一个"-"即可
- order_by 中的属性要加上字符串符号''
- 获取单对象过滤器
- get() 返回单个满足条件的对象,一般用于通过主键来进行查找
- 如果未找到会引发"模型类.DoesNotExist"异常。
- 如果多条被返回,会引发"模型类.MultipleObjectsReturned"异常。
- count() 返回当前查询结果的总条数。
- aggregate() 聚合,返回一个字典,在后边再详细介绍
- 判断是空对象过滤器
- exists() 判断查询集中是否有数据,如果有则返回True,没有则返回False。
- 获取具体对象属性值的过滤器
- values() 返回获取到对象的指定属性的值(字典格式)
- values_list() 返回获取到对象的指定属性的值(元组格式)
- 想要获取的字段用字符串的形式传入''
- 注意:
- 过滤器中,可以传入多个字段的过滤条件,但是不能传入同一个字段的不同条件,需要用后面的条件查询和F对象和Q对象
- 一般的过滤器返回的都是一个列表,get() 返回对象、count()返回数字、aggregate()返回字典、exists()返回bool类型的数值、values() / values_list()返回元组和列表
- 条件查询
- 条件查询的格式:
- 属性名称__比较运算符=值
- 属性名称和比较运算符间使用两个下划线,所以属性名不能包括多个下划线这个格式组合起来的一个整体就是一个条件表达式
- 1.等查询:
- 规范写法:id__exact
- 示例:BookInfo.objects.filter(id__exact=1)
- 可以简写成BookInfo.objects.filter(id=1)
- 2.非查询:
- 示例:
- BookInfo.objects.exclude(id=1)
- 3.空查询
- 规范写法:id__isnull
- 示例:
- BookInfo.objects.filter(id__isnull=True)
- Ture为查询空的内容,False为查询非空内容
- 4.模糊查询
- 第一种:判断是否包含查询
- 规范写法:btitle__contains
- 示例:
- BookInfo.objects.filter(btitle__contains='天')
- 第二种:判断是不是以什么开头结尾查询
- 示例:
- BookInfo.objects.filter(btitle__startswith='天')
- BookInfo.objects.filter(btitle__endswith='传')
- 5.范围查询
- 第一种:获取具体位置的内容
- 规范写法:id__in
- 示例:
- BookInfo.objects.filter(id__in=[1,3])
- 第二种:获取一个区间范围的内容
- 规范写法:id__gt(大于)、id__gte(大于等于) 、id__lt(小于)、id__lte(小于等于)
- 示例:
- BookInfo.objects.filter(id__gte=1)
- 第三种:获取时间范围的内容
- 规范写法:bpub_date__gt=date(1990, 1, 1)
- 示例:
- BookInfo.objects.filter(bpub_date__gt=date(1990,1,1))
- data(1990,1,1)返回日期
- 6、固定日期相关查询
- 应用的格式:时间字段__时间关键字
- 常用的时间相关关键字:year、month、day、week_day、hour、minute、second
- 示例:
- BookInfo.objects.filter(bpub_date__year=1980)
- 注意:时间的值可以写单引号,也可以不写单引号, 比如上例中的1980
- 注意:
- exact、contains、startswith、endswith运算符都区分大小写
- 在这些运算符前加上i表示不区分大小写
- 如iexact、icontains、istartswith、iendswith
- 复杂的查询
- F对象
- F对象作用:
- 可以用来对一个记录对象的两个段进行比较后查询
- F对象的格式:
- from django.db.models import F
- F(属性名) 获取该条记录对象的字段数值
- 注意:属性名一定要有单引号
- 示例:
- BookInfo.objects.filter(bread__lt=F('bcomment')*2)
- Q对象
- Q对象的作用:
- 可以通过Q对象使用条件表达式来描述逻辑非(not)的关系,逻辑或(or)的关系
- Q对象格式:
- from django.db.models import Q
- Q(属性名__运算符=值) 与其他Q对象进行逻辑运算
- &表示逻辑与
- |表示逻辑或
- Q对象前可以使用~操作符,表示非not
- 示例:
- 逻辑与:BookInfo.objects.filter(Q(bread__gt=20) & Q(id__lt=3))
- 逻辑或:BookInfo.objects.filter(Q(bread__gt=20) | Q(pk__lt=3))
- 逻辑非:BookInfo.objects.filter(~Q(pk=3))
- 限制
- 什么是限制
- 就是对我们查询后的结果或者查询过滤器集合,进行进一步的条件约束限制,等同于sql中的limit和offset语句
- 常见使用限制的场景
- 对查询集进行取下标或切片操作。
- 对查询集进行切片后返回一个新的查询集,不会立即执行查询。
- 备注:限制查询不支持负数索引
- 聚合查询
- Django包含的聚合函数:
- Avg,Count,Max,Min,Sum,被定义在django.db.models中;
- 格式:
- aggregate(聚合函数('字段名'))
- 字段名要加上引号''
- 返回值得格式:
- 是一个字典类型---{'聚合类小写__属性名':值}
- 备注:使用count时一般不使用aggregate()过滤器,因为有专门的count()过滤器,返回值是一个数字类型
- 示例:
- from django.db.models import Sum
- BookInfo.objects.aggregate(Sum('bread'))
- 查询集的特性
- 过滤器的惰性
- 特性一:惰性
- 过滤器的惰性
- 创建查询集不会访问数据库,直到调用数据时,才会访问数据库,调用数据的情况包括迭代、序列化、与if合用等
- 特性二:缓存
- 过滤器的缓存
- 使用同一个查询集,第一次使用时会发生数据库的查询,然后把结果缓存下来,再次使用这个查询集时会使用缓存的数据。
- 使用过滤器缓存的场景
- 场景一:在两个列表表达式中,创建了两次查询集,无法使用缓存
- 场景二:查询集经过存储后,可以重用查询集,第二次使用缓存中的数据。
- 场景二中应用了过滤器的缓存功能
- 备注:
- 1.缓存的介绍:将我们查到的记录到一个临时位置,方便我们查看的效果就是缓存
- 2.缓存的作用:加快我们获取数据的效率,减轻数据库的压力。试想一下,如果我现在的数据库有大批量的人员访问就快崩溃了,如果这个时候,获取到的数据都存放在某一个地方,我们就不会去查数据库,那么数据库的压力是不是就大幅度降低啊
- 3.可以通过打开数据库的日志功能查看数据库的运行日志
- 之后我们便可以运行查询集来观察运行日志,可以发现当将查询集存储后,重复查询,不会再次对数据库进行操作
关系和关联
- 模型类之间的关联
- 关系类型-三种数据库表的关系
- ForeignKey:一对多,将字段定义在多的一端中。
- ManyToManyField:多对多,将字段定义在任意一端中。
- OneToOneField:一对一,将字段定义在任意一端中。
- 在模型类中配置关系的方式
- 一对多:models.ForeignKey('关联类名')
- 设置方法:
- 在多对应的模型类加上一条关联字段属性models.ForeignKey('关联类名')
- 结果:
- 会在设置关联的数据库表中增加一个 关联模型类属性名_被关联模型类主键属性 的字段
- 多对多:models.ManyToManyField('关联类名')
- 设置方法:
- 第一种:
- 手工创建一个包含两个表外键的字段属性和一个主键的字段属性的模型类
- 再在任意一个模型类中添加一个 多对多的配置属性,并制定关联的第三个表
- 示例:
- 在第三张表中添加如下类,给表的字段添加索引
- 第二种:
- 直接通过Django的功能帮我们生成第三张表,直接在任意模型类中添加属性
- 示例:
- 备注:两种创建的方式本质上和结果是一样的是一样的
- 一对一:models.OneToOneField('关联类名')
- 设置方法:
- 设置方法:
- 在任意一段的模型类加上一条关联字段属性OneToOneField('关联类名')
- 结果:
- 会在设置关联的数据库表中增加一个 关联模型类属性名_被关联模型类主键属性 的字段
- 关联查询语法(只介绍一对多的查询方法)
- 通过对象来查询
- 由一到多:
- 格式:一对应的模型类对象.多对应的模型类名小写_set.过滤器()
- 示例:
- b = BookInfo.objects.get(id=1)
- b.heroinfo_set.all()
- 由多到一:
- 格式:多对应的模型类对象.多对应的模型类中的关联类属性名
- 示例:
- h = HeroInfo.objects.get(id=1)
- h.hbook
- 由多到一(获取一实例对象的主键属性)
- 格式:多对应的模型类对象.多对应的模型关联类属性__一对应的主键
- 示例:
- h = HeroInfo.objects.get(id=1)
- h.hbook_id
- 通过类来查询
- 通过多的条件来查询一
- 语法:多模型类名小写__属性名__条件运算符=值
- 例子:list = BookInfo.objects.filter(heroinfo__hcontent__contains='八')
- 通过一的条件来查询多
- 语法:多模型类关联属性名__一模型类属性名__条件运算符=值
- 例子:list = HeroInfo.objects.filter(hbook__btitle='天龙八部')
- 模型类的自关联
- 设置表自关联的方法
- 通过指定外键字段的self属性,来告诉orm,创建自关联的字段;
- 示例:
- 结果:
- 会在数据库表结构中生成一个 设置关联类属性名_表主键名 的字段
- 父实例对象:被关联的记录实例对象
- 子实例对象:设置关联记录的实例对象
- 自关联查询方法
- 通过子对象来查询父对象
- 格式:子实例对象.关联字段类属性名
- 示例:
- area = AreaInfo.objects.get(id=1)
- area.aParent
- 通过父对象来查询子对象
- 格式:父实例对象.模型类名小写_set.过滤器()
- 示例:
- area = AreaInfo.objects.get(id=20)
- area.areainfo_set.all()
- 通过子对象查询父对象的主键值
- 格式:子实例对象.关联字段类属性名_主键字段
- 示例:
- area = AreaInfo.objects.get(id=1)
- area.aParent_id