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('')



django中的objects.get和objects.filter方法的区别

Django之models查询参数及聚合函数

posted @ 2021-01-17 15:12  mkay  阅读(773)  评论(0编辑  收藏  举报