Django3—数据库&查询数据
一、使用传统pymysql执行与sqlite区别
①使用pymysql执行原生sql语句来操作数据
1.sql语句比较复杂,且不好管理
2.sql语句安全性无法保持
3.数据库创建、数据表生成、数据添加以及数据迁移等非常麻烦
4.sql语句性能不够好
②使用ORM框架创建数据库
mysql中的对象
1.数据库
需要手动创建数据库
2.数据表
a.与ORM中的模型类一一对应
b.在子应用的models.py中定义模型类
3.字段
a.与模型类的类属性一一对应
4.记录
a.与模型类对象一一对应
二、在django中创建数据库
1、settings.py中
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
# 指定数据库的配置信息
DATABASES = {
# 使用的默认数据库信息
'default': {
'ENGINE': 'django.db.backends.sqlite3',
# a.指定使用的数据库引擎(使用哪种类型数据库?)
# 'ENGINE': 'django.db.backends.mysql',
# b.指定数据库名称
'NAME': BASE_DIR / 'db.sqlite3',
# 'NAME': 'my_django',
# c.指定数据库的用户名
# 'USER': 'root',
# d.指定数据库的密码
# 'PASSWORD': '123456',
# e.指定数据库主机地址
# 'HOST': 'localhost',
# f.指定数据库的端口号
# 'PORT': 3306
}
}
2. models.py中
a.定义模型类必须继承Model或者Model子类,一个模型类相当于一个table
b.定义的类属性(Field对象)为表中的字段信息
c.默认表名为子应用名_模型类名小写
d.默认会自动创建一个id主键(自增、非空)
e.生成迁移脚本:python manage.py makemigrations 子应用名
f.生成的迁移脚本会自动放置到子应用的migrations目录中
g.执行迁移脚本:python manage.py migrate 子应用名
from django.db import models # Create your models here. class People(models.Model): name = models.CharField(max_length=20) age = models.IntegerField()
生成迁移脚本:python manage.py makemigrations 子应用名,生成migrations文件夹,里面是迁移脚本
执行迁移脚本:python manage.py migrate 子应用名
执行后可看到生成的DB,如果没有sqlite驱动,按提示下载
from django.db import models class People(models.Model): """ a.定义模型类必须继承Model或者Model子类,一个模型类相当于一个table b.定义的类属性(Field对象)为表中的字段信息 c.默认表名为子应用名_模型类名小写 d.默认会自动创建一个id主键(自增、非空) e.生成迁移脚本:python manage.py makemigrations 子应用名 f.生成的迁移脚本会自动放置到子应用的migrations目录中 g.执行迁移脚本:python manage.py migrate 子应用名 """ name1 = models.CharField(max_length=20) age = models.IntegerField() class Projects(models.Model): # 一个数据库模型类中只允许定义一个设置了primary_key=True的字段 # 一旦某个字段设置了primary_key=True,那么ORM框架就不会自动创建id主键 # num = models.IntegerField(primary_key=True) id = models.AutoField(primary_key=True, verbose_name='id主键', help_text='id主键') # a.CharField指定varchar类型 # b.CharField必须得设置max_length参数,指定最大长度 # c.verbose_name与help_text指定中文的描述,在admin后台站点以及在接口文档平台中会使用到 # d.unique=True设置唯一约束,默认unique=False name = models.CharField(verbose_name='项目名称', help_text='项目名称', max_length=20, unique=True) leader = models.CharField(verbose_name='项目负责人', help_text='项目负责人', max_length=10) # e.default指定当前字段的默认值 is_execute = models.BooleanField(verbose_name='是否开展', help_text='是否开展', default=True) # f.null指定当前字段是否允许保持null空值 # g.blank指定前端在创建数据时是否允许不输入 desc = models.TextField(verbose_name='项目描述信息', help_text='项目描述信息', null=True, blank=True, default='') # DateTimeField指定日期时间类型 # a.auto_now_add=True,在创建一条数据时,会自动将当前时间赋值给create_time,只修改一次 # b.auto_now=True,每次在更新数据时,会自动将当前时间赋值给update_time,只要修改就会自动更新 create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间', help_text='创建时间') update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间', help_text='更新时间') class Meta: # a.可以在Meta内部类中修改当前表的元数据信息 # b.指定创建的数据表名称 db_table = 'tb_projects' # c.指定创建的数据表中文描述信息 verbose_name = '项目表' verbose_name_plural = '项目表' def __str__(self): return self.name
from django.db import models # 表与表之间有哪些关联关系? # Projects与Interfaces表,一对多的关系 # 学生表与学生详细信息表,一对一的关系 # 学生表与课程表,多对多的关系 # 一条项目数据:id为1的测试开发平台项目 # 多条接口数据:id为1的登录接口、id为2的注册接口、id为3的生成用例的接口 class Interfaces(models.Model): id = models.AutoField(primary_key=True, verbose_name='id主键', help_text='id主键') name = models.CharField(verbose_name='接口名称', help_text='接口名称', max_length=15, unique=True) tester = models.CharField(verbose_name='测试人员', help_text='测试人员', max_length=10) # a.可以使用ForeignKey在从表中指定外键字段,在一对多关系中‘多’的那侧添加外键字段 # b.ForeignKey第一个参数,需要指定关联的父表,往往使用'子应用名.父表模型类名' # c.必须指定on_delete级联删除策略 # d.级联删除策略有如下种类: # CASCADE:当父表数据删除之后,对应的从表数据会被自动删除 # SET_NULL:当父表数据删除之后,对应的从表数据的外键字段会被自动设置为null # PROTECT:当父表数据删除时,如果存在对应的从表数据,那么会抛出异常 # SET_DEFAULT:父表数据删除之后,对应的从表数据的外键字段会被自动设置为default参数指定的值 # 创建创建数据表时,会自动创建projects_id作为字段名,用于存放父表外键值 # ForeignKey: 一对多 # OneToOneField:一对一 # ManyToManyField:多对多 projects = models.ForeignKey('projects.Projects', on_delete=models.CASCADE) create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间', help_text='创建时间') update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间', help_text='更新时间') class Meta: db_table = 'tb_interfaces' verbose_name = '接口表' verbose_name_plural = '接口表' def __str__(self): return self.name
添加数据
一、创建(C)
方式一:
a.直接使用模型类来创建模型对象
b.必须调用save()方法才会执行sql语句(提交)
one_project = Projects(name='XXX金融项目11', leader='大脑斧', desc='这是一个描述')
one_project.save()
方式二:
a.可以使用模型类.objects为manager对象
b.可以使用manager对象.create方法(关键字参数)
c.无需调用save方法,会自动提交
one_project = Projects.objects.create(name='XXX在线商城项目11', leader='开始', desc='xxx描述')
添加子表数据
Interfaces(name='登录接口', tester='Aaron', projects_id=one_project.id)
one_interface = Interfaces(name='登录接口', tester='Aaron', projects=one_project)
one_interface = Interfaces.objects.create(name='登录接口', tester='Aaron', projects=one_project)
二、更新数据(U)
方式一:
a.所有的模型类,会有一个默认的objects属性,是一个manager对象
b.获取需要修改的模型类对象之后,重写相应的字段
c.必须得调用save()方法,才会提交
one_project = Projects.objects.get(id=5)
one_project.name = 'XXX在线商城项目22'
one_project.save()
方式二:
a.先将待修改的数据取出(查询集对象)
b.然后调用update()方法
c.无需调用save()方法,会自动提交
qs = Projects.objects.filter(id=5).update(leader='唯一')
三、查询(R)
1.读取多条数据
a.使用模型类.objects.all()
b.返回QuerySet对象,类似于列表,但不是列表
c.QuerySet对象,惰性查找,只有需要用到数据(len、取值、for)时,才会执行sql语句
d.QuerySet对象中为模型类对象(数据)
project_qs = Projects.objects.all()
for pro in project_qs:
print(pro.name)
print(list(project_qs))
2.读取一条数据
方式一:
a.可以使用模型类.objects.get()
b.如果查询的结果为空,那么会抛出异常
c.如果查询的结果超过一条数据,也会抛出异常
d.get方法,往往会使用主键或者唯一键作为查询条件
e.返回模型类对象(数据)
one_project = Projects.objects.get(id=1)
pk为django模型类内置的一个属性,是主键的别名
one_project = Projects.objects.get(pk=1)
one_project = Projects.objects.get(Projects.objects.get(leader='大脑斧'))
方式二:
a.模型类.objects.filter方法
b.返回QuerySet对象
c.如果查询的结果为空,那么会返回空的QuerySet对象
d.如果查询的结果超过一条,也会返回多条结果所在的QuerySet对象
e.字段名__查询类型=具体值
f.查询类型种类?
gt >
gte >=
lt <
lte <=
in 对处于列表中的值进行过滤
contains 包含
icontains 包含,忽略大小写
startswith 以xxx开头
istartswith 以xxx开头,忽略大小写
endswith 以xxx结尾
iendswith 以xxx结尾,忽略大小写
isnull 是否为空
qs = Projects.objects.filter(id=4)
qs = Projects.objects.filter(pk=4)
qs = Projects.objects.filter(id__exact=4)
qs = Projects.objects.filter(id__in=[1, 3])
qs = Projects.objects.filter(name__contains='金融')
qs = Projects.objects.filter(update_time__gt='2021-01-18')
exclude与filter为反向关系
qs = Projects.objects.filter(id__gt=3)
qs = Projects.objects.exclude(id__lte=3)
取出某个项目所属接口名称中包含'登录'的项目
关联查询
关联模型类名小写__关联模型类中的字段名__查询类型=具体值
关联模型类名1小写__关联模型类1中的外键名__关系模型类2中的字段名__查询类型=具体值
qs = Projects.objects.filter(interfaces__name__contains='登录')
qs = Interfaces.objects.filter(name__contains='登录')
使用外键字段,可以取出父表中对应的模型类对象
one_project = qs[0].projects
return HttpResponse(one_project)
QuerySet查询集的特性
1、惰性查询
2、链式调用
a.查询集对象可以多次调用filter方法,进行过滤
b.多个filter中的过滤条件为与的关系
c.在一个filter方法中,可以写多个条件,每个条件之间以“逗号”分割,每个条件为与的关系
3、哪些操作会让查询集执行sql语句? 查询集支持哪些操作?
a.通过数字索引取值,但不支持负值索引
b.支持切片操作
c.支持.first()方法,可以取出查询集中的第一个元素,为模型类对象
d.支持.last()方法,可以取出查询集中的最后一个元素,为模型类对象
e.支持len(查询集对象),获取查询集的长度,也可以使用.count()方法
f.支持.exists()方法,来判断查询集中是否有元素,如果有元素,那么返回True,否则返回False
g.支持for循环迭代
qs = Projects.objects.filter(name__contains='商城')
逻辑关系
a.与的关系
one = qs.filter(leader='唯一')
qs = Projects.objects.filter(name__contains='商城').filter(leader='唯一')
qs = Projects.objects.filter(name__contains='商城', leader='唯一')
b.或的关系
可以使用Q对象来实现逻辑关系查询
多个Q对象之间使用|,为或的关系
多个Q对象之间使用&,为与的关系
qs = Projects.objects.filter(Q(name__contains='商城') | Q(leader='大脑斧'))
排序操作
a.默认是以id主键升序来排序的
b.查询集对象.order_by('字段名1','字段名2')
c.默认指定的字段名为升序
d.可以在字段名的前面添加-,代表以降序来排序
删除操作(D)
方式一:
调用模型类对象中的delete()方法
one_project = Projects.objects.get(pk=1)
one_project.delete()
方式二:
使用查询集对象.delete(),可以将查询集中的所有数据删除
one = Projects.objects.filter(name__contains='商城').delete()
names = ['登录接口', '注册接口', '订单接口', '购物车接口']
for i in range(20):
random_str = ''.join(random.sample(string.ascii_letters + string.digits, 8))
interface_name = random.choice(names) + random_str
Interfaces.objects.create(name=interface_name, tester='Aaron', projects_id=random.choice([2, 3, 4, 5]))
a.values和annotate为固定用法
b.聚合运算需要设置为从表名小写
c.使用外键id作为关联条件,同时会把外键id作为分组条件
d.默认查询id和聚合运算的值
e.聚合运算的别名会自动设置为从表名小写__聚合函数名小写
f.可以给聚合运算设置关键词参数,会作为聚合运算的别名
qs = Projects.objects.values('id').annotate(Count('interfaces'))
qs = Projects.objects.values('id').annotate(interfaces=Count('interfaces'))
qs = Projects.objects.annotate(interfaces=Count('interfaces'))
return HttpResponse('')