前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Django 2.1.7 模型的关联

Django 2.1.7 模型的关联

作者头像
Devops海洋的渔夫
发布2019-06-17 14:45:18
1.5K0
发布2019-06-17 14:45:18
举报
文章被收录于专栏:Devops专栏

上一篇Django 2.1.7 模型 - 条件查询 F对象 Q对象 聚合查询讲述了关于Django模型的F对象、Q对象、聚合查询等功能。

但是没有讲到两张表的关联查询的实现,这个在模型里面该怎么处理呢?

参考文献

https://docs.djangoproject.com/zh-hans/2.1/ref/models/relations/

https://docs.djangoproject.com/zh-hans/2.1/topics/db/managers/

模型类关系

在进行关联查询之前,首先要了解一下模型之间的关联关系,以及相应的操作。

关系字段类型

关系型数据库的关系包括三种类型:

  • ForeignKey:一对多,将字段定义在多的一端中。
  • ManyToManyField:多对多,将字段定义在任意一端中。
  • OneToOneField:一对一,将字段定义在任意一端中。
  • 可以维护递归的关联关系,使用'self'指定。
一对多关系

想在前面篇章中,写到的服务器信息表以及中间件表,就是一对多的关系。

一台服务器对应多个中间件,相应的数据模型如下:

代码语言:javascript
复制
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) # 数据加入时间
    update_time = models.DateTimeField(auto_now=True) # 数据更新时间
    is_delete = models.BooleanField(default=False) # 逻辑删除

class MiddlewareInfo(models.Model):
    name = models.CharField(max_length=20)
    port = models.IntegerField()
    server = models.ForeignKey('ServerInfo',on_delete=models.CASCADE, default=None)
    shelves_date = models.DateTimeField(auto_now_add=True) # 数据加入时间
    update_time = models.DateTimeField(auto_now=True)  # 数据更新时间
    is_delete = models.BooleanField(default=False) # 逻辑删除

可以从上面的模型看出,一对多的关系构建的关键就是MiddlewareInfo(中间件-多类)设置外键连接ServerInfo(服务器信息 - 一类)。

server = models.ForeignKey('ServerInfo',on_delete=models.CASCADE, default=None)

但是在实际使用的过程中,使用外键的话,在做一些数据处理的时候很不方便。也可以不设置一个外键,直接就单纯一个int字段来记录ServerInfo类的id也是可以的。

多对多关系

在前面篇章中,并没有设计关于多对多的关联模型,那么现在可以设计一个。

在前面已有服务器类的前提下,可以设计一个服务器用途类。

定义一个服务器用途类的话,那么一台服务器可能有多种用途,同时一种用途类型下,可能有多台服务器对应。

这种就是多对多的关系。

代码语言:javascript
复制
class ServerUsedType(models.Model):
    used_type = models.CharField(max_length=20,default=None)

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) # 数据加入时间
    update_time = models.DateTimeField(auto_now=True) # 数据更新时间
    is_delete = models.BooleanField(default=False) # 逻辑删除
    server_used_type_id = models.ManyToManyField(ServerUsedType) # 通过ManyToManyField建立多对多的关系

那么这种模型多对多关系的字段通过数据迁移,会生成什么样的字段呢?

执行数据迁移,如下:

代码语言:javascript
复制
python3 manage.py makemigrations
python3 manage.py migrate

从mysql日志查看关键执行日志如下:

