一、django
对各种数据库提供了很好的支持,django为这些数据库提供了统一的调用API,可以根据不同的业务需求选择不同的数据库
二、配置数据库
(1)修改工程文件(project)下__init__.py文件
import pymysql
pymysql.install_as_MySQLdb()
(2)修改settings.py文件
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'sunck', #你的数据库名称
'USER': 'root', #你的数据库用户名
'PASSWORD': '123456', #你的数据库密码
'HOST': '', #你的数据库主机,留空默认为localhost
'PORT': '3306', #你的数据库端口
'OPTIONS': {
'init_command': "SET sql_mode='traditional',default_storage_engine=INNODB;"#设置数据库为INNODB,为第三方数据库登录用
},
}
}
三、开发流程
(1)配置数据库
(2)定义模型
一个模型类都在数据库中对应一张数据表
(3)生成迁移文件
(4)执行迁移生成数据表
(5)使用模型类进行增删改查
四、ORM
1、概念
对象-关系-映射
2、任务
(1)根据对象的类型生成表结构
(2)将对象、列表的操作转换为sql语句
(3)将sql语句查询到的结果结果转换为对象、列表
3、优点
极大的减轻了开发人员的工作量,不需要面对面对数据库的变更而修改代码
4、图解(如下图)
五、定义模型
1、模型、属性、表,字段间的关系
一个模型在数据库中对应一张表,在模型类中定义的属性对应该模型对照表中的一个字段
2、定义属性
(1)概述
1)django根据属性类型确定以下信息
- 当前选择的数据库支持字段的类型
- 渲染管理表单时使用的html控件
- 在管理站点最低限度的验证
2)django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
3)属性命名限制
- 遵循标识符规则
- 由于django的查询方式,不允许使用连续的下划线(两个也不行)
(2)库
1)定义属性时, 需要字段类型, 字段类型被定义在django.db. models.fields目录下,为了方便使用,被导入到django.db.models中
2)使用方式
- 导入from django.db import models
- 通过models.Field创建字段类型的对象,赋值给属性
(3)逻辑删除
对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete
属性,类型为BooleanField,默认值为False
字段类型(字段选项)
(4)字段类型
1)models.AutoField()
- 一个根据实际ID自动增长的IntegerField, 通常不指定
- 如果不指定,一个主键字段将自动添加到模型中
2)CharField(max_ length=字符长度)
字符串,默认的表单样式是TextInput
3)models.TextField()
大文本字段,一般超过4000字节使用,默认的表单控件是Textarea
4)models.IntegerField()
整数
5)DecimalField(max_digits=None, decimal_places=None)
- 使用python的DecimalField实例表示的十进制浮点数3.1415926----->DecimalField(8,7)
- 参考说明
(1)DecimalField.max_digits位数总数
(2)DecimalField.decimal_places小数点后的数字位数
6)FloatField
用python的float实例来表示的浮点数
7)BooleanField(default=False默认否)或者(default=True默认是)
true/false字段,此字段的默认表单控制是CheckboxInput
8) NullBooleanField
支持null、true、 false三种值
9)DateField[auto_now=False, auto_now_ add=False ])
- 使用Python的datetime.date实例表示的日期
- 参数说明
(1)DateField.auto_now
每次保存对象时,自动设置该字段为当前时间,用于
最后一次修改”
的时间戳,它总是使用当前日期,默认为false
(2)DateField.auto_now_add
当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false - 说明
该字段默认对应的表单控件是一个TextInput。在管理员站点添加了一个JavaScript写的日历控件,和一个"Today"的快捷按钮,包含了一个额外的invalid_date错误消息键 - 注意
auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果,写一个就行
10)TimeField
使用Python的datetime.time实例表示的时间,参数同DateField
11)DateTimeField
使用Python的datetime .
datetime实例表示的日期和时间,参数同DateField
12)FileField
一个上传文件的字段
13)ImageField
继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image(传的是一个图片)
(5)字段选项
1)概述
通过字段选项,可以实现对字段的约束
在字段对象时通过关键字参数指定
2)null
如果为True, Django 将空值以NULL 存储到数据库中,默认值是False
3)blanke
.如果为True, 则该字段允许为空白,默认值是False
4)注意
null是数据库范畴的概念,blank 是表单验证证范畴的
5)db_ column
字段的名称,如果未指定,则使用属性的名称sage=models.IntegerField(db_column=“age”),数据库中age,这里还是sage
6)db_ index
若值为True, 则在表中会为此字段创建索引
- default
默认值
8)primary_key
若为True,则该字段会成为模型的主键字段
9)unique
若为True,这个字段在表中必须有唯一值
(6)关系
1)分类
- ForeignKey:一对多,将字段定义在多的端中
- ManyToManyField; 多对多,将字段定义在两端中
- OneToOneField: 一对一,将字段定义在任意一端中
2)用一访问多
- 格式
对象.模型类小写_ set - 示例
grade . students_ set
3)用一访问一
- 格式
对象.模型类小写 - 示例
grade.students
4)访问id
- 格式
对象.属性_id - 示例
student.sgrade_id
3、创建模型类
想要更改模型内容
(1)删除此数据库
(2)再重建此数据库
(3)删除迁移文件(firstapp/migrations目录下0001_initial.py文件)
(4)执行迁移文件(project目录下输入python manage.py makemigrations)
(5)再迁移(project目录下输入python manage.py migrate)
添加班级数据
mysql> select *from grades; >3;
+----+------------+----------------------------+------+----------+
| id | gname | gdate | gnum | isDelete |
+----+------------+----------------------------+------+----------+
| 1 | 计算机一班 | 2012-02-04 00:00:00.000000 | 30 | 0 |
| 2 | 计算机二班 | 2012-02-04 00:00:00.000000 | 30 | 0 |
| 3 | 财务管理 | 2012-02-04 00:00:00.000000 | 30 | 0 |
| 4 | 市场营销 | 2012-02-04 00:00:00.000000 | 30 | 0 |
+----+------------+----------------------------+------+----------+
添加学生数据
mysql> select *from students;
+----+--------+---------+------+------------+----------+-----------+
| id | sname | sgender | sage | scontend | isDelete | sgrade_id |
+----+--------+---------+------+------------+----------+-----------+
| 1 | 薛艳梅 | 0 | 20 | 我叫薛艳梅 | 0 | 1 |
| 2 | 向方 | 0 | 21 | 我叫向方 | 0 | 1 |
| 3 | 孔雨 | 1 | 21 | 我叫孔雨 | 0 | 2 |
| 4 | 孟林 | 1 | 20 | 我叫孟林 | 0 | 3 |
| 5 | 夏明 | 1 | 20 | 我叫夏明 | 0 | 2 |
| 6 | 孙艳 | 0 | 19 | 我叫孙艳 | 0 | 3 |
| 7 | 田宝 | 1 | 20 | 我叫田宝 | 0 | 4 |
+----+--------+---------+------+------------+----------+-----------+
4、元选项
在模型中定义一个Meta类,用于设置元信息
把之前的firstapp_grades改成grades,firstapp_students改成students
- db_table 定义数据表名,推荐使用小写字母,数据表明默认
“项目名小写_类名小写”(如db_table=“students”) - ordering=[] 对象的默认排序字段,或许对象的列表时使用
ordering=[“id”] ------- 升序
ordering=[“-id”] ------- 降序
注意:排序会增加数据库的开销
#在班级类最后添下面两条代码,会把之前的firstapp_grades改成grades
class Meta:
db_table="grades"
#在学生类最后添下面两条代码,会把之前的firstapp_students改成students
class Meta:
db_table="students"
ordering=["id"]
具体如下图:
在数据库中数据表名显示出来,如下图
六、模型成员
1、类属性
sname,sgender,sage,scontend等等都是类属性
(1)objects
- objects---->是Manager类型的一个对象,作用是与数据库进行交互
- 当定义模型类没有指定管理器,则django为模型创建一个名为objects的管理器
>>> from firstapp.models import Students
>>> stu=Students.objects.get(pk=1)
>>> stu
<Students: 薛艳梅>
>>> stu.sage=22
>>> stu.save()
mysql> select *from students;
+----+--------+---------+------+------------+----------+-----------+
| id | sname | sgender | sage | scontend | isDelete | sgrade_id |
+----+--------+---------+------+------------+----------+-----------+
| 1 | 薛艳梅 | 0 | 22 | 我叫薛艳梅 | 0 | 1 |
| 2 | 向方 | 0 | 21 | 我叫向方 | 0 | 1 |
| 3 | 孔雨 | 1 | 21 | 我叫孔雨 | 0 | 2 |
| 4 | 孟林 | 1 | 20 | 我叫孟林 | 0 | 3 |
| 5 | 夏明 | 1 | 20 | 我叫夏明 | 0 | 2 |
| 6 | 孙艳 | 0 | 19 | 我叫孙艳 | 0 | 3 |
| 7 | 田宝 | 1 | 20 | 我叫田宝 | 0 | 4 |
+----+--------+---------+------+------------+----------+-----------+
(2)自定义模型管理器
当我们为模型指定模型管理器,django就不再为模型类生成objects模型管理器
class Grades(models.Model):
#自定义模型管理器
#当自定义模型管理器时,objects就不存在了
stuObj=models.Manager()
>>> from firstapp.models import Students
>>> stu=Students.stuObj.get(pk=1)
>>> stu
<Students: 薛艳梅>
>>> stu.sage=22
>>> stu.save()
(3)自定义模型管理器Manager类
- 模型管理器时django的模型进行与数据库进行交互的接口,一个模型类可以有多个模型管理器
- 作用
(1)可以向管理器类中添加额外的方法
(2)修改管理器返回的原始查询集
重写get_queryset()方法,比如可以过滤掉已经删除的学生,薛艳梅显示已删除,isDelete为1
>>> stu=Students.objects.all()
>>> stu
#下面的统称查询集,数据库中所有都拿出来,并没有进行过滤
<QuerySet [<Students: 薛艳梅>, <Students: 向方>, <Students: 孔雨>, <Students: 孟林>, <Students: 夏明>, <Students: 孙艳>, <Students: 田宝>]>
class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentsManager,self).get_queryset().filter(isDelete=False)
class Students(models.Model):
#自定义模型管理器
#当自定义模型管理器时,objects就不存在了
stuObj=models.Manager()
stuObj2=StudentsManager()
#自定义模型管理器,objects就不存在了
>>> stu=Students.objects.all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: type object 'Students' has no attribute 'objects'
>>> stu=Students.stuObj.all()
>>> stu
#下面的统称查询集,数据库中所有都拿出来,并没有进行过滤
<QuerySet [<Students: 薛艳梅>, <Students: 向方>, <Students: 孔雨>, <Students: 孟林>, <Students: 夏明>, <Students: 孙艳>, <Students: 田宝>]>
>>> stu=Students.stuObj2.all()
>>> stu
#stuObj2则过滤掉已经删除的学生,薛艳梅显示已删除,isDelete为1
<QuerySet [<Students: 向方>, <Students: 孔雨>, <Students: 孟林>, <Students: 夏明>, <Students: 孙艳>, <Students: 田宝>]>
2、创建对象
(1)目的:
向数据库中添加数据
(2)当创建对象时,django不会对数据库进行读写操作,当调用save()方式时才与数据库进行交互,将对象保存在数据库表中
(3)注意:
__ init__.py方法已经在父类models.Model中使用,在自定义的模型中是无法使用
(4)方法
1)在模型类中增加一个类方法
#在学生类下定义下面类方法,注意使用@classmethod
#定义一个类方法创建对象,装饰器表明下面的定义的是类方法
@classmethod
def createStudent(cls,name,gender,age,contend,grade,isD=False):
stu = cls(sname=name,sgender=gender,sage=age,scontend=contend,isDelete=isD,sgrade=grade)
return stu
在views.py最下面添加
from .models import Students,Grades
def addstudent(request):
grade=Grades.objects.get(pk=1)
stu =Students.createStudent("刘美美",0,34,"我叫刘美美",grade)
stu.save()
return HttpResponse('avnjka')
在firstapp.py/urls.py文件下添加路径
path('addstudent/',views.addstudent)
输入网址http://localhost:8000/firstapp/addstudent/
得到下图,表示models.py中数据添加成功
2)在自定义管理器中自定义一个方法,正好应对属性类中自定义管理器Manager类,可以排除掉已经删除了的学生
class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentsManager,self).get_queryset().filter(isDelete=False)
def createStudent(self,name,gender,age,contend,grade,isD=False):
stu=self.model()
stu.sname=name
stu.sgender=gender
stu.sage=age
stu.scontend=contend
stu.sgrade=grade
return stu
在views.py最下面添加
def addstudent2(request):
grade=Grades.objects.get(pk=1)
stu =Students.stuObj2.createStudent("刘梅",0,34,"我叫刘梅",grade)
stu.save()
return HttpResponse('********')
在firstapp.py/urls.py文件下添加路径
path('addstudent2/',views.addstudent2)
在网页http://localhost:8000/firstapp/addstudent2/
得到如下图,证明学生信息添加成功
七、模型查询
1、概述
(1)查询集表示从数据库中获取的对象集合
(2)查询集可以有多个过滤器
(3)过滤器就是一个函数,基于所给的参数限制查询集结果
(4)从sql角度来说,查询集和select语句等价,过滤器就像是where条件
2、查询集
下面是返回所有查询集
return super(StudentsManager,self).get_queryset()
(1)在管理器上调用过滤器方法返回查询集
class StudentsManager(models.Manager):
def get_queryset(self):
return super(StudentsManager,self).get_queryset().filter(isDelete=False)
(2)查询集经过过滤器筛选后返回新的查询集,所以我们可以写成链式调用
super(StudentsManager,self).get_queryset().filter(isDelete=False).filter()...#还可以往后再写
(3)惰性执行-------创建查询集不会带来任何数据的访问,直到调用数据时,才会访问数据库(也是为了提高性能)
(4)直接访问数据的情况
- 迭代
- 序列化
- 与if合用
(5)返回查询集的方法称为过滤器(返回多条数据)
-
all()返回查询集中的所有数据
-
filter(),返回符合条件的数据
(1)filter(键=值)
(2)filter(键=值,键=值) (两个键值对是且的关系)
(3)filter(键=值).filter(键=值) -
exclude() 返回不符合条件的数据
-
order_by() 排序
-
values() 一条数据就是一个对象(字典),返回一个列表,
(6)返回单个数据
- get ()----- 返回一个满足条件的对象
注意:(1)如果没有找到符合条件的对象,会引发“模型类.DoesNotExist”异常
(2)如果找到多个对象,会引发“模型类.MultipleObjectsReturned”异常
比如在views.py中studentsList=Students.stuObj2.get(sgender=True),
性别都为男,对象很多 - count()-----返回当前查询集中的个数Grades.objects.count()
- first()-----返回查询集中的第一个对象
- last()------返回查询集中的最后一个对象
- exists()----判断查询集中是否有数据,如果有数据,返回True
Grades.objects. exists()
(7)限制查询集–查询集返回列表,可以使用下标的方法,进行限制等同于sql中的limit语句,
studentsList=Students.stuObj2.all()[0:5]#取五行数据,在views.py中添加
注意:下标不能是负数
1、在firstapp/views.py文件下,添加下面这些数据
from .models import Students,Grades
#分页显示学生
def stupage(request,page):
#0-3 3-6 6-9
#1 2 3
#page*3
page=int(page)
studentsList=Students.stuObj2.all()[(page-1)*3:page*3]
return render(request,'firstapp/students.html',{"students":studentsList})
2、在firstapp/urls.py文件下,添加下面代码
path('stu/<int:page>',views.stupage),
3、输入网址在http://localhost:8000/firstapp/stu/1
4、输入网址在http://localhost:8000/firstapp/stu/2
5、输入网址在http://localhost:8000/firstapp/stu/3
(8)查询集的缓存
概述
- 每个查询集都包含一个缓存,来最小化的对数据库访问
- 在新建的查询集中,缓存首次为空,第一次对查询集求值(访问数据),会发生数据缓存,django会将查询出来的数据做一个缓存,并返回查询结果,以后的查询直接使用查询集的缓存
(9)字段查询–参数
1、概念
- 实现了sql中的where语句,作为方法filter(),exclude(),get()的参数
- 语法:属性名__比较运算符=值(模型类中对应的属性)(比如:
sage__>=20
年龄大于20的) - 外键:属性名_id(如:
sgrade_id
) - 转义:sql中的like语句中使用%是为了匹配占位,匹配数据中的%(where like “%”)(模糊查询)
在过滤器中使用filter(sname__contains="%")
2、比较运算符
- (1)exact----判断,区分大小写,类似filter(isDelete=False)
- (2)contains----是否包含,区分大小写,filter(sname__contains=“刘”)
#在firstapp/views.py文件下添加下面这些代码
from .models import Students,Grades
def studentsearch(request):
#显示名字里面含有刘字的学生信息
studentsList=Students.stuObj2.filter(sname__contains="刘")
return render(request,'firstapp/students.html',{"students":studentsList})
在firstapp/urls.py文件下添加
path('studentsearch/',views.studentsearch),
输入http://localhost:8000/firstapp/studentsearch/
网址,显示名字里面含有刘字的学生信息
- (3)startswith、endswith----以value开头或者结尾,区分大小写,filter(sname__startswith=“田”)
#在firstapp/views.py文件下
from .models import Students,Grades
def studentsearch2(request):
#显示名字里面以田字开头的学生信息
studentsList=Students.stuObj2.filter(sname__startswith="田")
return render(request,'firstapp/students.html',{"students":studentsList})
在firstapp/urls.py文件下添加
path('studentsearch2/',views.studentsearch2),
输入http://localhost:8000/firstapp/studentsearch2/
网址,显示名字里面以田字开头的学生信息
- (4)以上四个在前面加上i,就表示不区分大小写,iexact、icontains、istartswith、iendswith
- (5)isnull、isnotnull ----是否为空,filter(sname__isnull=False)
- (6) in -----是否包含在范围内
#在firstapp/views.py文件下
from .models import Students,Grades
def studentsearch3(request):
#获取pk在2,4,6里面的学生信息
studentsList=Students.stuObj2.filter(pk__in=[2,4,6])
return render(request,'firstapp/students.html',{"students":studentsList})
在firstapp/urls.py文件下添加
path('studentsearch3/',views.studentsearch3),
输入http://localhost:8000/firstapp/studentsearch3/
- (7)gt----大于、gte----大于等于、lt----小于、lte----小于等于
#年龄大于20的学生信息,只有下面部分替换,其余部分类似
studentsList=Students.stuObj2.filter(sage__gt=20)
- (8)year、month、day、week_day、hour、minute、second
#创建时间是2020的班级信息
gradesList=Grades.objects.filter(gdate__year=2020)
- (9)跨关联查询
处理join查询----语法:模型类名__属性名__比较运算符
def grades(request):
#描述中带有'刘美美'这三个字的数据是属于哪个班级的
gradesList=Grades.objects.filter(students__scontend__contains='刘美美')
return render(request,'firstapp/grades.html',{"grades":gradesList})
- (10)查询快捷----pk----代表的主键
3、聚合函数
想用哪个聚合函数需要引用
#五个里面,用哪个引用哪个
from django.db.models import Avg,Count,Max,Min,Sum
- 使用aggregate( )函数,返回聚合函数的值
- (1)Avg----平均值
- (2)Count----和
- (3)Max----
maxAge=Students.stuObj2.aggregate(Max('sage'))
- (4)Min
- (5)Sum
4、F对象
- 可以使用模型的A属性与B属性进行比较,比如某个班级男生人数(A)和女生人数(B)进行比较
filter(ggirlnum__gt=F('gboynum'))
- 支持F对象的算数运算
filter(ggirlnum__gt=F('gboynum')+20)
需要引入F,Q
(1)
from django.db.models import F,Q
def grades1(request):
#查看女生人数大于男生人数的班级,需要在models.py文件里面,班级下面,添加ggirlnum,gboynum这两个属性
g=Grades.objects.filter(ggirlnum__gt=F('gboynum'))
print(g)
return HttpResponse("oooooo")
(2)
from django.db.models import F,Q
def grades1(request):
#查看(女生人数)大于(男生人数+20)的班级,需要在models.py文件里面,班级下面,添加ggirlnum,gboynum这两个属性
g=Grades.objects.filter(ggirlnum__gt=F('gboynum')+20)
print(g)
return HttpResponse("oooooo")
5、Q对象
- 概述:过滤器的方法中的关键字参数,条件为And模式
- 需求:进行or查询
- 解决:使用Q对象
studentsList=Students.stuObj2.filter(Q(pk__lte=2))
----只有一个Q就是用于匹配的studentsList=Students.stuObj2.filter(~Q(pk__lte=2))
----取反
from django.db.models import F,Q
def students(request):
#pk<2或者年龄大于23 的学生信息
studentsList=Students.stuObj2.filter(Q(pk__lte=2) | Q(sage__gt=23))
return render(request,'firstapp/students.html',{"students":studentsList})