上一篇章讲述了如何创建项目,本篇章主要讲解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.py
中 INSTALLED_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()
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]: