ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

ORM框架2-数据库操作

2022-07-23 23:35:31  阅读:182  来源: 互联网

标签:Student 框架 数据库 ORM list objects student print name


数据库操作

操作对象: orm/view.py # orm为创建的子应用

from django.db import models


# 模型类必须要直接或者间接继承于 models.Model
class BaseModel(models.Model):
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    # SQL:created_time datetime(6) null comment="创建时间"

    updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    # SQL:updated_time datetime(6) null comment="更新时间"

    # auto_now_add 当数据添加时设置当前时间为默认值
    # auto_now= 当数据添加/更新时, 设置当前时间为默认值

    class Meta(object):
        abstract = True  # 设置当前模型为抽象模型, 当系统运行时, 不会认为这是一个数据表对应的模型.


# Create your models here.
class Student(BaseModel):
    SEX_CHOICES = (
        (0, "女生"),
        (1, "男生"),
        (2, "保密"),
    )
    # 以类属性的方式声明表结构的字段
    # 属性名 = models.数据类型(db_column="表字段名", max_length=最大长度, db_index=是否为当前字段创建普通索引, verbose_name="中文提示")
    # 注意:db_column属性如果不写则默认使用属性名作为表的字段名进行对应
    # django中默认会自动给模型创主键名为ID,所以我们一般不需要手动创建
    # 如果要手动创建主键ID则代码如下:
    # id = models.BigAutoField(primary_key=True, verbose_name="主键")  # django会自动在创建数据表的时候生成id主键/还设置了一个调用别名 pk
    # SQL: id bigint primary_key auto_increment not null comment="主键",
    name = models.CharField(max_length=20, db_index=True, verbose_name="姓名")
    # SQL: name varchar(20) not null comment="姓名"
    # SQL: index(name),

    age = models.SmallIntegerField(verbose_name="年龄")
    # SQL: age smallint not null comment="年龄"

    sex = models.BooleanField(default=0, verbose_name="性别", help_text="辅助提示")
    # SQL: sex tinyint not null default 0 comment="性别"

    # sex = models.SmallIntegerField(choices=SEX_CHOICES, default=2, verbose_name="性别")
    # SQL = sex smallint not null default 2 comment="性别"

    classmate = models.CharField(db_column="class", max_length=5, db_index=True, verbose_name="班级")
    # SQL: class varchar(5) not null comment="班级"
    # SQL: index(class)

    description = models.TextField(blank=True, null=True, verbose_name="个性签名")
    # SQL: description longtext default "" null comment="个性签名"


    class Meta:  # 子类中,可以针对当前模型类对应的数据设置一些独立的选项
        db_table = "tb_student"  # 设置当前Student模型对象对应的数据库的表名, 如果没有指定表名,则默认为子应用目录名_模型名称,例如: student_student
        verbose_name = '学生信息表'  # 在admin站点中显示的名称
        verbose_name_plural = verbose_name  # 显示的复数名称

    # 3. 自定义数据库操作方法
    def __str__(self):
        """定义每个数据对象的显示信息"""
        return "<User %s>" % self.name
orm/models.py

1 增加数据

方法 描述 代码
save 通过创建模型类对象,执行对象的save()方法保存到数据库中。
from django.views import View
from django.http import HttpResponse
from .models import Student


class Student1(View):
    def get(self, request):
        """添加一条数据"""
        # ORM对于数据的所有操作都是有子类objects来提供的。objects,可以被修改,开发中一般叫objects为"模型管理器"
        student = Student(
            name="刘德华",
            age=17,
            xingbie=True,
            classmate=301,
            description="一杯忘情水",
        )
        # 自动执行添加数据
        student.save()
        # 添加后的模型会多出一个主键数据,可以通过id或者pk来读取
        print(student.id)  # print(student.pk)
        return HttpResponse('ok')
create 通过模型类.objects.create()保存。
# 返回值就是添加后的模型对象,会有ID主键的
student = Student.objects.create(
    name="赵本山",
    age=50,
    sex=True,
    classmate=301,
    description="一段小品"
)
print(student)# <User 赵本山>
print(student.pk) 
return HttpResponse('ok')
bulk_create 通过模型类.objects.bulk_create()批量添加数据
stu1 = Student(name="小黄1号", age=17, xingbie=True, classmate=301, description="hello")
stu2 = Student(name="小黄2号", age=17, xingbie=False, classmate=301, description="hello")
stu3 = Student(name="小黄3号", age=17, xingbie=True, classmate=301, description="hello")
stu_list = [stu1,stu2,stu3]
ret = Student.objects.bulk_create(stu_list)
print(ret)
return HttpResponse('ok')

