• ORM数据库操作


    在一个 Web 框架中,前端负责提交和接收数据,展示页面,后端负责数据的处理与存储。

    常见的数据库有 PostgreSQL、Mariadb、MySQL、Oracle、Sqlite3等,Web 开发中对数据库的操作是必不可少的,然而数据库种类多种多样,每种数据库的操作方式以及用法不尽相同,常见的数据库操作,就是去编写SQL语句。

    在 Web 开发中,通常不需要去编写SQL语句去操作数据库,例如用SQL查出的数据,还需要对数据类型进行转化,并对数据进行一定的处理,这大大降低了开发这的工作效率。 Web 框架提供了丰富的模块,避免程序员在开发的过程中重复“造轮子”。

    ORM 模块

    ORM (Object Realtional Mapping)即对象关系映射,是一种基于关系型数据库的程序技术,这种程序技术的底层主要是通过映射机制实现的。ORM 把类映射成数据库中的表,把类的一个实例对象映射成数据库中的数据行,把类的属性映射成表中的字段,通过对象的操作对应到数据库表的操作,实现了对象到 SQL、SQL 到对象转换过程。

    请添加图片描述

    ORM 使用类和对象对数据库进行操作,大大提高了对数据库的控制,避免了直接使用 SQL 语句对数据库进行操作。

    ORM 适配多种常用的关系型数据库,例如 PostgreSQL、Mariadb、MySQL、Oracle、Sqlite3 等,由于 Django 中 ORM 的存在,为我们操作不同种类的数据库提供了统一的方法。

    ORM 模块定义数据表

    Django 把表模型定义为 Model,他需要继承自 django.db.models中的 Model 类,只要是与数据表相关的操作,都需要继承这个类。

    可以这样理解,Django 中模型类就相当于 ORM 模块。模型类本质上属于一个 Python 类,只不过在 Django 中称之为做模型类 ,它是由 django.db.models.Model 派生出的子类,在 Django 中模型类是数据交互的接口,一个模型类代表数据库中的一张数据表,模型类中每一个类属性都代表数据表中的一个字段。

    字段类型

    针对数据库中的字段类型,Django ORM 都有对应的 “xxxField” 来表述:

    字段说明字段属性
    AutoFiled默然自增主键(Primary_key=Ture),Django 默认建立id字段为主键。
    CharFiled字符类型字符长度需要明确,Max_length=,最大长度256
    IntgerFiled整型 int
    DateFiled年月日时间类型auto_now=True,数据被更新就会更新时间 ;auto_now_add=True,数据第一次参数时产生。
    DateTimeFiled年月日小时分钟秒时间类型auto_now=True,数据被更新就会更新时间; auto_now_add=True,数据第一次参数时产生。
    DecimalFiled混合精度的小数类型max_digits=3,限定数字的最大位数(包含小数位);decimal_places=2,限制小数的最大位数。
    BooleanFiled布尔字段,对应数据库 tinyint 类型数据长度只有1位。值为True或False,默认值是None
    TextFiled用于大文本
    字段选项

    Model 中添加的字段都是 Field 类型的实例,不同的 Field 类型可能会支持不同的字段选项,但是也有很多字段选项是通用的,即可以用在任何一种 Field 类型中。

    • blank: 默认值是 False,设置为 True 时,字段可以为空。设置为 False 时,字段是必须填写的。如果是字符型字段 CharField 和 TextField,它们是用空字符串来存储空值的。

    • null: 默认为 False,如果此选项为 False 建议加入 default 选项来设置默认值;如果设置为 True,表示该列值允许为空。日期型、时间型以及数字型字段不接受空字符串。所以当设置 IntegerField,DateTimeField 型字段可以为空时,需要将 blank 与 null 均设为 True 才可以。

    • default: 用于给字段设置默认值。可以是一个值或者是个可调用的对象,不能是一个可更改的对象(模型实例、list、set 等)。比如 BooleanFiled 布尔类型 default 值为Ture 或者 False。主要的使用场景是当一个字段的值被用户省略时,后台服务器自动为该字段的设置默认值。

    • unique: 默认值是 False,它是一个数据库级别的选项,规定该字段在表中必须是唯一的。如果设置为 True,这个字段必须在整个表中保持值唯一。数据库层面对待对待唯一性约束会创建唯一性索引,所以,如果一个字段设置了 unique=True,就不需要对这个字段加上索引选项了。

    • db_index: 默认值是 False,如果设置为 True,Django 则会为该字段创建数据库索引,如果该字段经常作为查询的条件,那么就需要设置 db_index 选项,从而加快数据的检索速度。

    • db_column: 此字段用于设置数据库表字段的名称。如果没有指定,Django 默认使用 Model 中字段的名字。

    • primary_key: 默认值是 False,如果设置为 True,表示该字段为主键,在 Django 中 默认 id 为主键,也就是说即使你的数据表中没有创建 id 字段,Django 也会自动为你创建 id 字段并将其设置为主键。如果你在表中设置了其他字段为主键的时,那么 Django 将取消为 id 字段设置主键。

    • verbose_name: 设置此字段在 admin 后台管理系统界面上的显示名称,如果没有给定详细名称,Django 会使用字段的属性名自动创建,并将下划线转换为空格。

    • choices: 用于给字段设置可以选择的值。它是一个可迭代对象,即列表或者元组,其中每一个元素都是一个二元组(a,b)的形式,a 是用来选择的对象,b 是对 a 的描述信息。比如我们对某个人性别定义:

    class UserInfo(models.Model):
        # 定义chocies参数的对应关系,以元组(或者列表)的形式进行表述:
        choices = (
            (male, '男性'),
            (female, '女性'),
        )
        sex = models.CharField(max_length=2,choices = choices,default='male')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在执行python manage.py startapp 命令创建应用的时候,在应用目录下,就生成了一个 models.py 文件,通过这个文件,我们去创建模型,定义数据表

    from django.db import models
    
    # Create your models here.
    
    # 测试交流会模型
    class Event(models.Model):      # 继承django自带的模型基类
    
        # 交流会主题
        name = models.CharField(max_length=256,null=False)
        # 交流会地点
        address = models.CharField(max_length=256)
        # 交流会开始时间
        start_time = models.DateTimeField(null=True)
        # 交流会状态
        status = models.BooleanField(default=True)
    	# 交流会限制人数
        limits = models.IntegerField(default=200)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    模型迁移

    在进行迁移前,需要确定setting文件中应用配置和数据库配置。

    确保INSTALLED_APPS中应已注册该应用

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'demo',     
        'sgin',		# 添加应用
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果是连接的mysql(mariadb),要注意数据库信息的配置,否则会迁移不成功

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',	 #数据库引擎
            'NAME': 'DjangoSite',				 	 #数据库名称
            'USER': 'bobo',							 #用户名
            'PASSWORD': '123456',					 #密码
            'HOST': '192.168.134.132',				 #数据库IP
            'PORT': '3306',							 #数据库端口
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在终端执行命令python manage.py makemigrations生成迁移文件,这个文件可以在应用目录下的目录下找到

    from django.db import migrations, models
    
    
    class Migration(migrations.Migration):
    
        initial = True
    
        dependencies = [
        ]
    
        operations = [
            migrations.CreateModel(
                name='Event',
                fields=[
                    ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('name', models.CharField(max_length=256)),
                    ('address', models.CharField(max_length=256)),
                    ('start_time', models.DateTimeField(null=True)),
                    ('status', models.BooleanField(default=True)),
                    ('limits', models.IntegerField(default=200)),
                ],
            ),
        ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    执行命令python manage.py migrate应用数据库迁移,在数据库中生成数据表

    请添加图片描述

    可以发现,数据库中生成了一个名为sgin_event的数据表,该表是以应用名+模型名命名的。除了这张表,还生成了很多其他表,这些表是因为在 setting.py文件中,INSTALLED_APPS中存在Django自带的应用,这些应用也会生成数据表

    拓展: django报错Did you install mysqlclient?

    django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module.
    Did you install mysqlclient?
    
    • 1
    • 2

    若出现如上方类似的报错提示,这个报错的意思是没有安装mysqlclient,如果能安装mysqlclient,可以安装,Windows下可能安装失败,推荐安装PyMySQL

    pip install PyMySQL
    
    • 1

    修改项目目录下的__init__.py (与settings.py同一个目录)
    添加以下信息:

    import pymysql
    pymysql.install_as_MySQLdb()
    
    • 1
    • 2

    ORM 管理器对象

    生成了数据表后,数据表的内容是空的,需要插入数据,可以通过 ORM 来操作数据,使用类名(即数据表名)来操作数据

    打开pycharm的Terminal终端,输入命令python manage.py shell 打开Django自带命令行,输入指令from sgin.models import Event导入sgin应用下的Event模型类

    输入指令Event.objects.all()查询所有数据。该命令就相当于SQL:select * from sgin_event。返回的是QuerySet对象,这里因为表是空的,所以没有数据,查出来的是一个空列表。

    这里objects指向的是一个模型管理器(Manager),模型管理器的作用是管理当前数据模型对应表的增删改查操作。Django提供的模型管理器,通过模型类的objects属性调用,只能通过类调用,不能通过实例调用,如Event.objects而不是Event().objects

    ORM 的增删改查称为 CURD 操作

    插入数据

    语法:Model.objects.create(**kws)

    使用create方法插入数据,也就是增删改查操作中的 C,在pycharm的Terminal终端,输入指令

    Event.objects.create(name='安全测试交流会',address='直播间888号房')
    Event.objects.create(name='性能测试交流会',address='直播间666号房')
    
    • 1
    • 2
    查询数据
    查询所有

    语法:

    Model.objects.all()
    
    • 1

    输入指令Event.objects.all()查询所有数据。该命令就相当于SQL:select * from sgin_event。返回的是QuerySet对象

    <QuerySet [<Event: Event object (2)>]>
    
    • 1
    条件过滤查询

    语法:

    Model.objects.filter(**kw)
    Model.objects.values(**kw)
    
    • 1
    • 2

    输入指令 Event.objects.filter(name='安全测试交流会') 查询数据,返回的是QuerySet对象。

    输入指令 Event.objects.filter(name='安全测试交流会').values() 查询数据,返回QuerySet对象的是以键值对的形式展示,可以使用list函数将其转变成列表。

    >>> Event.objects.filter(name='安全测试交流会')
    ]>
    >>> Event.objects.filter(name='安全测试交流会').values()
    
    >>> list(Event.objects.filter(name='安全测试交流会').values())
    [{'id': 1, 'name': '安全测试交流会', 'address': '直播间888号房', 'start_time': None, 'status': True, 'limits': 200}]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    该命令就相当于SQL:select * from sgin_event where name='安全测试交流会'

    查询单个

    语法:

    Model.objects.get(**kw)
    
    • 1

    输入指令 Event.objects.all().get(name='安全测试交流会') 查询数据,返回单个模型数据对象,如果结果超出或者少于1个的时候,会抛出异常

    <Event: Event object (1)>
    
    • 1

    该命令就相当于SQL:select * from sgin_event where name='安全测试交流会' limits=1

    可以发现QuerySet对象与get返回的单个模型数据对象,区别在于QuerySet对象多了一层[],单个模型数据对象相当于QuerySet对象列表里的单个数据。

    覆盖对象对外的字符串表现形式

    对于以上查询,返回的QuerySet对象不利于查看数据,这里可以对模型添加魔术方法。

    __str__方法是 Python 中的 "魔术” 方法,它是为 print 这样的打印函数设计的,它属于 python 的 object 基类的一个方法,也就是说 python 所有的类都有该方法,当然 Django 的 modle 类也有。如果没有这个方法定义,打印对象会显示对象的内存地址,但是这样的显示方式不够友好,且不利于调试,而用__str__方法后,可以在 print 时得到易于人阅读的信息

    models.py 文件中添加__str__魔术方法

    from django.db import models
    
    # Create your models here.
    
    # 测试交流会模型
    class Event(models.Model):      # 继承django自带的模型基类
    
        # 交流会主题
        name = models.CharField(max_length=256,null=False)
        # 交流会地点
        address = models.CharField(max_length=256)
        # 交流会开始时间
        start_time = models.DateTimeField(null=True)
        # 交流会状态
        status = models.BooleanField(default=True)
    	# 交流会限制人数
        limits = models.IntegerField(default=200)
        
        # 覆盖对象对外的字符串表现形式
        def __str__(self):
            return self.name
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    添加__str__魔术方法并不会影响model中的表结构,所以不需要重新生成迁移文件,也不需要迁移到数据库表这一操作。

    输入exit()退出shell后,输入命令python manage.py shell 重新激活一下,输入指令from sgin.models import Event导入sgin应用下的Event模型类,此时再输入指令Event.objects.all()查询所有数据

    <QuerySet [<Event: 安全测试交流会>, <Event: 性能测试交流会>]>
    
    • 1

    这样查看数据,可能会稍微好看一点

    修改数据
    save方法

    修改数据首先要拿到数据对象,使用一个变量event_obj去接收查询的单个模型数据对象

    event_obj = Event.objects.all().get(name='性能测试交流会')
    
    • 1

    然后通过对属性进行赋值的方式,进行修改

    event_obj.address = '直播间1111号房'
    
    • 1

    修改只是将修改的内容保存到了内存中,并没有同步到数据库,最后还需要通过save方法,将修改保存到数据库

    event_obj.save()
    
    • 1

    这时候去查看数据表中的内容,可以发现性能测试交流会这条数据的 address直播间666号房变为直播间1111号房

    如果变量接收的是一个QuerySet对象,可以通过获取其列表里的第一个元素,再进行操作

    event_obj2 = Event.objects.filter(name='安全测试交流会').first()
    event_obj2.address = '直播间2222号房'
    event_obj2.save()
    
    • 1
    • 2
    • 3
    update方法

    使用一个变量event_obj3去接收查询的QuerySet对象

    event_obj3 = Event.objects.filter(name='性能测试交流会')
    
    • 1

    然后通过update方法进行修改

    event_obj3.update(name='测试开发交流会')
    
    • 1

    这种方式相对于save方法,稍微没有那么麻烦,update后就直接更新到数据库了

    删除数据

    删除的内容,是一条语句,对于Django来说,就是删除单个模型数据对象

    event_obj4 = Event.objects.all().get(name='测试开发交流会')
    event_obj4.delete()
    
    • 1
    • 2

    删除成功后,数据表中就没有测试开发交流会这条数据了

    ORM数据交互

    通过ORM增删改查操作,与数据库进行实时交互,那么,如果要将数据库中的数据展示到前端页面,该如何处理?

    from django.shortcuts import render
    
    
    def event(request):
        eventlist = [
            '功能测试',
            '性能测试',
            '自动化测试'
        ]
        return render(request,'events.html',{'event_list':eventlist})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    之前返回给前端的数据,是在视图函数里写死了,这里需要修改成从数据库里取数据。

    from django.shortcuts import render
    from sgin.models import Event       # 导入sgin应用下的Event模型类
    
    # Create your views here.
    
    def event(request):
        eventlist = Event.objects.all()     # 通过模型管理器获取数据
        return render(request,'events.html',{'event_list':eventlist})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    通过Event.objects.all()查询的内容,是一个QuerySet对象,其本质是一个可迭代对象,前端页面有一个 for 循环读取处理,在 models.py 文件中添加了__str__魔术方法,数据对外展示的时候,以name的方式进行展示,所以到了前端,展示的内容就是数据表中 name的数据

    启动项目,在浏览器中输入http://127.0.0.1:8000/events/,可以发现,这块内容变成了从数据库中获取的数据了

    在这里插入图片描述

    ORM优势与不足

    ORM 模块确实有诸多的优势,比如:

    • 使用该模块只需要面向对象编程,不需要面向数据库编写代码,对数据库的操作转换为对类属性和方法的操作,不用我们编写各种数据库的 SQL 语句。
    • 实现数据模型与数据库的解耦,屏蔽了不同数据库操作上的差异化,不在关注不同数据库内部的操作细节,通过简单更改配置就可以实现数据库的更换而无需更改代码。

    与此同时 ORM 也存在一点不足之处:
    相比直接用 SQL 语句操作数据库会有性能损失,因为在映射的过程中 ORM 需要与 SQL 之间进行转换,根据对象的操作转换成 SQL 语句,根据查询结果转换成对象,所以在映射的过程存在性能损失。

    但是 ORM 的不足带来的这点性能损失是微不足道的,ORM 的优势还是非常突出的,这种对象模型和关系型数据库之间的转换方式,给开发者带来了极大的便捷。

  • 相关阅读:
    Java 17 新特性:switch的模式匹配(Preview)
    音视频技术开发周刊 | 316
    matplotlib做时钟
    Vue入门
    另辟蹊径者 PoseiSwap:背靠潜力叙事,构建 DeFi 理想国
    有哪些gif动画制作软件比较好用?
    [JavaWeb] Tomcat 基础安装和使用
    数据结构前瞻
    Golang 程序漏洞检测利器 govulncheck(三):github 集成方法
    C++算法入门练习——树的带权路径长度
  • 原文地址:https://blog.csdn.net/qq_44614026/article/details/126445154