7. Django 2.1.7 基于默认sqlite3 模型设计 以及 数据操作

2022-01-17 10:04:44 浏览数 (1)

上一篇章讲述了如何创建项目,本篇章主要讲解Django的模型设计。

参考文献

Django 官网 2.1 文档

一般操作数据库是通过写sql语句,那么能不能不写sql语句就可以操作数据库呢?可以,就是通过接下来要给大家讲的ORM框架。

本篇章首先使用Django默认使用的sqlite3,后续再继续讲解使用mysql。

ORM框架

O是object,也就类对象的意思,R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思,M是mapping,是映射的意思。在ORM框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据。ORM框架还有一个功能,它可以根据我们设计的类自动帮我们生成数据库中的表格,省去了我们自己建表的过程。

django中内嵌了ORM框架,不需要直接面向数据库编程,而是定义模型类,通过模型类和对象完成数据表的增删改查操作。

使用django进行数据库开发的步骤如下:

  • 1.在models.py中定义模型类
  • 2.迁移
  • 3.通过类和对象完成数据增删改查操作

下面我们以保存服务器资产信息为例来给大家介绍Django中进行数据库开发的整个流程。

1.定义模型类

模型类定义在models.py文件中,继承自models.Model类。

说明:不需要定义主键列,在生成时会自动添加,并且值为自动增长。 ”

设计服务器资产类

服务器类:

  • 类名:ServerInfo
  • 服务器名称:server_hostname
  • 服务器内网IP:server_intranet_ip
  • 服务器外网IP:server_internet_ip
  • 服务器上架日期:server_shelves_date

模型类的设计

根据设计,在models.py中定义模型类如下:

代码语言:javascript复制
from django.db import models

class ServerInfo(models.Model):
    server_hostname = models.CharField(max_length=20, default=None)
    server_intranet_ip = models.CharField(max_length=20,default=None)
    server_internet_ip = models.CharField(max_length=20,default=None)
    server_shelves_date = models.DateField(auto_now_add=True)

下一步就可以使用Django自带的迁移的方式,创建数据库表。

2.激活模型

上面的一小段用于创建模型的代码给了 Django 很多信息,通过这些信息,Django 可以:

  • 为这个应用创建数据库 schema(生成 CREATE TABLE 语句)。
  • 创建可以与 ServerInfo 对象进行交互的 Python 数据库 API。
  • 但是首先得把 assetinfo 应用安装到我们的项目里。

为了在我们的工程中包含这个应用,我们需要在配置类 INSTALLED_APPS 中添加设置。因为 AssetinfoConfig 类写在文件 assetinfo/apps.py中,所以它的点式路径是 'assetinfo.apps.AssetinfoConfig'。在文件 mysite/settings.pyINSTALLED_APPS 子项添加点式路径后,它看起来像这样:

不用死记硬背这个点路径,pycharm会自动提示。

3.迁移

现在你的 Django 项目会包含 assetinfo 应用。接着运行下面的命令:

$ python3 manage.py makemigrations assetinfo

看看生成的这个文件是什么样的,如下:

Django框架根据我们设计的模型类生成了迁移文件,在迁移文件中我们可以看到fields列表中每一个元素跟Serverinfo类属性名以及属性的类型是一致的。同时我们发现多了一个id项,这一项是Django框架帮我们自动生成的,在创建表的时候id就会作为对应表的主键列,并且主键列自动增长。

执行迁移命令如下:python3 manage.py migrate

当执行迁移命令后,Django框架会读取迁移文件自动帮我们在数据库中生成对应的表格。

迁移后目录结构如下图:

Django默认采用sqlite3数据库,上图中的db.sqlite3就是Django框架帮我们自动生成的数据库文件。sqlite3是一个很小的数据库,通常用在手机中,它跟mysql一样,我们也可以通过sql语句来操作它。

使用navicat访问sqlite3数据库

从上图可以看到自动创建生成的表以及字段。

默认生成的表名称

细心的读者会发现上面生成的表的名字叫做assetinfo_serverinfo,assetinfo是应用的名字,serverinfo是模型类的名字。

数据表的默认名称为:

代码语言:javascript复制
<app_name>_<model_name>
例:
assetinfo_serverinfo

设计中间件类

中间件类:

类名:MiddlewareInfo 中间件名称:name 中间件端口号:port 中间件所属服务器:server 服务器-中间件的关系为一对多

打开assetinfo/models.py,定义中间件类代码如下:

代码语言:javascript复制
# 中间件类:MiddlewareInfo
# 中间件名称: name
# 中间件端口号:port
# 中间件所属服务器:server
class MiddlewareInfo(models.Model):
    name = models.CharField(max_length=20)
    port = models.IntegerField()
    server = models.ForeignKey('ServerInfo')

这里要说明的是,ServerInfo类和MiddlewareInfo类之间具有一对多的关系,这个一对多的关系应该定义在多的那个类,也就是MiddlewareInfo类中。

server = models.ForeignKey('ServerInfo')这句代码就让ServerInfo类和MiddlewareInfo类之间建立了一对多的关系。 ”