2 基本查询

方法 描述 代码
get

查询单一结果,如果不存在或者返回多个结果会抛出异常。

查询不到, 则返回模型类.DoesNotExist异常。

查询多个, 则返回模型类.MultipleObjectsReturned异常。

    def get(self,request):
        """基本查询数据"""
        """get 获取一条数据"""
        try:
            student = Student.objects.get(name="小黄")
            print(student, type(student))
            print(student.name)
            print(student.description)
        except Student.DoesNotExist:
            print("没有查询结果!")
        except Student.MultipleObjectsReturned:
            print("当前数据不是唯一的结果!")
        return HttpResponse("OK")
first 查询一个结果, 查询不到,则返回None,查询多个,返回查询结果列表的第一个。
def get(self, request):
        student = Student.objects.first()
        # SQL: select * from tb_student limit 1;
        print(student) # <User 赵华>
        if student:  # 判断如果student不是None
            print(student.description)
        return HttpResponse('ok')
all 查询所有结果。查询不到,则返回空列表对象。默认为all
def get(self, request):
    student_list = Student.objects.all()
    print(student_list)       # 获取结果列表 <QuerySet [<Student: <User 赵华>>,
    print(len(student_list))  # 获取结果列表的长度

    # 把结果列表中的所有模型对象转化成字典结构
    student_list = Student.objects.all().values()
    print(student_list) # <QuerySet [{'id': 1,

    # 把结果列表中的所有模型对象转换成元组结构
    student_list = Student.objects.all().values_list()
    print(student_list) # <QuerySet [(1,

    """使用filter查询过滤数据,并返回所有符合条件的结果
    filter(字段名=条件值)
    filter(字段名=条件值, 字段名=条件值)  # 相当于and
    """
    student_list = Student.objects.filter(classmate=302).all()
    print(student_list)
    return HttpResponse('ok')

3 更新数据

方法 描述 代码
save 修改模型类对象的属性,然后执行save()方法同步到数据库中
    def get(self, request):
        # 先把要更新的数据查询出来,得到一个模型类对象
        student = Student.objects.filter(name="小白").first()
        # SQL: select * from tb_student where name='小白' limit1;
        if student:
            student.name = "小黑"
            student.age = 18
            student.save()  # 把当前模型的中字段值同步到数据库
        return HttpResponse('ok')
update 使用模型类.objects.filter().update(),基于update来完成更新满足条件的所有数据,结果是受影响的行数
    def get(self, request):
        """update 更新多条数据"""
        # 基于update这种操作在数据库操作中,一般称之为"乐观锁" update操作的执行效率比save要高!
        # update如果条件设置宽松,可以修改多条数据
        Student.objects.filter(name="刘德华").update(name="刘福荣")
        # SQL: update tb_student set name="刘福荣" where name="刘德华";
        return HttpResponse('ok')

4 删除数据

方法 描述 代码
模型类对象.delete() 删除一条
        student = Student.objects.filter(name="小白").first()
        if student:
            # 调用模型对象的delete方法进行删除
            student.delete()
模型类.objects.filter().delete() 删除多条
Student.objects.filter(name="小黄").delete()

5 过滤条件

ORM在内部生成SQL中的where子句时,提供3个方法可以帮我们实现where过滤操作,包括:

  • filter 过滤出符合条件的多个结果

  • exclude 排除掉符合条件的多个结果,与filter相反,与filter互斥。

  • get 过滤单一结果, 结果不是一个,会报错。

对于过滤条件的使用,上述三个方法相同,但是互斥的,只能使用任意1个。以下内容以filter为例。

5.1 语法

# 单表的过滤:
模型类.objects.filter(属性名称__运算符=值)  # 此处的运算符是django的ORM提供的英文单词的运算符,与python的运算符不一样。
# 多表的过滤
模型类.objects.filter(外键属性名称__外键模型的属性名称__运算符=值)
# 属性名称和比较运算符间使用两个英文下划线

5.2 过滤条件

过滤条件 运算符 描述 代码
相等 exact 表示判断值是否相等
    def get(self, request):
        student_list = Student.objects.filter(name__exact="吴杰").all()
        # student_list = Student.objects.filter(name="吴杰").all()  # 常用!!
        print(student_list)
        return HttpResponse('ok')
模糊查询    contains 是否包含。
        student1 = Student.objects.filter(name__contains='华')
        print(student1) # <QuerySet [<Student: <User 赵华>>, <Student: <User 龙华>>,