代码语言:javascript
复制
2019-06-14T16:54:06.348996Z    21 Query CREATE TABLE `assetinfo_serverinfo_server_used_type_id` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `serverinfo_id` integer NOT NULL, `serverusedtype_id` integer NOT NULL)
2019-06-14T16:54:06.394877Z    21 Query ALTER TABLE `assetinfo_serverinfo_server_used_type_id` ADD CONSTRAINT `assetinfo_serverinfo_serverinfo_id_b297c62e_fk_assetinfo` FOREIGN KEY (`serverinfo_id`) REFERENCES `assetinfo_serverinfo` (`id`)
2019-06-14T16:54:06.441100Z    21 Query ALTER TABLE `assetinfo_serverinfo_server_used_type_id` ADD CONSTRAINT `assetinfo_serverinfo_serverusedtype_id_5551cbd5_fk_assetinfo` FOREIGN KEY (`serverusedtype_id`) REFERENCES `assetinfo_serverusedtype` (`id`)
2019-06-14T16:54:06.489104Z    21 Query ALTER TABLE `assetinfo_serverinfo_server_used_type_id` ADD CONSTRAINT `assetinfo_serverinfo_ser_serverinfo_id_serverused_c12509b8_uniq` UNIQUE (`serverinfo_id`, `serverusedtype_id`)

查看mysql迁移数据之后,生成了两个表,如下:

代码语言:javascript
复制
mysql> show tables;
+------------------------------------------+
| Tables_in_assetinfo                      |
+------------------------------------------+
| assetinfo_middlewareinfo                 |
| assetinfo_scriptinfo                     |
| assetinfo_serverinfo                     |
| assetinfo_serverinfo_server_used_type_id |
| assetinfo_serverusedtype                 |

可以看到为了实现多对多的关系,django自动创建了一张中间表assetinfo_serverinfo_server_used_type_id,通过中间表绑定assetinfo_serverinfoassetinfo_serverusedtype表的关系。

查看这三张表的表结构如下:

代码语言:javascript
复制
mysql> desc assetinfo_serverinfo;
+---------------------+-------------+------+-----+---------+----------------+
| Field               | Type        | Null | Key | Default | Extra          |
+---------------------+-------------+------+-----+---------+----------------+
| id                  | int(11)     | NO   | PRI | NULL    | auto_increment |
| server_hostname     | varchar(20) | NO   |     | NULL    |                |
| server_intranet_ip  | varchar(20) | NO   |     | NULL    |                |
| server_internet_ip  | varchar(20) | NO   |     | NULL    |                |
| server_shelves_date | date        | NO   |     | NULL    |                |
| is_delete           | tinyint(1)  | NO   |     | NULL    |                |
| update_time         | datetime(6) | NO   |     | NULL    |                |
+---------------------+-------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

mysql> desc assetinfo_serverinfo_server_used_type_id;
+-------------------+---------+------+-----+---------+----------------+
| Field             | Type    | Null | Key | Default | Extra          |
+-------------------+---------+------+-----+---------+----------------+
| id                | int(11) | NO   | PRI | NULL    | auto_increment |
| serverinfo_id     | int(11) | NO   | MUL | NULL    |                |
| serverusedtype_id | int(11) | NO   | MUL | NULL    |                |
+-------------------+---------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> desc assetinfo_serverusedtype;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int(11)     | NO   | PRI | NULL    | auto_increment |
| used_type | varchar(20) | NO   |     | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> 

在知道Django模型如何实现多对多的关联之后,下面来看看怎么关联查询。

关联查询

Django中也能实现类似于join查询。

通过对象执行关联查询

首先写一个一对多的关联查询SQL,如下:

select s.server_hostname,m.name,s.id,m.server_id from assetinfo_serverinfo as s left join assetinfo_middlewareinfo as m on s.id = m.server_id where s.id = 1;

代码语言:javascript
复制
mysql> select s.server_hostname,m.name,s.id,m.server_id from assetinfo_serverinfo as s left join assetinfo_middlewareinfo as m on s.id = m.server_id where s.id = 1;
+-----------------+-----------+----+-----------+
| server_hostname | name      | id | server_id |
+-----------------+-----------+----+-----------+
| 测试服务器      | memcached |  1 |         1 |
| 测试服务器      | redis     |  1 |         1 |
| 测试服务器      | test      |  1 |         1 |
| 测试服务器      | test      |  1 |         1 |
| 测试服务器      | test      |  1 |         1 |
| 测试服务器      | test      |  1 |         1 |
| 测试服务器      | test      |  1 |         1 |
| 测试服务器      | test      |  1 |         1 |
| 测试服务器      | test      |  1 |         1 |
| 测试服务器      | mongodb   |  1 |         1 |
| 测试服务器      | test      |  1 |         1 |
| 测试服务器      | test      |  1 |         1 |
+-----------------+-----------+----+-----------+
12 rows in set (0.00 sec)

mysql> 

那么模型类该怎么实现这个查询呢?

由一到多的访问语法:一对应的模型类对象.多对应的模型类名小写_set

代码语言:javascript
复制
In [1]: from assetinfo.models import ServerInfo,MiddlewareInfo

# 设置查询 id = 1 的 服务器信息
In [2]: s = ServerInfo.objects.get(id=1)

# 关联查询相关的中间件信息
In [3]: s.middlewareinfo_set.all()
Out[3]: <QuerySet [<MiddlewareInfo: MiddlewareInfo object (1)>, <MiddlewareInfo: MiddlewareInfo object (2)>, <MiddlewareInfo: MiddlewareInfo object (5)>, <MiddlewareInfo: Middlewar
eInfo object (6)>, <MiddlewareInfo: MiddlewareInfo object (7)>, <MiddlewareInfo: MiddlewareInfo object (8)>, <MiddlewareInfo: MiddlewareInfo object (9)>, <MiddlewareInfo: Middlewar
eInfo object (10)>, <MiddlewareInfo: MiddlewareInfo object (11)>, <MiddlewareInfo: MiddlewareInfo object (14)>, <MiddlewareInfo: MiddlewareInfo object (15)>, <MiddlewareInfo: Middl
ewareInfo object (16)>]>

In [4]: 

对应的SQL如下:

SELECTassetinfo_middlewareinfo.id,assetinfo_middlewareinfo.name,assetinfo_middlewareinfo.port,assetinfo_middlewareinfo.server_id,assetinfo_middlewareinfo.shelves_date,assetinfo_middlewareinfo.update_time,assetinfo_middlewareinfo.is_deleteFROMassetinfo_middlewareinfoWHEREassetinfo_middlewareinfo.server_id= 1 LIMIT 21;

代码语言:javascript
复制
mysql> SELECT `assetinfo_middlewareinfo`.`id`, `assetinfo_middlewareinfo`.`name`, `assetinfo_middlewareinfo`.`port`, `assetinfo_middlewareinfo`.`server_id`, `assetinfo_middlewareinfo`.`shelves_date`, `assetinfo_middlewareinfo`.`update_time`, `assetinfo_middlewareinfo`.`is_delete` FROM `assetinfo_middlewareinfo` WHERE `assetinfo_middlewareinfo`.`server_id` = 1  LIMIT 21;
+----+-----------+-------+-----------+----------------------------+----------------------------+-----------+
| id | name      | port  | server_id | shelves_date               | update_time                | is_delete |
+----+-----------+-------+-----------+----------------------------+----------------------------+-----------+
|  1 | memcached | 11211 |         1 | 2019-06-10 14:56:46.150556 | 2019-06-10 17:37:51.365155 |         1 |
|  2 | redis     |  6379 |         1 | 2019-06-10 14:56:46.150556 | 2019-06-10 17:38:20.712862 |         1 |
|  5 | test      |   123 |         1 | 2019-06-10 17:05:16.632773 | 2019-06-10 17:05:16.632773 |         1 |
|  6 | test      |   123 |         1 | 2019-06-10 17:06:20.120658 | 2019-06-10 17:06:20.121656 |         1 |
|  7 | test      |   123 |         1 | 2019-06-10 17:06:43.193412 | 2019-06-10 17:06:43.193412 |         1 |
|  8 | test      |   123 |         1 | 2019-06-10 17:07:03.747395 | 2019-06-10 17:07:03.747395 |         1 |
|  9 | test      |   123 |         1 | 2019-06-10 17:08:43.372097 | 2019-06-10 17:08:43.372097 |         1 |
| 10 | test      |   123 |         1 | 2019-06-10 17:09:37.877019 | 2019-06-10 17:09:37.877019 |         1 |
| 11 | test      |   123 |         1 | 2019-06-10 17:11:45.403627 | 2019-06-10 17:11:45.403627 |         1 |
| 14 | mongodb   |  3306 |         1 | 2019-06-11 14:01:24.003175 | 2019-06-11 14:06:14.525648 |         1 |
| 15 | test      |   123 |         1 | 2019-06-11 14:04:10.576241 | 2019-06-11 14:04:10.576241 |         0 |
| 16 | test      |  3306 |         1 | 2019-06-11 14:06:05.608006 | 2019-06-11 14:06:05.608006 |         0 |
+----+-----------+-------+-----------+----------------------------+----------------------------+-----------+
12 rows in set (0.00 sec)

mysql> 

可以结果看出,其实Django模型的关联查询,也只是查询多类一方的单独数据而已。

上面是一到多的查询方式,下面再来一个多到一的查询方式,如下:

查看中间件信息id = 1 对应的 服务器信息

代码语言:javascript
复制
# 首先查询中间件的数据
In [4]: m = MiddlewareInfo.objects.get(id=1)

# 根据中间件的查询结果,再进行服务器信息查询
In [13]: s = ServerInfo.objects.filter(id = m.server_id )

# 打印查询出来的服务器名称
In [14]: for item in s:
    ...:     print(item.server_hostname)
    ...: 
测试服务器

上面查询主键编号的时候都是使用id,还可以使用pk来进行查询,如下:

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

In [16]: ServerInfo.objects.get(id=1)
Out[16]: <ServerInfo: ServerInfo object (1)>

In [17]: 

这两个查询的结果是一样的。

上面就是使用对象来实现的关联查询。那么有没有更加一句话能搞定的关联查询呢?

通过模型类执行关联查询

由多模型类条件查询一模型类数据:

语法如下:

代码语言:javascript
复制
关联模型类名小写__属性名__条件运算符=值

如果没有"__运算符"部分,表示等于,结果和sql中的inner join相同。

例:查询服务器信息,要求服务器中中间件的name包含'redis'。

代码语言:javascript
复制
In [17]: result = ServerInfo.objects.filter(middlewareinfo__name__contains='redis')

In [18]: print(result)
<QuerySet [<ServerInfo: ServerInfo object (1)>]>

对应的SQL如下:

代码语言:javascript
复制
mysql> SELECT `assetinfo_serverinfo`.`id`, `assetinfo_serverinfo`.`server_hostname`, `assetinfo_serverinfo`.`server_intranet_ip`, `assetinfo_serverinfo`.`server_internet_ip`, `assetinfo_serverinfo`.`server_shelves_date`, `assetinfo_serverinfo`.`update_time`, `assetinfo_serverinfo`.`is_delete` FROM `assetinfo_serverinfo` INNER JOIN `assetinfo_middlewareinfo` ON (`assetinfo_serverinfo`.`id` = `assetinfo_middlewareinfo`.`server_id`) WHERE `assetinfo_middlewareinfo`.`name` LIKE BINARY '%redis%'  LIMIT 21
    -> ;
+----+-----------------+--------------------+--------------------+---------------------+----------------------------+-----------+
| id | server_hostname | server_intranet_ip | server_internet_ip | server_shelves_date | update_time                | is_delete |
+----+-----------------+--------------------+--------------------+---------------------+----------------------------+-----------+
|  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          | 2019-06-10 14:56:46.425830 |         0 |
+----+-----------------+--------------------+--------------------+---------------------+----------------------------+-----------+
1 row in set (0.00 sec)

mysql> 

由一模型类条件查询多模型类数据: 语法如下:

代码语言:javascript
复制
一模型类关联属性名__一模型类属性名__条件运算符=值

