文章目录[隐藏]
模型
- Django 对各种数据库提供了很好的支持,Django为这些数据库提供了统一的调用API,可以根据不同的业务需求选择不同的数据库。
ORM
- 概述
- 对象-映射-模型
- 任务
- 根据对象的类型生成表结构
- 将对象、列表的操作转换为sql语句
- 将SQL语句查询的结果转换为对象、列表
- 优点
- 极大的减轻了开发人员的工作量,不需要面对因数据库的变更而修改代码
流程
配置数据库
- 在
__init__.py
文件中添加选定的数据库Package。
import pymysql
pymysql.version_info = (2,0,3,"final",0)
pymysql.install_as_MySQLdb()
- 在
settings.py
文件中修改数据库配置。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'sunck', # 数据库名
'USER': 'sunk', # 数据库用户名
'PASSWORD': 'sunk', # 数据库密码
'HOST': 'localhost', # 数据库主机
'PORT': '3306', # 数据库端口
}
}
在models.py 添加模型类
- 一个模型类都在数据库中对应一张表
定义模型
模型、属性、表、字段间的关系
- 一个模型类在数据库中对应一张表
- 模型类中定义的属性,对应模型对照表中的字段
定义属性
概述
- Django根据属性的类型确定以下信息
- 当前选择的数据库支持字段的类型
- 渲染管理表单时使用的默认html控件
- 在管理站点最低限度的验证
- Django会为表增加自动增加的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则Django不会再生成默认的主键列。
- 属性命名限制
- 不能是Python的保留关键字(遵循标识符命名规则)
- 由于Django的查询方式,不允许使用连续的下划线
库
- 定义属性时,需要字段类型,字段类型被定义再
django.db.modles.fields
目录下,为了方便使用,被导入到django.db.modles
中 - 使用方式:
- 导入
from django.db import models
- 通过
modles.Field
创建字段类型的对象,赋值给属性
- 导入
逻辑删除
- 对于重要数据都做逻辑删除 ,不能做物理删除,实现方法是定义
isDelete
属性,类型为BooleanField
,默认值为False
。
字段类型
字段类型 | 说明 |
---|---|
AutoField |
一个根据实际ID自动增长的IntergerField,通常不指定,如果不指定一个主键字段将自动添加到模型中 |
CharField(max_length=字符长度) |
字符串,默认的表单样式是TextInput |
TextField |
大文本字段,一般超过4000字节使用,默认的表单控件是textArea |
IntegerField |
整数 |
DecimalFiled(max_digits=None,decimal_places=None) |
使用Python的Decimal实例表示的十进制浮点数,max_digits表示位数总数,decimal_places表示小数点后的数字位数。[[精确的浮点运算-Decimal]] |
FloatField |
用Python的Float实例来表示的浮点数 |
BooleanField |
true/false字段,此字段的默认表单控制是CheckboxInput |
NullBolleanField |
支持null、true、false三种值 |
DateField([auto_now=False,auto_now_add=False]) |
使用Python的Datetime.date实例表示的日期,auto_now表示每次保存对象是,自动设置该字段为当前时间,用于“最后一次修改”的时间戳,它总是使用当前日期,默认为False。auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前时间,默认为False。说明:该字段默认对于表单控件是一个TextField,在管理员站点添加了一个JavaScript写的日历控件,和一个“Today”的快捷按钮,包含了一个额外的invalid_date错误消息键。注意:auto_now_add、auto_now、defalut这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果。 |
TimeField |
使用Python的datetime,datetime实例表示的日期和时间,参数同DateField |
FiledField |
一个上传文件的字段 |
ImageField |
继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是一个有效的image |
字段选项(字段参数)
- 概述:
- 通过字段选项,可以实现对字段的约束
- 在字段对象是通过关键字参数指定
- null
- 如果为True,Django将空值已NULL存储到数据库中,默认是False
- blanke
- 如果为True,则该字段允许为空白,默认值是False
- 注意:
- null是数据库范畴的概念,blank是表单验证范畴的
- db_column
- 字段的名称,如未指定,则使用属性的名称
- db_index
- 若值为True,则在表中会为此字段创建索引
- defalut
- 默认值
- primary_key
- 若为True,则该字段会成为模型的主键字段
- unique
- 若为True,则该字段的值必须唯一
关系
- 分类
- ForeignKey:一对多,将字段定义在多的端中
- ManyToManyField: 多对多,将字段定义在两端中
- OneToOneField:一对一,将字段定义在任意一端中。
- 用一访问多:
- 格式: 对象.模型类小写_set
- 示例:grade.students_set
- 用一访问一:
- 格式:对象.模型类小写
- 示例:grade.students
- 访问id:
- 格式:对象.属性_id
- 示例:student.sgrade_id
创建模型类
- 在
models.py
中创建即可
元选项
在模型类中定义一个
Meta
类,用于设置元信息(即信息)
- 属性
db_table
: 定义数据库表名,推荐使用小写字母。如果不写,数据表名默认为项目名小写_类名小写。ordering
: 对象的默认排序字段,获取对象的列表时使用。排序会增加数据库的开销。
class Students(models.Model):
sname = models.CharField(max_length=20)
sgender = models.BooleanField(default=True) # True表示男生,False表示女生
sage = models.IntegerField() # 年龄
scontend = models.CharField(max_length=20) # 简介
isDelete = models.BooleanField(default=False) # 是否删除
# 关联外键
sgrade = models.ForeignKey("Grades", on_delete=models.CASCADE) # 关联Grade表的主键
lastTime = models.DateTimeField(auto_now=True) # 最后修改时间
createTime = models.DateTimeField(auto_now_add=True) # 创建时间
def __str__(self):
return self.sname
# 元数据
class Meta:
db_table = "students" # 定义数据库表名
ordering = ["id"] # 指明排序方式
# ordering = ["-id"] # 降序
模型成员
类属性
objects
- 隐藏类属性
objects
: 是Manager类型的一个对象,作用是与数据库进行交互。- 当定义模型类时没有指定管理器,则Django为模型创建一个名为objects的管理器。
自定义管理器
- 自定模型管理器后,自定后object就不存在了。
class Students(models.Model):
stuObj = models.Manager(); # 自定义管理器 , 自定义后objects就不存在了。
自定义管理器Manager类
- 模型管理器时Django的模型进行预数据库交互的接口,一个模型可以有多个模型管理器。
- 作用:
- 向管理器类中添加额外的方法 ^a11ed7
- 修改管理器返回其的原始集合(查询集)
- 重写get_queryset()方法即可
- test case
class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentsManager, self).get_queryset().filter(isDelete=False)
class Students(models.Model):
stuObj = models.Manager() # 自定义管理器 , 自定义后objects就不存在了。
stuObj2 = StudentsManager() # 自定义管理器类
自定义属性
sname = models.CharField(max_length=20)
创建对象
- 目的:
- 向数据库中添加数据
- 当创建对象时,Django不会对数据库进行读写操作。当调用
save()
方式时才与数据库进行交互,将对象保存到数据库表中。 -
注意:
__init__
方法已经在父类models.Model
中使用,在定义模型中无法使用。
- 方法
- 在模型类中增加一个类方法
class Students(models.Model):
stuObj = models.Manager() # 自定义管理器 , 自定义后objects就不存在了。
stuObj2 = StudentsManager() # 自定义管理器类
sname = models.CharField(max_length=20)
sgender = models.BooleanField(default=True) # True表示男生,False表示女生
sage = models.IntegerField(db_column="age") # 年龄
scontend = models.CharField(max_length=20) # 简介
isDelete = models.BooleanField(default=False) # 是否删除
# 关联外键
sgrade = models.ForeignKey("Grades", on_delete=models.CASCADE) # 关联Grade表的主键
lastTime = models.DateTimeField(auto_now=True) # 最后修改时间
createTime = models.DateTimeField(auto_now_add=True) # 创建时间
def __str__(self):
return self.sname
# 元数据
class Meta:
db_table = "students" # 定义数据库表名
ordering = ["id"] # 指明排序方式
# ordering = ["-id"] # 降序
# 定义一个类方法创建对象
# cls 代表Student类
@classmethod
def createStudent(cls, name, age,gender,contented,grade,lastT,createT,isD=False):
stu = cls(sname = name,sage = age,sgender = gender,scontend = contented,sgrade = grade,lastTime=lastT,createTime = createT,isDelete = isD)
return stu
```
- 在自定义管理器类中添加一个方法 [[Django#^a11ed7]]
```python
class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentsManager, self).get_queryset().filter(isDelete=False)
def createStudent(self, name, age,gender,contented,grade,lastT,createT,isD=False):
stu = self.model() # 创建一个对象
print(type(stu))
stu.sname = name
stu.sage = age
stu.sgender = gender
stu.scontend = contented
stu.sgrade = grade
stu.lastTime = lastT
stu.createTime = createT
return stu
模型查询
概述
- 查询集表示从数据库获取的对象集合
- 查询集可以又多个过滤器
- 过滤器就是一个函数,基于所给的参数限制查询集结果
- 从sql角度来说,查询集合select语句等价,过滤器就像where条件
查询集
- 在管理器上调用过滤器方法返回查询集合
class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentsManager, self).get_queryset().filter(isDelete=False)
pass
- 查询集经过过滤器筛选后返回新的查询集,所以可以写成链式标准
xxx.filter(xxx).filter(xxx).xxx
- 惰性执行
- 创建查询集不会带来任何数据的访问,直到调用数据时,才会访问数据
- 直接访问数据的情况
- 迭代
- 序列化
- 与
if
合用
- 返回查询集(多个数据)的方法称为过滤器
all()
返回查询集中的所有数据filter()
返回符合条件的数据filter(键=值)
filter(键=值,键=值)
两者同时满足filter(键=值).filter(键=值)
两者同时满足
exclude()
过滤掉 符合条件的数据order_by()
排序values()
一条数据就是一个对象(字典),返回一个列表
- 返回单个数据
get()
返回一个满足条件的对象- 注意
- 如果没有找到符合条件对象,会引发模型类.DoesNotExist异常。
- 如果找到多个对象, 会引发“模型类.MultipleObjectsReturned”异常
- 注意
count()
返回当前查询集中的对象个数first()
返回当前查询集中的第一个对象last()
返回当前查询集中的最后一个对象exists()
判断查询集中是否有数据,如果有数据返回True,没有返回False
- 限制查询集
- 查询集是返回列表,可以使用下标的方法进行限制,等同于SQL中的LIMIT语句’
- 注意下标不能是负数
# 分页显示学生
def stupage(request,page):
# 0 - 5 , 5 - 10
page = int(page)
studentsList = Students.stuObj2.all()[(page-1)*5:page*5]
return render(request, 'myApp/students.html', {'students': studentsList})
- 查询集的缓存
- 概述
- 每个查询集都包含一个缓存,来最小化的对数据库访问
- 在新建的查询集中,缓存首次为空,第一次对查询集求值,会发生数据缓存,Django会将查询出来的数据做一个缓存,并返回结果,后续查询直接直接使用查询集的缓存。
- 概述
- 字段查询
- 概述:
- 实现了SQL中的WHERE语句,作为方法
filter(),exclude(),get()
的参数 - 语法:
属性名称__比较运算符=值
(注意是两个_) - 外键是比较特殊的:
属性名_id
- 转义:
- SQL中的like中使用%是为了匹配占位的,想匹配数据中的%(WHER LIKE '\%')
filter(sname__contains='%')
不需要转义
- 实现了SQL中的WHERE语句,作为方法
- 比较运算符
exact
- 判断,大小写敏感
filter(isDelete=False)
contains
- 是否包含,大小写敏感
startswith、endswith
- 以value开头或结尾,大小写敏感
- 以上四个在前面加上i,就表示不区分大小写。
iexact、icontains、istartswith、iendswith
isnull、isnotnull
- 是否为空
in
- 是否包含在范围内
gt,gte,lt,lte
- 大于、大于等于、小于、小于等于
year、month、day、week_day、hour、minute、second
- 日期
- 跨关联查询
- 处理join查询的
模型类名__属性名__比较运算符
- 查询快捷
- pk : 代表主键
- 聚合函数
- 使用
aggregate()
函数返回聚合函数的值 Avg
Count
Max
Min
Sum
- 使用
- F对象
- 可以使用模型的A属性与B属性进行比较(同一条数据的两个值进行比较)
Grades.objects.filter(ggirlnum__gt=F('gboynum'))
- 支持F对象的算术运算
gradesList = Grades.objects.filter(ggirlnum__gt=F('gboynum')+30)
- 可以使用模型的A属性与B属性进行比较(同一条数据的两个值进行比较)
- Q对象(解决或的关系)
- 概述
- 过滤器的方法中的关键字参数,条件为And模式
- 需求
- 进行OR查询
- 解决
- 使用Q对象
- 注意
- 只有一个Q对象时,就是用于匹配的
- 前面加
~
代表取非
- 概述
- 概述:
from django.db.models import Max,F,Q,Min,Avg,Sum
def studentsearch(request):
# studentsList = Students.stuObj2.filter(sname__contains="孙%")
# studentsList = Students.stuObj2.filter(sname__contains="孙") #包含孙
# studentsList = Students.stuObj2.filter(sname__startswith="张") #以张开头
# studentsList = Students.stuObj2.filter(pk__in=[2,4,6,8,10]) #in
# studentsList = Students.stuObj2.filter(sage__gte=30) #大于等于
studentsList = Students.stuObj2.filter(lastTime__year=2017) #年
grade = Grades.objects.filter(students__scontend__contains="薛延美") # 关联查询,描述中带有薛延美的学生是属于哪个班级?
print(grade)
maxAge = Students.stuObj2.aggregate(Max('sage'))
print(maxAge)
return render(request, 'myApp/students.html', {'students': studentsList})
def gradesF(request):
# get data
gradesList = Grades.objects.filter(ggirlnum__gt=F('gboynum'))
# send data to templates
# 将数据传递给模板,模板在渲染页面,模板将渲染好的页面返回给浏览器
return render(request, 'myApp/grades.html', {'grades': gradesList})
def studentsearch(request):
# studentsList = Students.stuObj2.filter(sname__contains="孙%")
# studentsList = Students.stuObj2.filter(sname__contains="孙") #包含孙
# studentsList = Students.stuObj2.filter(sname__startswith="张") #以张开头
# studentsList = Students.stuObj2.filter(pk__in=[2,4,6,8,10]) #in
# studentsList = Students.stuObj2.filter(sage__gte=30) #大于等于
# studentsList = Students.stuObj2.filter(lastTime__year=2017) #年
# studentsList = Students.stuObj2.filter(students__scontend__) #跨关联查询
studentsList = Students.stuObj2.filter(sname__contains="孙")
maxAge = Students.stuObj2.aggregate(Max('sage'))
print(maxAge)
return render(request, 'myApp/students.html', {'students': studentsList})
def studentQ(request):
studentsList = Students.stuObj2.filter(Q(pk__lte=3) | Q(sage__gte=30))
# studentsList = Students.stuObj2.filter(Q(pk__lte=3)) # 只有一个Q对象时,就是用于匹配的
# studentsList = Students.stuObj2.filter(~Q(pk__lte=3)) # 取非
return render(request, 'myApp/students.html', {'students': studentsList})
删除/更新
- 查询到后,del对象在save即可删除
- 查询到后,更新对象内容再save即可更新。