startswith 指定值开头
        student2 = Student.objects.filter(name__endswith='华')
        print(student2) # QuerySet [<Student: <User 赵华>>, <Student: <User 龙华>>,
endswith 指定值结尾
        student3 = Student.objects.filter(name__startswith="江")
        print(student3) # <QuerySet [<Student: <User 江宸轩>>,
空查询  isnull 字段值是否为null。空查询
        student = Student.objects.filter(description__isnull=True)
        print(student)
范围查询  in 是否包含在范围内
        student = Student.objects.filter(classmate__in=[301, 302, 303]).all().values("id", "name", "classmate")
        print(student) # <QuerySet [{'id': 2, 'name': '程星云', 'classmate': '301'},
取值范围 range 设置开始值与结束值范围,进行数值判断,符合范围的数据被查询出来。也可以设置时间范围。
        # SQL: SELECT ... WHERE id BETWEEN 51 and 67;
        student_list = Student.objects.filter(id__range=(51, 67)).values("id", "name")
        print(student_list) # <QuerySet [{'id': 51, 'name': '董晴'},
比较查询  gt(e) 大于(等于)
    def get(self, request):
        # # 年龄大于20的
        # # age__gt=20  ---->>>  where age > 20
        student_list = Student.objects.filter(age__gt=22).values("name", "age")  # 后面任何方法,默认补充all()
        print(student_list) # <QuerySet [{'name': '欧阳博', 'age': 23},

        # # 年龄小于19的
        # # age__lt=19  ---->>>  where age < 19
        student_list = Student.objects.filter(age__lt=19).all().values("name","age")
        print(student_list) # <QuerySet [{'name': '张小玉', 'age': 18},
        
        # 年龄不等于19的
        # 使用exclude把符合条件的排除掉。不等于的运算符,使用exclude()过滤器。
        student_list = Student.objects.exclude(age=19).all().values("name","age")
        print(student_list)
        return HttpResponse('ok')
lt(e) 小于(等于)
日期查询    year 对日期时间类型的属性进行运算
from django.views import View
from django.http import HttpResponse
from .models import Student
from datetime import datetime, timedelta

class Student1(View):
    def get(self, request):
        student_list = Student.objects.filter(
            created_time__year=2022,
            created_time__month=7,
            created_time__day=20
        ).values("name", "created_time")
        print(student_list)
        # 精确时间查询
        from datetime import datetime
        add_time = "2021-08-18 16:19:38"
        timestamp = datetime.strptime(add_time, "%Y-%m-%d %H:%M:%S")
        student_list = Student.objects.filter(
            created_time=timestamp,
        ).all()
        print(student_list)
        # 查询时间范围在 "2021-08-18 16:19:38" ~ "2021-08-18 16:21:56" 的数据
        start_time = "2021-08-18 16:19:38"
        end_time = "2021-08-18 16:21:56"
        end_time_timestamp = datetime.strptime(end_time, "%Y-%m-%d %H:%M:%S")
        end_time_next = end_time_timestamp + timedelta(seconds=1)
        student_list = Student.objects.filter(
            created_time__gte=start_time,
            created_time__lt=end_time_next,
        ).all()
        print(student_list)
        return HttpResponse('ok')
month
day
weekday
 hour
minute
second
F对象 用于在SQL语句中针对字段之间的值进行比较的查询
"""F对象,字段间的值比较查询"""
from django.db.models import F
# 查询出入学以后,数据没有被修改过的学生信息
student = Student.objects.filter(created_time=F("updated_time")).values("name","created_time","updated_time")
print(student)
Q对象 多个过滤器逐个调用表示逻辑与关系,同sql语句中where部分的and关键字。
        """Q对象,复杂逻辑查询,针对多条件进行与或非处理"""
        from django.db.models import Q
        # 多个与 and  Q(条件) & Q(条件)
        # 查询出301班的男生
        # student = Student.objects.filter(Q(classmate=301) & Q(xingbie=1)).values("name","xingbie","classmate")
        # 上面也可以简写成
        # student = Student.objects.filter(classmate=301, xingbie=1).values("name", "xingbie", "classmate")
        """单纯的多个条件并立的情况下,没必要使用到Q对象进行处理,直接编写多个条件,使用逗号串联即可"""

        # NOT
        student = Student.objects.filter(~Q(classmate=301)).values("name", "age", "sex")

        # 多个或,or Q(条件) | Q(条件)
        # 查询出301班的男生 或者 302班的男生
        # student = Student.objects.filter(Q(classmate=301, xingbie=1) | Q(classmate=302, xingbie=1)).values("name",
        # 上面也可以简写成
        # student = Student.objects.filter(classmate__in=[301, 302], xingbie=1).values("name", "xingbie", "classmate")
        # print(student)

 

