#前言:
关于Django我在此片博客之前已经发布了六篇博客,感兴趣的可以在主页查看学习与交流。此篇博客我会讲解在Django中数据库的一些操作,如若各位大佬发现错误或者需要添加的内容,欢迎各位指正,最后我后续还会继续更新关于Django的一些基本内容,欢迎大家关注。
一、数据库及其在开发中的地位介绍:
关于数据库,最简单最浅显的认知就是它是用来存储数据和管理数据的一门学科,但是关于数据库的认知可不止如此。
1.数据库系统(DBS):
从广义上来讲数据库系统它由四部分组成,分别是数据库、硬件、软件、人员组成。而数据库系统它是采用了数据库技术,有组织地、动态的存储大量数据,方便用户访问的计算机系统。
注意:数据库属于数据库系统。
1、数据库:
数据库是统一管理的、长期储存在计算机内的、有组织的相关数据的集合。其特点是数据间联系密切、冗余度小、独立性较高、易扩展,并且可为各类用户共享。
2、硬件:
硬件是构成计算机系统的各种物理设备,包括存储数据所需的外部设备。硬件的配置应满足整个数据库系统的需要。
3、软件:
软件包括操作系统、数据库管理系统及应用程序。其中数据库管理系统是最为重要的一个点,也是数据库这门学科中的核心内容。数据库管理系统它是数据库系统的核心软件,需要在操作系统的支持下工作,解决如何科学地组织和储存数据。
4、人员:
人员主要有4类。
第一类为系统分析员和数据库设计人员,系统分析员负责成用系统的需求分析和规范说明,他们和用户及数据库管理员一起确定系统的硬件配置,并参数据库系统的概要设计。
第一类为应用程序员,负责编写使用数据库的应用程序,这些应用程序可对数据进行检索、建立、删除或修改。
第三类为最终用户,他们应用系统的接口或利用查询语言访问数据库。
第类用户是数据库管理员(Data Base Administrator,DBA),负责数据库的总体信息控制。
2.数据库系统的体系结构:
数据库系统是数据密集型应用的核心,其体系结构受数据库运行所在的计算机系统的影响很大,尤其是受计算机体系结构中的连网、并行和分布的影响。从不同的角度或不同层次上看数据库系统体系结构不同;从最终用户的角度看,数据库系统体系结构分为集中式)分布式C/S(客户端/服务器)和并行结构。
1.集中式数据库系统:
在这种系统中,不仅数据是集中的,数据的管理也是集中的,数据库系统的所有功能(从形式的用户接口到DBMS 核心)都集中在 DBMS 所在的计算机上,如下图所示。大多数关系 DBMS 的产品也是从这种系统结构开始发展的,目前这种系统还在使用。
2.客户端/服务器结构(C/S):
这种结构非常重要,它就是体现数据库在前后端中作用最好的实例。
很多现代软件都采用客户端/服务器体系结构,如下图所示。在这种结构中,一个处理机(客户端)的请求被送到另一个处理机(服务器)上执行。其主要特点是客户端与服务器 CPU之间的职责明确,客户端主要负责数据表示服务,服务器主要负责数据库服务。采用客户端/服务器结构后,数据库系统功能分为前端和后端。前端主要包括图形用户界面、表格生成和报表处理等工具;后端负责存取结构、查询计算和优化、并发控制以及故障恢复等。前端与后端通过SQL或应用程序来接口。
3.并行数据库系统:
并行体系结构的数据库系统是多个物理上连在一起的 CPU)而分布式系统是多个地理上分开的 CPÙ。
4.分布式数据库系统:
分布式 DBMS包括物理上分布,逻辑上集中的分布式数据库结构和物理上分布、逻辑上布的分布式数据库结构两种。
上述主要从介绍了数据库系统的角度来介绍了数据库在实际开发中的地位。
二、数据库在Django中的实际应用:
以Mysql为实例:
1、ORM:
ORM 是 django 提供的内置框架,是和一些关系型数据库的连接接口,使用类对象的方式操作数据(增删改查)。ORM 将类对象的操作语句转换为 SQL 语句,接着进入到数据库中获取结果,最后将结果转为对象的格式返回。
模型是项目的数据来源,模型类映射到数据库中的表,模型类中的每一个属性相当于表中的字段。
在 Django 中配置 MySQL 数据库 , 先在 MySQL 中创建好数据库(空)【一个数据库只能连接一个项目】。
在数据库自己已经创建好的Django文件中找到setting.py文件,找到DATABASE:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',#配置数据库引擎
'HOST':'127.0.0.1',#主机
'USER':'root',#数据库没创建前一般叫root(用户名)
'PASSWORD':'',#自己数据库的密码
#配置连接对数据库,数据库在连接前必须被创建好
'NAME':'orm_13',#自己数据库的名字
}
}
2、模型类:
关于模型类主要包括三大操作:
定义模型类 、数据迁移 、通过类对象进行操作数据。
1.定义模型类:
定义模型类 , 模型类都必须继承 Model 类。模型类定义在应用中的 models 文件。
from django.db import models
class Student(models.Model):
# 定义属性,数据表中的字段
# name char(10)
# CharField 定义字符串字段,这个类型字段必须定义最大长度
# max_length 定义字段的最大长度
name = models.CharField(max_length=10)
# age int()
# IntegerField 定义整型字段
age = models.IntegerField()
# height float/double(3 , 2)
# DecimalField 定义浮点类型
# max_digits 浮点型的数据长度
# decimal_places 浮点型小数位数
height = models.DecimalField(max_digits=3, decimal_places=2)
# gender enum('男','女')
# 设置选择字段的选项值
gender_choices = (
#(选项字符 , 选项内容)
('1' , '女'),
('2' , '男'),
)
gender = models.CharField(choices=gender_choices , max_length=1)
上述代码主要介绍的就是定义模型类的方法,其中关于整形、浮点型或者字符型是啥,或者其它类型怎么表示,我在下面列一个表:
字段类型:
字段类型 | 说明 |
---|---|
AutoField | 自动增量,32位整数。取值:1 ~ (2^31)-1 |
BigAutoField | 自动增量,64位整数。取值:1 ~ (2^63)-1 |
BigIntegerField | 64位整数。取值:-2^63 ~ (2^63)-1。字段默认表单控件为TextInput |
BinaryField | 存储原始的二进制数据 |
BooleanField | 存储True或者False,字段默认表单控件为CheckboxInput |
CharField | 存储字符串。字段默认表单控件为TextInput |
DateField | 存储日期,字段值为datetime.date实例。字段默认表单控件为TextInput;参数auto_now 表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为False;参数auto_now_add 表示当对象第一次 被创建时自动设置当前时间,用于创建的时间戳,它总使用当前日期,默认为False;参数auto_now_add 和auto_now 是相互排斥的, 组合将会发生错误. |
DateTimeField | 存储日期时间,字段值为datetime.datetime实例。字段默认表单控件为TextInput |
DecimalField | 存储固定精度的十进制数字段,字段值为Decimal实例。字段默认表单控件为NumberInput;参数max__digits 表示总位数,参数decimal__places 表示小数位数 |
DurationField | 存储时间段 |
EmailField | 存储E-mail地址 |
FileField | 存储文件,字段默认表单控件为ClearableFileInput |
FilePathField | 存储文件路径 |
FloatField | 存储浮点数。字段默认表单控件为NumberInput |
ImageField | 存储图片。字段默认表单控件为ClearableFileInput |
IntegerField | 存储整数。取值:-2^31 ~ (2^31)-1 |
GenericIPAdderssField | 存储字符串格式的IPv4或者IPv6地址。字段默认表单控件为TextInput |
PositiveIntegerField | 存储非负整数,取值:0~ (2^31)-1 |
PositiveSmallIntegerField | 存储非负小整数。取值:0~ (2^15)-1 |
SmallIntegerField | 存储小整数 , 取值范围-2^15 ~ (2^15)-1 |
TextField | 存储大量文本。字段默认表单控件为Textarea |
TimeField | 存储时间。字段值为datetime.time实例 ,字段默认表单控件为TextInput |
URLField | 存储URL。字段默认表单控件为TextInput |
SlugField | 存储Slug数据 , 只包含字母、数字 、下换线或连字符 |
而其它细节在代码中的注释中都有提及。
2.数据迁移:
定义好模型类之后,必须进行数据迁移,数据库中才能同步到对应的数据表。
数据迁移要在项目的终端操作,在 manage.py 的同级目录下操作。
然后输入:
python manage.py makemigrations
3.数据同步:
执行 migrate 命令 ,将模型类同步到数据库中。
同上在上述操作后继续在终端输入:
python manage.py migrate
4.注意:
1.在定义模型类的时候没有给其定义数据表的表名,在迁移同步到数据库中之后,这个表的表名会默认设置为:应用名_模型类名。
2.只要操作到 models.py 文件中的内容,就必须执行数据迁移和数据同步两个操作。
迁移过了之后增加字段,必须给新增的字段设置默认值,或者允许为空【null 设置是否允许为空(True/False),default 设置默认值】
ORM 在执行迁移数据的时候,会自动生成一个为主键且自增的id字段。
同时应该设置在数据库中的表名:(注意它是同属于模型类之下的)
class Meta:
# 设置在数据库中的表名
db_table = 'student'#以student为例子
如果发生迁移报错的问题如何解决,我在上一篇博客中已经做了详细介绍,有兴趣的可以点击它直达:Pycharm中使用mysqlclient(Django)-CSDN博客。
3、数据操作:
1、使用 raw 方法操作原始 SQL:
from OrmApp1.models import Student
# 增加数据
sql = "insert into student(name , age , height , gender , weight)values" \
"('陈一' , 18 , 1.65 , '2' , 98.2),('刘二' , 19 , 1.75 , '2' , 178.2)"
# 将 sql 语句交给 raw 方法执行
# 通过模型类对象的方式进行操作
add_data = Student.objects.raw(sql)
# 对这个操作的返回值对象进行提交(增删改)
add_data.query._execute_query()
# 修改数据
sql = "update student set age=20 where id=2"
update_data = Student.objects.raw(sql)
update_data.query._execute_query()
# 删除数据
sql = 'delete from student where id=1'
delete_data = Student.objects.raw(sql)
delete_data.query._execute_query()
# 查询数据
sql = "select * from student"
# RawQuerySet 数据查询集,是一个对象
data = Student.objects.raw(sql)
print(data)
# 获取对象中的某个数据,需要使用循环
for i in data:
# 获取到选项字段的具体数据:对象.get_字段名_display()
print(i.name , i.age , i.get_gender_display())
上述代码中就是用raw方法来操作增删改查SQL数据 ,具体细节在代码的注释中。
2、直接执行原始的 SQL 语句:
与pymysql操作类似:
from django.db import connection
# 创建游标
cursor = connection.cursor()
sql = "insert into student(name , age , height , gender , weight)values" \
"('陈一' , 18 , 1.65 , '2' , 98.2)"
cursor.execute(sql)
sql = "select * from student"
cursor.execute(sql)
data = cursor.fetchall()
print(data)
3、使用 django 提供的模型方法:
# 添加数据
# 方式一:会有返回值,是一个数据对象
add_data= Student.objects.create(name='张三' , age=25 , height=1.55 , gender='1' , weight=102.3)
print(add_data)
# 方式二:这种方式添加数据必须执行保存的方法
data = Student(name='李四' , age=35 , height=1.85 , gender='2' , weight=162.3)
data.save()
# 查询数据
# all 查询表中的所有数据
data = Student.objects.all()
# QuerySet 返回一个查询集对象
print(data)
for d in data:
print(d.name, d.age, d.get_gender_display())
print('='*20)
# filter 相当于 where 子句
data = Student.objects.filter(gender='2')
for d in data:
print(d.name, d.age, d.get_gender_display())
4、字段选项(总结):
选项 | 说明 |
---|---|
Null | 默认为False。为True时,Django在字段没有数据时将空值NULL存储数据库(字符串字段存储空字符串) |
blank | 默认为False。为True时,字段允许为空,即表单验证允许输入空值。blank影响数据验证,null影响数据库数据存储 |
choices | 为字段定义选择项。字段值为选项中的列表或者元组的值 |
db_column | 定义字段在数据库表中的列名称,为设置时,Django用模型中的字段名作为数据库表的列名称 |
db_index | 为True时,为该字段创建数据库索引 |
db_tablespace | 若为字段创建了索引,则为字段索引设置数据库的表空间名称 |
default | 设置字段默认值 |
editable | 默认是True。为False时,字段不在模型表单中显示 |
error_messages | 设置错误提示信息。该设置会覆盖默认的错误提示信息 |
help_text | 设置字段的帮助信息 |
primary_key | 设置为True时,字段成为模型的主键 |
unique | 设置为True时,字段值在整个表中必须是唯一的 |
unique_for_date | 设置日期或者日期时间字段名,关联的两个字段值在整个表中必须是唯一的 |
unique_for_month | 类似unique_for_date。与关联的月份唯一 |
unique_for_year | 类似unique_for_date。与关联的年份唯一 |
verbose_name | 为字段设置备注名称 |
validators | 为字段设置校验器 |
5、字段查找类型(总结):
查找类型 | 说明 |
---|---|
exact | 完全符合。例如:question_exact='text' 等同于where question='text' |
iexact | 与exact类似,但不区分字母大小写 |
contains | 包含,区分字母大小写。例如question_contains = 'text' 等同于 where question like '%text%' |
icontains | 包含,不区分字母大小写 |
in | 在指定项中进行匹配。例如id_in = [3,5] 等同于 where id in(3,5),表达式可以是列表、元组、字符串、也可以是filter()、exclude()和get()等方法返回的包含当个字段值的查询集(QuerySet) |
gt | 大于。例如id_gt = 3 等同于 where id >3 |
gte | 大于等于。例如id_gte = 3 等同于 where id >=3 |
lt | 小于。例如id_lt = 3 等同于 where id <3 |
lte | 小于等于。例如id_lte = 3 等同于 where id <=3 |
startswith | 匹配字符串开头,区分大小写。例如question_startswith = 'text' 等同于 where question like 'text%' |
istartswith | 匹配字符串开头,不区分大小写。例如question_istartswith = 'text' |
endswith | 匹配字符串结尾,区分大小写。例如question_endswith = 'text' 等同于 where question like '%text' |
iendswith | 匹配字符串结尾,不区分大小写。例如question_iendswith = 'text' |
range | 范围测试。例如id_range(1 , 5) 等同于 where id between 1 and 5 |
date | 查找datetime字段。例如rgDate_date = datetime.date(2023,5,31),可以和其他字段查找类型结合使用。例如rgDate_date_gt = datetime.date(2023,5,31) |
time | 查找datetime字段。例如rgDate_data = datetime.time(10,30),可以和其他字段查找类型结合使用。例如rgDate_data_gt = datetime.time(10,30) |
isnull | 取值True或者False,测试数据是否为NULL。例如:question_isnull = True 等同于 where question is NULL |
regex | 使用正则表达式进行匹配,区分大小写。例如,question_regex = "^[a-z0-9]*" |
iregex | 使用正则表达式进行匹配,不区分大小写。例如,question_iregex = "^[a-z0-9]*" |
三、多表关系:
关于表与表之间的关系无非就为三种:一对一、一对多、多对多。
1、一对一关系:
表与表之间一对一这种关系最为核心的思想就是其中表的外键和另外一个表的主键之间建立一种联系。
具体操作:以下述代码为例子,创建一个people的表和idcard的表,此时在‘idcard’表中设立外键与‘people’表的主键建立联系。
具体细节详细见下述代码注释:
class People(models.Model):
name = models.CharField(max_length=10)
class Meta:
db_table = 'people'
class IdCard(models.Model):
ID_card = models.CharField(max_length=18)
# 创建外键 , 建立和 People 表的一对一关系
# OneToOneField: 一对一关系的字段
# to : 设置关联的模型类名称
# on_delete=models.CASCADE:设置级联删除 , 主表中删除数据从表有关联的数据也会被删除掉
# 在模型类中创建的是属于外键对象
# 设置关系之后会自动的关联对象表中的 id 字段 , 生成一个外键字段,外键字段的名称:外键对象名_id
pel = models.OneToOneField(to='People' , on_delete=models.CASCADE)
class Meta:
db_table = 'idcard'
而此时创建好表之后要对表增加数据:
from OrmApp3.models import People , IdCard
# 主表数据:People
p1 = People.objects.create(name='谢bro')
p2 = People.objects.create(name='皓月当空')
p3 = People.objects.create(name='林谋')
p4 = People.objects.create(name='zero')
p5 = People.objects.create(name='车神')
# 从表数据:IdCard
# 使用外键字段添加关系
c = IdCard.objects.create(ID_card='20240322' , pel_id=1)
c = IdCard.objects.create(ID_card='20240323' , pel_id=3)
c = IdCard.objects.create(ID_card='20240324' , pel_id=4)
# 使用外键对象添加关联数据
# 获取 People 表中的数据对象
p = People.objects.get(id=2)
# 外键对象的值必须是一个对象类型的数据
c = IdCard.objects.create(ID_card='20250322' , pel=p)
更改数据:
# 更改关系
# 先获取要关联的主表中的数据对象
p = People.objects.get(id=5)
# 获取从表中要更改关系的数据对象
c = IdCard.objects.get(id=3)
#通过外键对象,修改外键对象值
c.pel_id = p
c.save()
删除数据:
# 删除数据
p = People.objects.get(id=2).delete()
# (2, {'OrmApp3.IdCard': 1, 'OrmApp3.People': 1})
print(p)
2、一对多关系:
一对多关系同样也是在表与表主键和外键之间建立一种能够多对一的关系。
class BJ(models.Model):
name = models.CharField(max_length=10)
class Meta:
db_table = 'bj'
class Students(models.Model):
stu_name = models.CharField(max_length=10)
# ForeignKey 创建一对多的关系
# related_name 设置反向数据操作 , 主表要操作从表的数据直接使用这个值,
# 如果没有设置 就要使用 , 小写的模型类名称_set
bj = models.ForeignKey(to='BJ' , on_delete=models.CASCADE , related_name='sub')
class Meta:
db_table = 'students'
3、多对多关系:
多对多关系同样也是在表与表主键和外键之间建立一种能够多对多的关系,例如学生与所学科目之间的关系就是这种多对多关系。
class Shet(models.Model):
name = models.CharField(max_length=10)
class Meta:
db_table = 'shet'
class Stus(models.Model):
stu_name = models.CharField(max_length=10)
# ManyToManyField: 创建多对多的外键对象
# 数据迁移同步之后,在数据库中会自动的创建一个外键关系表,表名:模型类名称_外键对象名
sh = models.ManyToManyField(to='Shet')
class Meta:
db_table = 'stus'
四、分页器:
数据分页 , 使用 Paginator 类实现数据分页。
from django.core.paginator import Paginator
# Paginator(可迭代对象 , 每一页允许出现的最大数据条数)
ls = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
# 制作分页器
p = Paginator(ls , 4)
# 查询数据分页的总页数
print(p.num_pages)
# 获取到数据的总条数
print(p.count)
# 获取到每一页的迭代对象
print(p.page_range)
# 获取分页器对象中的某一页内容对象
page = p.page(3)
# 获取到页面的数据
print(page.object_list)
# 查询当前对象的页数
print(page.number)
# 判断是否有上一页
print(page.has_previous())
# 判断是否有下一页
print(page.has_next())
# 获取上一页的页码
print(page.previous_page_number())
# 获取下一页的页码
print(page.next_page_number())
五.总结:
该篇博客先介绍了数据库及其在开发中的地位,然后介绍了数据库在Django中的实际应用(ORM、模型类、数据操作、字段选项的总结、字段查找类型的总结),其次介绍了三种表的关系(一对一、一对多、多对多),最后介绍了分页器。如若各位大佬发现问题或者需要补充的地方,欢迎指正,后续我还会继续更新关于Django的其它内容,欢迎大家关注我等后续更新。