一对多:models.ForeignKey()
首先定义表结构:
class UserType(models.Model): caption = models.CharField(max_length=32) def __unicode__(self): return self.caption class UserInfo(models.Model): username = models.CharField(max_length=32) user_type = models.ForeignKey("UserType") age = models.IntegerField() def __unicode__(self): return "%s%d" % (self.username,self.age)
在创建表的时候,一般情况下 ,默认会生成一列 id 列,用来做表的主键.ForeignKey 字段默认会关联表的id列.
增加数据
向 UserType插入数据
dic1 ={"caption":"AAA"} models.UserType.objects.create(**dic1) dic2 ={"caption":"BBB"} models.UserType.objects.create(**dic2) dic3 ={"caption":"CCC"} models.UserType.objects.create(**dic3)
此时,我们向 UserType 表插入了三条数据, 因不涉及其他表,正常操作即可
向 UserInfo 插入数据:
第一种方式:
dic = {"username":"user01","age":12,"user_type":models.UserType.objects.get(id=2)} models.UserInfo.objects.create(**dic)
第二种方式:
dic = {"username":"N","age":12,"user_type_id":1} models.UserInfo.objects.create(**dic)
两种方式都可以,两种方式的区别是 UserInfo 表中的user_type 列 在django中实际上一个对象,这个对象就是UserType表, 在数据表中 UserInfo表的 实际字段是user_type_id , 因为这个区别, 就有了这两种数据插入的方式.
查询数据
正向查询:
这里的正常查是指从ForeignKey字段所在的表,向被关联的表查询, 以上面的数据表为例:
UserInfo表中的user_type为 ForeignKey 字段, 关联了 UserType表
查询数据的方式 是从 UserInfo 表查询 UserType表的数据
如果我们查询UserInfo 表中 所有用户类型为 AAA 的用户 , 那么语句为:
models.UserInfo.objects.filter(user_type__caption="AAA")
注意 : 这里的双下划线
UserInfo 表中的 user_type 字段 为一个对象, 每行对应 UserType表中的一条数据, 此时 ,我们使用 字段名 + 双下划线 即可 在UserInfo 表中查询 UserType 表的数据.
在我们查询数据的时候,如果需要跨表查询 ,那么我们只需使用关联的模型字段的名称,并使用双下划线分隔,直至你想要的字段
反向查询:
UserType 表中的一条数据 对应 UserInfo表中的多条数据, 如果我们希望通过 UserType 表 查询 UserInfo 表中的数据的话,查询语句为:
line = models.UserType.objects.get(id=2) line.userinfo_set.filter(username="N") # 这一行是通过UserType 去UserInfo里查数据 models.UserInfo.objects.filter(user_type=line).filter(username="N") # 等价于 上一行
例:
获取 用户 A 所属的用户类型,有多少人
models.UserType.objects.get(userinfo__username="A").userinfo_set.all().count()
注意:
userinfo_set 的来历:
_set 是 Django 也提供反向获取关联对象的 API ,
django在创建数据库的时候.自动给 UserType 表创建了一个 userinfo (和关联UserType的 UserInfo 表同名 , 但这里是小写) , 这里的 userinfo_set 对应的就是 UserInfo 表, 可以通过userinfo_set 在UserInfo表中进行数据查询.
一对多 总结
创建数据:
两种方式:
1. 直接使用 models中 设置的字段名
2. 使用models 中设置的字段名 + _id
正向查询
filter(对象__跨表字段名) #使用filter时
对象.跨表字段名 # 直接查询时
反向查询
filter() 自动创建的同名(小写)的对象__跨表的字段名
自动创建的同名(小写)的对象_set.filter()
多对多 :ManyToManyField
多对多的工作方式和一对多类似.
在使用多对多的时候, 会为关联的两张表 创建一张中间表, 用中间表来关联两张表.
创建表结构
class Host(models.Model): hostname = models.CharField(max_length=32) port = models.IntegerField() class HostAdmin(models.Model): username = models.CharField(max_length=32) email = models.CharField(max_length=32) host = models.ManyToManyField(Host)
增加数据:
models.Host.objects.create(hostname="Host1",port=1024) models.Host.objects.create(hostname="Host2",port=1024) models.Host.objects.create(hostname="Host3",port=1024)
models.HostAdmin
.objects.create(username="user01",email="a@a.com") models.HostAdmin.objects.create(username="user02",email="b@a.com") models.HostAdmin.objects.create(username="user03",email="c@a.com")
在向两张表中插入数据的时候, 并不需要设置表数据之间的关联.
关联两张表的数据的时候,有两种方式,
正向添加
admin_obj = models.HostAdmin.objects.get(username="someone") # 获取用户对象 host_list = models.Host.objects.filter(id__lt=3) # 获取指定主机 admin_obj.host.add(*host_list) # 将获取到的主机添加到 中间表
反向添加
host_obj = models.Host.objects.get(id=3) #获取主机对象 admin_list = models.HostAdmin.objects.filter(id__gt=1) # 获取指定条件的管理员 host_obj.hostadmin_set.add(*admin_list) # 将数据添加到中间表
自定义中间表 (推荐使用)
有的时候,我们希望可以使用自定义的关联两张表的中间表,除了系统自动生成的字段,我们还可以添加其他字段.
创建表
class Host1(models.Model): hostname = models.CharField(max_length=32) port = models.IntegerField() class HostAdmin1(models.Model): username = models.CharField(max_length=32) email = models.CharField(max_length=32) host = models.ManyToManyField(Host1, through=‘HostRelation‘) class HostRelation(models.Model): c1 = models.ForeignKey(Host1) c2 = models.ForeignKey(HostAdmin1)
通过使用 through= " " 可以设置使用指定的中间表 .
多对多的查询方法也分正向查和反向查, 用法和一对多 一样. 学会了一对多的使用,也就学会多对多的使用.需要注意的是, 未使用自定义中间表的时候, 需要使用关联的两张表去找到中间表,再进行查询.
使用自定义中间表后, 因为中间表 是我们指定的. 我们可以直接操作中间表, 而未使用自定义中间表的时候 ,我们需要使用关联表去查询中间表的数据, 相比较来说, 使用自定义表的方法更直观,更接近数据库中表关系. 在实际使用过程中, 还是推荐使用自定义中间表的方式.
本文出自 “Will的笔记” 博客,请务必保留此出处http://timesnotes.blog.51cto.com/1079212/1765868
python学习笔记-Day022 - django ORM操作
原文:http://timesnotes.blog.51cto.com/1079212/1765868