在我们之后迁移生成表的时候,Django框架就会自动帮我们在图书表和英雄表之间建立一个外键关系。

生成迁移文件:python3 manage.py makemigrations assetinfo

执行之后,可以发现错误如下:

那么怎么解决这个错误呢?

解决model的外键错误

在外键值的后面加上 on_delete=models.CASCADE

可以看到错误提示,还需要设置一个默认值,那么下面就写多一个默认值,如下:

可以看到执行成功了。

中间类的代码如下:

代码语言:javascript复制
class MiddlewareInfo(models.Model):
    name = models.CharField(max_length=20)
    port = models.IntegerField()
    server = models.ForeignKey('ServerInfo',on_delete=models.CASCADE, default=None)

再查看一下生成的迁移文件,如下:

执行迁移的命令

python3 manage.py migrate

使用navicat查看表结构

注意上图中assetinfo_middlewareinfo表中有一列server_id,这一列名为什么不叫server?server_id是根据MiddlewareInfo类的关系属性server生成的,对应着服务器表中的主键id。

4.数据操作

完成数据表的迁移之后,下面就可以通过进入项目的shell,进行简单的API操作。

进入项目shell的命令: python3 manage.py shell

因为我安装了ipython3,所以会自动进入ipython3的工具。

首先引入assetinfo/models中的类:from assetinfo.models import ServerInfo,MiddlewareInfo

查询所有服务器信息:

代码语言:javascript复制
In [3]: ServerInfo.objects.all()
Out[3]: <QuerySet []>

因为当前并没有数据,所以返回空查询结果集。

新建服务器信息对象并写入一条数据:

代码语言:javascript复制
In [7]: s = ServerInfo()

In [8]: s
Out[8]: <ServerInfo: ServerInfo object (None)>

In [9]: s.server_hostname = "test_server"

In [10]: s.server_intranet_ip = "172.168.0.1"

In [11]: s.server_internet_ip = "223.5.5.5"

In [12]: from datetime import date

In [13]: s.server_shelves_date = date(2019,6,4)

In [14]: s.save()

In [15]:

再次查询所有服务器信息:

代码语言:javascript复制
In [15]: ServerInfo.objects.all()
Out[15]: <QuerySet [<ServerInfo: ServerInfo object (1)>]>

In [16]:

查找服务器信息并查看值:

代码语言:javascript复制
In [16]: server_info = ServerInfo.objects.get( id = 1 )

In [17]: server_info
Out[17]: <ServerInfo: ServerInfo object (1)>

In [18]: server_info.id
Out[18]: 1

In [19]: server_info.server_hostname
Out[19]: 'test_server'

In [20]: server_info.server_shelves_date
Out[20]: datetime.date(2019, 6, 4)

In [21]: server_info.server_intranet_ip
Out[21]: '172.168.0.1'

In [22]: server_info.server_internet_ip
Out[22]: '223.5.5.5'

修改服务器信息:

代码语言:javascript复制
In [23]: server_info.server_shelves_date = date(2018,6,4)

In [24]: server_info.save()

In [26]: server_info.server_shelves_date
Out[26]: datetime.date(2018, 6, 4)

In [27]:

从navicat查看如下:

删除服务器信息:

server_info.delete()

代码语言:javascript复制
In [27]: server_info.delete()
Out[27]: (1, {'assetinfo.MiddlewareInfo': 0, 'assetinfo.ServerInfo': 1})

In [28]: ServerInfo.objects.all()
Out[28]: <QuerySet []>

In [29]:

对象的关联操作

创建一个ServerInfo对象,写入一条服务器信息:

代码语言:javascript复制
In [29]: server1 = ServerInfo()

In [30]: server1.server_hostname = "redis_server"

In [32]: server1.server_intranet_ip = "172.168.0.1"

In [33]: server1.server_internet_ip = "223.5.5.5"

In [35]: server1.server_shelves_date = date(2019,6,4)

In [36]: server1.save()

创建一个MiddlewareInfo对象,写入两条中间件信息:

代码语言:javascript复制
In [39]: m1 = MiddlewareInfo()

In [40]: m1.name = "redis"

In [41]: m1.port = 6379

In [42]: m1.server = server1

In [43]: m1.save()

In [44]: m2 = MiddlewareInfo()

In [45]: m2.name = "memcached"

In [46]: m2.port = "26379"

In [47]: m2.server = server1

In [48]: m2.save()

In [49]: MiddlewareInfo.objects.all()
Out[49]: <QuerySet [<MiddlewareInfo: MiddlewareInfo object (1)>, <MiddlewareInfo: MiddlewareInfo object (2)>]>

服务器与中间件是一对多的关系,django中提供了关联的操作方式。

获得关联集合:返回当前server1对象的所有中间件。

代码语言:javascript复制
In [50]: server1.middlewareinfo_set.all()
Out[50]: <QuerySet [<MiddlewareInfo: MiddlewareInfo object (1)>, <MiddlewareInfo: MiddlewareInfo object (2)>]>

In [51]:

0 人点赞