例:查询服务器为“测试服务器”的所有中间件信息。

代码语言:javascript
复制
mysql> select * from assetinfo_middlewareinfo as m join assetinfo_serverinfo as s on m.server_id = s.id where s.server_hostname = '测试服务器';
+----+-----------+-------+-----------+-----------+----------------------------+----------------------------+----+-----------------+--------------------+--------------------+---------------------+-----------+----------------------------+
| id | name      | port  | server_id | is_delete | shelves_date               | update_time                | id | server_hostname | server_intranet_ip | server_internet_ip | server_shelves_date | is_delete | update_time                |
+----+-----------+-------+-----------+-----------+----------------------------+----------------------------+----+-----------------+--------------------+--------------------+---------------------+-----------+----------------------------+
|  1 | memcached | 11211 |         1 |         1 | 2019-06-10 14:56:46.150556 | 2019-06-10 17:37:51.365155 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
|  2 | redis     |  6379 |         1 |         1 | 2019-06-10 14:56:46.150556 | 2019-06-10 17:38:20.712862 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
|  5 | test      |   123 |         1 |         1 | 2019-06-10 17:05:16.632773 | 2019-06-10 17:05:16.632773 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
|  6 | test      |   123 |         1 |         1 | 2019-06-10 17:06:20.120658 | 2019-06-10 17:06:20.121656 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
|  7 | test      |   123 |         1 |         1 | 2019-06-10 17:06:43.193412 | 2019-06-10 17:06:43.193412 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
|  8 | test      |   123 |         1 |         1 | 2019-06-10 17:07:03.747395 | 2019-06-10 17:07:03.747395 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
|  9 | test      |   123 |         1 |         1 | 2019-06-10 17:08:43.372097 | 2019-06-10 17:08:43.372097 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
| 10 | test      |   123 |         1 |         1 | 2019-06-10 17:09:37.877019 | 2019-06-10 17:09:37.877019 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
| 11 | test      |   123 |         1 |         1 | 2019-06-10 17:11:45.403627 | 2019-06-10 17:11:45.403627 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
| 14 | mongodb   |  3306 |         1 |         1 | 2019-06-11 14:01:24.003175 | 2019-06-11 14:06:14.525648 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
| 15 | test      |   123 |         1 |         0 | 2019-06-11 14:04:10.576241 | 2019-06-11 14:04:10.576241 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
| 16 | test      |  3306 |         1 |         0 | 2019-06-11 14:06:05.608006 | 2019-06-11 14:06:05.608006 |  1 | 测试服务器      | 172.16.5.1         | 223.5.5.5          | 2019-06-10          |         0 | 2019-06-10 14:56:46.425830 |
+----+-----------+-------+-----------+-----------+----------------------------+----------------------------+----+-----------------+--------------------+--------------------+---------------------+-----------+----------------------------+
12 rows in set (0.00 sec)

mysql> 

那么模型该怎么写呢?

代码语言:javascript
复制
In [1]: from assetinfo.models import ServerInfo,MiddlewareInfo

In [2]: MiddlewareInfo.objects.filter(server_id__server_hostname='测试服务器')
Out[2]: <QuerySet [<MiddlewareInfo: MiddlewareInfo object (1)>, <MiddlewareInfo: MiddlewareInfo object (2)>, <MiddlewareInfo: MiddlewareInfo object (5)>
, <MiddlewareInfo: MiddlewareInfo object (6)>, <MiddlewareInfo: MiddlewareInfo object (7)>, <MiddlewareInfo: MiddlewareInfo object (8)>, <MiddlewareInfo
: MiddlewareInfo object (9)>, <MiddlewareInfo: MiddlewareInfo object (10)>, <MiddlewareInfo: MiddlewareInfo object (11)>, <MiddlewareInfo: MiddlewareInf
o object (14)>, <MiddlewareInfo: MiddlewareInfo object (15)>, <MiddlewareInfo: MiddlewareInfo object (16)>]>

