Django-02-DjangoModel-01
Model
- 在企业开发中,我们通常都是从数据开始发的
Django模型
Django对各种数据库都提供了很好的支持,对不同的数据库,Django提供了统一调用的API,我们可以根据不同的业务需求使用不同的数据库。
配置数据库
pip install pymysql
在工程目录的init.py文件中输入
1 | import pymsql |
完成数据库驱动加载
在settings.py中配置数据库连接信息
1 | 'ENGINE':'django.db.backends.mysql', |
开发流程
1.配置数据库
2.定义模型类(一个模型类对应数据库中的一张表)
3.生成迁移文件
4.执行迁移生成数据表
5.使用模型类进行增删改查(CRUD)操作
ORM技术
- 对象关系映射
- 可以简单理解为翻译机
- 核心思想:解耦合
Django定义模型
重要概念:模型,表,属性,字段
一个模型类在数据库中对应一张表,在模型类中定义的属性,对应该模型对照表中的一个字段
定义属性见定义属性文件
定义属性
概述
django根据属性的类型确定以下信息
- 当前选择的数据库支持字段的类型
- 渲染管理表单时使用的默认html控件
- 在管理站点最低限度的验证
django会为表增加自动增长的主键列,每个模型只能有一-个主键列, 如果使用选项设置某属性为主键列后,则django不会 再生成默认的主键列
属性命名限制
- 遵循标识符规则
- 由于django的查询方式, 不允许使用连续的下划线
库
- 定义属性时,需要字段类型,字段类型,字段类型被定义在django.db .models.fields目录下, 为了方便使用,被导入到django .db. models中
- 使用方式
- 导入from django. db import models
- 通过models. Field创建字段类型的对象,赋值给属性
逻辑删除
- 对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField, 默认值为False
字段类型
- AutoField
- 一个根据实际ID自动增长的IntegerField,通常不指定。如果不指定,一个主键字段将自动添加到模型中
- CharEield (max_ length=字符长度)
- 字符串,默认的表单样式是TextInput
- TextField
- 大文本字段,一般超过4000使用,默认的表单控件是Textarea
- IntegerField整数
- DecimalField (max_ digits=None, decimal_ places=None)
- 使用python的Decima1实例表示的十进制浮点数
- 参数说明
- DecimalField.max_ digits
- 位数总数
- DecimalField.decimal _places
- 小数点后的数字位数
- DecimalField.max_ digits
- FloatField
- 用Python的float实例来表示的浮点数
- BooleanField
- true/false 字段,此字段的默认表单控制是CheckboxInput
- NullBooleanField
- 支持null、true、 false三种值
- DateField( [auto_ now=False,auto_ now_ add=False] )
- 使用Python的datetime .date实例表示的日期
- 参数说明
- DateField. auto_ now
- 每次保存对象时,自动设置该字段为当前时间,用于”最后- -次修改”的时间戳,它总是使用当前日期,默认为false
- DateField.auto_now add
- 当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false
- DateField. auto_ now
- 该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个”Today”的快捷按钮, 包含了一 个额外的invalid
- 注意
- auto_now_add, auto_now. and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果
- TimeField
- 使用Python的datetime . time实例表示的时间,参数同DateField
- DateTimeField
- 使用Python的datetime . datetime实例表示的日期和时间,参数同DateField
- FileField
- 一个上传文件的字段
- ImageField
- 继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image
- AutoField
字段选项
- 概述
- 通过字段选项,可以实现对字段的约束
- 在字段对象时通过关键字参数指定
- null
- 如果为True,Django 将空值以NULL存储到数据库中,默认值是False
- blank
- 如果为True,则该字段允许为空白,默认值是False .
- 注意
- null是数据库范畴的概念,blank是表单验证证范畴的
- db_ column
- 字段的名称,如果未指定,则使用属性的名称
- db_ index
- 若值为True, 则在表中会为此字段创建索引
- default
- 默认值
- primary_ key
- 若为True, 则该字段会成为模型的主键字段
- unique
- 如果为True, 这个字段在表中必须有唯一值
- 概述
关系
- 分类
- ForeignKey: 一对多,将字段定义在多的端中
- ManyToManyField:多对多,将字段定义在两端中
- OneTooneField:一对一 ,将字段定义在任意一端中
- 用一访问多
- 格式
- 对象.模型类小写_ set
- 示例
- grade .students_ set
- 格式
- 用一访问一
- 格式
- 对象.模型类小写
- 示例
- grade . students
- 访问id
- 格式
- 对象.属性_ id
- 示例
- student. sgrade_ id
- 格式
- 格式
- 分类
创建模型类
元选项,在模型类中定义Meta,用于设置元信息
1 | class Meta: |
示例
1 | class Person(models.Model): |
随后输入python manage.py makemigrations
生成迁移文件
以及python manage.py migration
执行迁移
结果
模型成员objects
Django默认通过模型的objects对象实现模型数据查询
Django有两种过滤器用于筛选记录
- filter:返回符合筛选条件的数据集
- exclude:返回不符合筛选条件的数据集
多个filter和exclude可以连接在一起查询(链式调用)例如:Person.objects.filter().filter().xxxx.exclude()...
示例
首先将数据模型建立好
首先在App中建立urls并在根路由中注册
然后在App.models.py中建立添加函数
1 | def add_persons(request): |
- 最后在App.models.py中建立查询函数
1 | def get_persons(request): |
- 渲染的网页界面
1 |
|
结果
注意
筛选出的结果类型为查询结果集
<class 'django.db.models.query.QuerySet'>
创建对象
目的
向数据库中添加数据
当创建对象时,django不会对数据库进行读写操作,当调用save()方法时才与数据库交互,将对象保存到数据库中
注意
_ init_ 已经在父 类models.Model中使用,在自定义的模型中无法使用
创建对象方案
在模型类中增加类方法去创建对象,是不会映射到表中的
1 |
|
在自定义的管理器中添加方法来创建对象
示例
因为
1 | def add_person(requset): |
所以在models.py文件里创建对象的类中写入以下函数
1 |
|
于是前面创建对象的函数就可以自定义了,例如:
1 | def add_person(requset): |
模型的查询
- 查询集表示从数据库获取的对象集合
- 查询集可以有多个过滤器
- 过滤器就是一个函数,基于所给的参数限制查询集结果
- 从SQL角度来说,查询集合和select语句等价,过滤器就像where条件
查询集和过滤器
- 在管理器上调用方法返回查询集
- 查询经过过滤器筛选后返回新的查询集,所以可以写成链式调用
- 返回查询集的方法称为过滤器
- all() 返回所有数据
- filter() 返回符合条件的数据
- exclude() 过滤掉符合条件的数据
- order. by() 排序
- values() 一条数据就是一个字典,返回一个列表
返回单个数据
get(): 返回一个满足条件的对象(坑)
- 如果没有找到符合条件的对象,会引发模型类.DoesNotExist异常
如果找到多个,会引发模型类.MultiObiectsReturned 异常
first(): 返回查询集中的第一个对象,使用:all().first()
last(): 返回查询集中的最后一个对象,使用:all().last()
- 隐藏bug:如果数据较乱,可能会出现first()和last()获取的是相同的对象
- 解决方案:显式,手动写排序规则
count():返回当前查询集中的对象个数
exists():判断查询集中是否有数据,如果有数据返回True没有反之
状态码
1开头
1xx(临时响应)表示临时响应并需要请求者继续执行操作的状态代码。代码说明
100 (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。
2开头
2xx (成功)表示成功处理了请求的状态代码。代码说明
200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201 (已创建) 请求成功并且服务器创建了新的资源。
202 (已接受) 服务器已接受请求,但尚未处理。
203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206 (部分内容) 服务器成功处理了部分 GET 请求。
3开头
3xx (重定向) 表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。代码说明
300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
4开头
4xx(请求错误) 这些状态代码表示请求可能出错,妨碍了服务器的处理。代码说明
400 (错误请求) 服务器不理解请求的语法。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
406 (不接受) 无法使用请求的内容特性响应请求的网页。
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408 (请求超时) 服务器等候请求时发生超时。
409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417 (未满足期望值) 服务器未满足”期望”请求标头字段的要求。
5开头
5xx(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。代码说明
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
限制查询集和查询集的缓存
限制查询集,可以使用下标的方法进行限制,等同于sql中limit和offset,即并不是全部查询之后再进行切割
studentList = Student.objects.all()[0:5] 下标不能是负数
查询集的缓存:每个查询集都包含一个缓存,来最小化对数据库的访问。只有我们在迭代结果集,或者获取单个对象属性的时候,才会去查询数据库。
在新建的查询集中,缓存首次为空,第一次对查询集求值,会发生数据缓存,django会将查询出来的数据做一个缓存, 并返回查询结构,以后的查询直接使用查询集的缓存。
字段查询
对sql中where的实现,作为方法filter(),exclude(),get()的参数
语法:属性名称__比较运算符=值(双下划线)
外键:属性名_ id
转义: like语句中 使用%是为了匹配占位,匹配数据中的%
( where like %‘ )
filter(sname contains=’%’)
比较运算符
exact:判断,大小写敏感,filter(isDelete = False)
contains:是否包含,大小写敏感,filter(sname__contains=’孔’)
startswith,endswith:以values开头或结尾, 大小写敏感以上四个在运算符前加上i(ignore)就不区分大小写了iexact…
isnull,isnotnull:是否为空,filter(sname__ jisnull=False)
in:是否包含在范围内,filter(pk__in=[2,4,6,8])
gt,gte,It,Ite:大于,大于等于,小于小于等于filter(sage__gt30)
时间的
year,month,day,week_day,hour,minute,second:
filter(lasttime__year=2020)坑:django中查询条件有时区问题
关闭django中自定义的时区
在settings中把
USE_TZ = True
改为USE_TZ = False
在数据库中创建对应的时区表
查询快捷:
pk:代表主键,filter(pk=1)跨关系查询:
模型类名__属性名__比较运算符, 实际上就是处理的数据库中的join
grade = Grade.objects.filter(student_ scontend_ _contains=’小小明’)
描述中带有“小小明”这三个字的数据属于哪个班级
聚合函数
使用aggregate()函数返回聚合函数的值,如Student.objects().aggregate(Max(‘sage’))
- Avg:平均值
- Count:数量
- Max:最大
- Min:最小
- Sum:求和
F对象
可以使用模型的A属性与B属性进行比较
grades = Grade.objects.filter(girlnum_ gt=F(‘boynum’) )
F对象支持算数运算
grades = Grade.objects.filter(girlnum gt=F(‘boynum’) +10 )
Q对象
过滤器的方法中的关键参数,可以对条件进行封装,常用于组合条件
- 年龄小于25
- Student.objects.filter(Q(sage_ _It=25))
- 年龄小于25,身高大于160
- Student.objects.filter(Q(sage_ It=25)&Q(sheight\ _gt=160))
Q对象语法支持| (or), & (and), ~(取反)
- 年龄大于等于的
- Student.objects.filter(~Q(sage_ _It=25))
模型成员
类属性
显性:开发者手动书写的属性
隐性: objects是一个Manager类型的一个对象,作用于数据库进行交互
当模型类没有指定管理器的时候,Django会自动为我们创建模型管理器当然我们也可以自定义管理器,
1
2class Student(models.Model):
stuManager = models.Manager()当自定义模型管理器时,objects就不存在了,Django就
不会为我们自动生成模型管理器
自定义管理器
模型管理器是Django的模型与数据库进行交互的接口,一个模型可以有多个模型管理器
自定义模型管理器作用:
- 可以向管理器中添加额外的方法
- 修改管理器返回的原始查询集
- 提供创建对象的方式
1 | class StudentManager(models.Manager): |