一对多: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= " "  可以设置使用指定的中间表 . 


多对多的查询方法也分正向查和反向查, 用法和一对多 一样. 学会了一对多的使用,也就学会多对多的使用.需要注意的是, 未使用自定义中间表的时候, 需要使用关联的两张表去找到中间表,再进行查询.


使用自定义中间表后,  因为中间表 是我们指定的. 我们可以直接操作中间表, 而未使用自定义中间表的时候 ,我们需要使用关联表去查询中间表的数据, 相比较来说, 使用自定义表的方法更直观,更接近数据库中表关系. 在实际使用过程中, 还是推荐使用自定义中间表的方式.