Django ORM数据库操作

Django ORM数据库操作

      • ORM 模块
      • ORM 模块定义数据表
        • 字段类型
        • 字段选项
      • 模型迁移
      • ORM 管理器对象
        • 插入数据
        • 查询数据
          • 查询所有
          • 条件过滤查询
          • 查询单个
          • 覆盖对象对外的字符串表现形式
        • 修改数据
          • save方法
          • update方法
        • 删除数据
      • ORM数据交互
      • ORM优势与不足

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

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

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

ORM 模块

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

Django ORM数据库操作_第1张图片

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

在执行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)

模型迁移

在进行迁移前,需要确定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',		# 添加应用
]

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

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',	 #数据库引擎
        'NAME': 'DjangoSite',				 	 #数据库名称
        'USER': 'bobo',							 #用户名
        'PASSWORD': '123456',					 #密码
        'HOST': '192.168.134.132',				 #数据库IP
        'PORT': '3306',							 #数据库端口
    }
}

在终端执行命令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)),
            ],
        ),
    ]

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

Django ORM数据库操作_第2张图片

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

拓展: django报错Did you install mysqlclient?

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

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

pip install PyMySQL

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

import pymysql
pymysql.install_as_MySQLdb()

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号房')
查询数据
查询所有

语法:

Model.objects.all()

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

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

语法:

Model.objects.filter(**kw)
Model.objects.values(**kw)

输入指令 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}]

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

查询单个

语法:

Model.objects.get(**kw)

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

<Event: Event object (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

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

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

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

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

修改数据
save方法

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

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

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

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

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

event_obj.save()

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

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

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

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

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

然后通过update方法进行修改

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

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

删除数据

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

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

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

ORM数据交互

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

from django.shortcuts import render


def event(request):
    eventlist = [
        '功能测试',
        '性能测试',
        '自动化测试'
    ]
    return render(request,'events.html',{'event_list':eventlist})

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

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})

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

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

Django ORM数据库操作_第3张图片

ORM优势与不足

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

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

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

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

你可能感兴趣的:(#,Python,Django,数据库,django,python)