In [3]:

对应执行的SQL如下:

代码语言:javascript
复制
mysql> SELECT `assetinfo_middlewareinfo`.`id`, `assetinfo_middlewareinfo`.`name`, `assetinfo_middlewareinfo`.`port`, `assetinfo_middlewareinfo`.`server_id`, `assetinfo_middlewareinfo`.`shelves_date`, `assetinfo_middlewareinfo`.`update_time`, `assetinfo_middlewareinfo`.`is_delete` FROM `assetinfo_middlewareinfo` INNER JOIN `assetinfo_serverinfo` ON (`assetinfo_middlewareinfo`.`server_id` = `assetinfo_serverinfo`.`id`) WHERE `assetinfo_serverinfo`.`server_hostname` = '测试服务器'  LIMIT 21
    -> ;
+----+-----------+-------+-----------+----------------------------+----------------------------+-----------+
| id | name      | port  | server_id | shelves_date               | update_time                | is_delete |
+----+-----------+-------+-----------+----------------------------+----------------------------+-----------+
|  1 | memcached | 11211 |         1 | 2019-06-10 14:56:46.150556 | 2019-06-10 17:37:51.365155 |         1 |
|  2 | redis     |  6379 |         1 | 2019-06-10 14:56:46.150556 | 2019-06-10 17:38:20.712862 |         1 |
|  5 | test      |   123 |         1 | 2019-06-10 17:05:16.632773 | 2019-06-10 17:05:16.632773 |         1 |
|  6 | test      |   123 |         1 | 2019-06-10 17:06:20.120658 | 2019-06-10 17:06:20.121656 |         1 |
|  7 | test      |   123 |         1 | 2019-06-10 17:06:43.193412 | 2019-06-10 17:06:43.193412 |         1 |
|  8 | test      |   123 |         1 | 2019-06-10 17:07:03.747395 | 2019-06-10 17:07:03.747395 |         1 |
|  9 | test      |   123 |         1 | 2019-06-10 17:08:43.372097 | 2019-06-10 17:08:43.372097 |         1 |
| 10 | test      |   123 |         1 | 2019-06-10 17:09:37.877019 | 2019-06-10 17:09:37.877019 |         1 |
| 11 | test      |   123 |         1 | 2019-06-10 17:11:45.403627 | 2019-06-10 17:11:45.403627 |         1 |
| 14 | mongodb   |  3306 |         1 | 2019-06-11 14:01:24.003175 | 2019-06-11 14:06:14.525648 |         1 |
| 15 | test      |   123 |         1 | 2019-06-11 14:04:10.576241 | 2019-06-11 14:04:10.576241 |         0 |
| 16 | test      |  3306 |         1 | 2019-06-11 14:06:05.608006 | 2019-06-11 14:06:05.608006 |         0 |
+----+-----------+-------+-----------+----------------------------+----------------------------+-----------+
12 rows in set (0.00 sec)

mysql> 

自关联

对于地区信息、分类信息等数据,表结构非常类似,每个表的数据量十分有限,为了充分利用数据表的大量数据存储功能,可以设计成一张表,内部的关系字段指向本表的主键,这就是自关联的表结构。

示例数据如下:

创建表的SQL:

代码语言:javascript
复制
CREATE TABLE `AREA` (  
  `ID` int(11) NOT NULL,  
  `PARENT_ID` int(11) NOT NULL DEFAULT '0' COMMENT '父级ID',  
  `NAME` varchar(50) NOT NULL COMMENT '名称',  
  `SHORT_NAME` varchar(50) NOT NULL COMMENT '简称',  
  `LONGITUDE` float NOT NULL DEFAULT '0' COMMENT '经度',  
  `LATITUDE` float NOT NULL DEFAULT '0' COMMENT '纬度',  
  `LEVEL` int(1) NOT NULL COMMENT '等级(1省/直辖市,2地级市,3区县,4镇/街道)',  
  `SORT` int(3) NOT NULL DEFAULT '1' COMMENT '排序',  
  `STATUS` int(1) NOT NULL DEFAULT '0' COMMENT '状态(0禁用/1启用)',  
  PRIMARY KEY (`ID`)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8 

那么为了更好实验,先来写上这个表结构的模型类,如下:

代码语言:javascript
复制
# 全国区域信息
class AREA(models.Model):
    ID = models.AutoField(primary_key=True,db_column='ID',auto_created=True, serialize=False, verbose_name='ID')
    PARENT_ID = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True,db_column='PARENT_ID')  # 父级id
    NAME = models.CharField(max_length=50,default=None,db_column='NAME')  # 名称
    SHORT_NAME = models.CharField(max_length=50,default=None)  # 简称
    LONGITUDE = models.FloatField(default=0)  # 经度
    LATITUDE = models.FloatField(default=0) # 纬度
    LEVEL = models.IntegerField(default=1)# 等级
    SORT = models.IntegerField(default=1) # 排序
    STATUS = models.IntegerField(default=1) # 状态

    class Meta:
        db_table = 'AREA' # 设置表名为 AREA

执行数据迁移:

代码语言:javascript
复制
python3 manage.py makemigrations
python3 manage.py migrate

到mysql中查看创建的表结构,如下:

代码语言:javascript
复制
mysql> desc AREA;
+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| ID         | int(11)     | NO   | PRI | NULL    | auto_increment |
| Name       | varchar(50) | NO   |     | NULL    |                |
| SHORT_NAME | varchar(50) | NO   |     | NULL    |                |
| LONGITUDE  | double      | NO   |     | NULL    |                |
| LATITUDE   | double      | NO   |     | NULL    |                |
| LEVEL      | int(11)     | NO   |     | NULL    |                |
| SORT       | int(11)     | NO   |     | NULL    |                |
| STATUS     | int(11)     | NO   |     | NULL    |                |
| PARENT_ID  | int(11)     | YES  | MUL | NULL    |                |
+------------+-------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)

mysql> 

导入几条数据,如下:

代码语言:javascript
复制
In [1]: from assetinfo.models import AREA

In [2]: area1 = AREA()

In [3]: area2 = AREA()

In [4]: area1.NAME = '广东省'

In [6]: area1.SHORT_NAME = '广东'

In [7]: area1.save()

In [8]: area2.NAME = '深圳市'

In [9]: area2.SHORT_NAME = '深圳'

In [10]: area2.PARENT_ID = area1

In [11]: area2.save()

In [13]: area3.NAME = '广州市'

In [14]: area3.SHORT_NAME = '广州'

In [15]: area3.PARENT_ID = area1

In [16]: area3.save()

到mysql中查询数据如下:

代码语言:javascript
复制
mysql> select * from AREA;
+----+------------+-----------+----------+-------+------+--------+-----------+-----------+
| ID | SHORT_NAME | LONGITUDE | LATITUDE | LEVEL | SORT | STATUS | PARENT_ID | NAME      |
+----+------------+-----------+----------+-------+------+--------+-----------+-----------+
|  1 | 广东       |         0 |        0 |     1 |    1 |      1 |      NULL | 广东省    |
|  2 | 深圳       |         0 |        0 |     1 |    1 |      1 |         1 | 深圳市    |
|  3 | 广州       |         0 |        0 |     1 |    1 |      1 |         1 | 广州市    |
+----+------------+-----------+----------+-------+------+--------+-----------+-----------+
3 rows in set (0.00 sec)

mysql> 
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019.06.15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 参考文献
  • 模型类关系
    • 关系字段类型
      • 一对多关系
      • 多对多关系
  • 关联查询
    • 通过对象执行关联查询
      • 通过模型类执行关联查询
        • 由多模型类条件查询一模型类数据:
    • 自关联
    相关产品与服务
    云数据库 SQL Server
    腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档