6 结果排序

方法 描述 代码
order_by

order_by("第一排序字段","第二排序字段",....)

当前第一字段的值一样时,参考第二字段进行排序,第二字段的值一样时,参考第三字段进行排序..

# order_by("id")   # 表示按id字段的值进行升序排序,id数值从小到大
# order_by("-id")  # 表示按id字段的值进行降序排序,id数值从大到小
# 调用了order_by以后,如果没有后续声明返回结果的all方法时,默认使用all()进行结果查询
student = Student.objects.order_by("-id")
print(student)

 

7 限制查询

7.1 说明

ORM中针对查询结果的数量限制,提供了一个查询集对象[QuerySet].这个QuerySet,是ORM中针对查询结果进行临时保存数据的一个容器对象,我们可以通过对QuerySet进行使用,达到查询优化的目的,也或者限制查询结果数量的作用。

 

7.2 查询集 QuerySet

1 查询集,也称查询结果集、QuerySet,表示从数据库中获取的对象集合。当调用如下ORM提供的过滤器方法时,Django会返回查询集(而不是简单的列表):

  • all():返回所有数据。

  • filter():返回满足条件的数据。filter会默认调用all方法。

  • exclude():返回满足条件之外的数据。exclude会默认调用all方法

  • order_by():对结果进行排序。order_by会默认调用all方法

 

2 判断某一个查询集中是否有数据:

方法 描述 代码
exists() 判断查询集中是否有数据,如果有则返回True,没有则返回False。
        student_list = Student.objects.filter(classmate="301")
        student_list = student_list.order_by("-age")
        student_list = student_list.filter(sex=1)
        ret = student_list.exists()
        print(ret) # True
values() 把结果集中的模型对象转换成字典,并可以设置转换的字段列表,达到减少内存损耗,提高性能。
   student_list = Student.objects.filter(classmate="301")
        student_list = student_list.order_by("-age")
        student_list = student_list.filter(sex=1)
        ret1 = student_list.values()  # 默认把所有字段全部转换并返回
        ret2 = student_list.values_list()  # 默认把所有字段全部转换并返回
        ret3 = student_list.values_list("id", "name", "age")  # 可以通过参数设置要转换的字段并返回
        print(ret1, type(ret1))  # <QuerySet [{'id': 102,..}]><class 'django.db.models.query.QuerySet'>
        print(ret2, type(ret2))  # <QuerySet [(102,..)]> <class 'django.db.models.query.QuerySet'>
        print(ret3, type(ret3))  # <QuerySet [(102, '赵本山', 50),..]> <class 'django.db.models.query.QuerySet'>
values_list() 把结果集中的模型对象转换成列表,并可以设置转换的字段列表(元祖),达到减少内存损耗,提高性能

 

3 QuerySet的两大特性

     
惰性执行

QuerySet查询集在创建时是不会访问数据库执行SQL语句,

直到模型对象被调用输出或者调用模型对象的属性时,才会真正的访问数据库执行SQL语句,

调用模型的情况包括循环迭代、序列化、与if合用,print的时候。

    def get(self, request):
        '''惰性执行,可以让重复的查询操作,只执行一次'''
        # 创建了一个查询集对象student_list,此时没有执行SQL语句的
        student_list = Student.objects.all()
        # 继续执行遍历迭代、或打印操作之后操作后,才进行了数据库的查询
        for student in student_list:
            pass
        return HttpResponse('ok')
缓存结果 使用同一个查询集,第一次使用时会发生数据库的查询,然后Django会把结果缓存下来,再次使用这个查询集时会使用缓存的数据,减少了数据库的查询次数
        """两个查询集,无法重用缓存,每次查询都会与数据库进行一次交互,增加了数据库的负载"""
        [student.id for student in Student.objects.all()]  # 因为没有缓存查询集到变量中,所以此处第一次执行了SQL语句
        [student.id for student in Student.objects.all()]  # 因为没有缓存查询集到变量中,所以此处第一次执行了SQL语句

        '''经过存储后,可以重用查询集,第二次使用缓存中的数据'''
        student_list = Student.objects.all()
        [student.id for student in student_list]  # 因为上面保存到查询到变量中,所以此处执行了SQL语句
        [student.id for student in student_list]  # 此处调用了之前的缓存数据

 

4 限制结果数量

django中可以对查询集QuerySet进行取下标或切片操作,等同于SQL中的limit和offset子句。对查询集QuerySet进行切片后返回一个新的查询集,但还是不会立即执行查询。

注意:QuerySet毕竟不是真正的列表,所以它不支持负数索引。

    def get(self, request):
        '''如果获取一个对象,直接使用[0],等同于[0:1].get(),
        但是如果没有数据,[0]引发IndexError异常,
        [0:1].get()如果没有数据引发DoesNotExist异常。'''
        # 查询集结果数量的下标和切片操作
        qs = Student.objects.all()
        # print(qs[0])  # 第1条数据, ORM会自动识别这个操作并转化成SQL语句的 limit 1
        # print(qs[2])  # 第3条数据, ORM会自动识别这个操作并转化成SQL语句的 limit 1 offset 2【表示跳过2条数据,从第3条数据开始取,取1条数据,也就是取3这条数据。】
        # print(qs[:2])   # 前2条数据, ORM会自动识别这个操作并转化成SQL语句的 limit 2
        # print(qs[1:4])  # 第1,2,3 数据, ORM会自动识别这个操作并转化成SQL语句的 limit 3 offset 1。
        # print( qs[-1] )   # 报错!!!不能使用负数
        return HttpResponse('ok')

 

8 聚合函数

django中,可以使用aggregate()过滤器调用聚合函数。聚合函数包括:Avg 平均,Count 总数,Max 最大,Min 最小,Sum 求和,导入from django.db.models import Max, Min, Count

中。

注意:使用count时一般不使用aggregate()过滤器。

        # 查询301班年龄最大的学生
        ret = Student.objects.filter(classmate=301).aggregate(Max("age"))
        # print(ret)  # {'age__max': 23}

        # 查新301班入学最早的学生[也就是ID最小的]
        ret = Student.objects.filter(classmate=301).aggregate(c=Min("id"))
        print(ret)  # {'id__min': 2}  ==> {'c': 2}

        # 调用count方法即可,不需要经过aggregate的调用
        ret = Student.objects.filter(classmate=301).count()
        print(ret)  # 11

 

9 分组函数 

django中,可以使用annotate()调用分组函数。等同于SQL中的select GROUP BY语句,对一个或多个列对结果集进行分组。

注意:SQL原生语句中分组之后可以使用having过滤,在django中并没有提供having对应的方法,但是可以使用filter对分组结果进行过滤。所以filter在annotate之前,表示where,在annotate之后代表having。同理,values在annotate之前,代表分组的字段,在annotate之后代表数据查询结果返回的字段列

        # 针对多个字段进行分组  values("classmate","xingbie").annotate(total=Count("id")) 按 班级和性别 统计人数
        # ret = Student.objects.values("classmate","sex").annotate(total=Count("id"))
        # print(ret)
        '''<QuerySet [{'classmate': '307', 'sex': True, 'total': 3},
            {'classmate': '301', 'sex': True, 'total': 8},
            {'classmate': '301', 'sex': False, 'total': 2},..'''
        # 查询出女生数量在2个以上的班级
        ret = Student.objects.filter(sex=True).values("classmate").annotate(total=Count("id")).values("classmate","total").filter(total__gte=2)
        print(ret)
        '''<QuerySet [{'classmate': '307', 'sex': True, 'total': 3},
            {'classmate': '301', 'sex': True, 'total': 8},..'''

 

10 原生查询

在django中,可以引入pymysql执行SQL,也可以调用ORM提供的raw方法来执行SQL语句。如果使用raw方法执行SQL语句,则返回结果是QuerySet,这个返回结果在操作字段时,会有额外性能损耗。

# 查询所有学生的班级、年龄、姓名和性别
sql = "SELECT id,name,sex,age,class FROM `db_student`"
ret = Student.objects.raw(sql)
# 针对原生SQL语句中已经查询出来的字段,只会查询一遍,
# 但是如果SQL语句没有查询出来的字段,而在模型中调用,则会由ORM再次调用数据库查询,把数据临时查询出来。
for student in ret:
    print(student)
    print(student.description)

 

11 多库共存

在django中,settings.py配置的DATABASES配置项允许注册多个数据库,可以支持在项目中随时切换操作不同的数据库。

        """ORM模型操作切换数据连接"""
        # 类名,可以使用django.db.models.Model 或者Model的子类,当然最好是为当前操作的数据库中的数据表简历一个对应的模型
        ret = Student.objects.using("数据库名").raw("SELECT * FROM mf_user")
        for row in ret:
            print(row.__dict__)

 

 

标签:Student,框架,数据库,ORM,list,objects,student,print,name
来源: https://www.cnblogs.com/daminghuahua/p/16503750.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有