ForeignKey定义了一个多对一的关系,需要两个位置参数:模型相关的类和on_delete
选项
例如:models.Foreignkey(User,on_delete=models.CASCADE)
,其中User
就是模型相关的类,表示与User
表相关联,而on_delete=models.CASCADE
则是on_delete
选项,定义关联表数据删除时的动作
两个必选参数,分别是模型类和on_delete
选项
关联的模型,默认情况下指向关联的模型对象,某些情况下需要模型对象关联自身,例如用户表里有个leader
字段用来标识当前用户的直属领导,直属领导也是个用户,所以需要跟用户表自身相关联,那模型类就需要写成self
class User(models.Model):
username = models.CharField(max_length=16, verbose_name='用户名称')
leader = models.ForeignKey('self', on_delete=models.PROTECT, verbose_name='直属领导')
def __str__(self):
return self.username
on_delete的值主要有以下几个
null=True
default=n
SET()
的值,例如SET(get_sentinel_user)
,则在删除时会调用get_sentinel_user
方法来设置结果unique=True
默认情况下,当migrate应用表修改后,查询数据库会发现,所有ForeignKey字段在数据库里的字段名称会加上_id
,例如上边User表的leader字段,在数据库里讲会变成leader_id
当然你可以通过db_column
来改变字段在数据库中的名字,不过一般没必要,通常保持默认就好了
CREATE TABLE `accounts_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(16) NOT NULL,
`leader_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `accounts_user_leader_id_28d81690` (`leader_id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8
以下演示代码参考如下表设计
class Host(TimeBaseModel):
ip = models.GenericIPAddressField(verbose_name='IP地址')
port = models.SmallIntegerField(verbose_name='主机端口')
class Password(TimeBaseModel):
host = models.ForeignKey(Host, on_delete=models.CASCADE, verbose_name='主机')
user = models.CharField(max_length=32, verbose_name='账号')
password = models.CharField(max_length=32, verbose_name='密码')
contact = models.CharField(max_length=64, verbose_name='联系人')
note = models.TextField(max_length=64, verbose_name='备注')
>>> h1 = Host.objects.create(ip='192.168.3.1', port=22)
>>>
>>> h2 = Host.objects.create(ip='192.168.3.2', port=22)
>>>
>>>
>>> h1.id
29
>>> h2.id
30
>>> p1 = Password.objects.create(host=h1, user='root', password='123', contact='fei.liu', note='')
>>>
>>> p2 = Password.objects.create(host_id=30, user='root', password='123', contact='fei.liu', note='')
>>>
>>>
>>> p1.host.id
29
>>> p2.host.id
30
可以通过instance实例或instance_id两种方式来新增数据
正向查询
>>> p = Password.objects.get(id=3)
>>> p.host.ip
'192.168.3.1'
反向查询
>>> h = Host.objects.get(id=30)
>>> h.password_set.all()
<QuerySet [<Password: Password object (5)>]>
related_name
class Password(TimeBaseModel):
host = models.ForeignKey(Host, on_delete=models.CASCADE, related_name='users', verbose_name='主机')
>>> h = Host.objects.get(id=30)
>>> h.users.all()
<QuerySet [<Password: [email protected]>]>
当related_name
配置存在时,则可以通过related_name
定义的值进行查询
>>> p = Password.objects.get(id=5)
>>> p.host_id = 29
>>> p.save()
>>>
>>> p.host
<Host: 192.168.3.1>
>>> h = Host.objects.get(id=30)
>>> h.ip
'192.168.3.2'
>>>
>>> p.host = h
>>> p.save()
>>>
>>> p.host
<Host: 192.168.3.2>
同样的也能通过instance实例或instance_id两种方式来修改数据
>>> p = Password.objects.get(id=5)
>>> p.delete()
(1, {'cmdb.Password': 1})