Django学习笔记:Models03 关系类型字段

多对一(ForeignKey)

多对一关系由外键实现,外键要定义在“多”的一方,如:

models.ForeignKey(<主表>, ...)


如果要关联的主表在另一个app中,要显式的指出:

models.ForeignKey(’.<主表>‘, ...)

 

可创建自己关联自己的外键——比如,在评论系统中,一条评论可被多次引用自身并继续评论:

class Comment(models.Model):

    title = models.Charfield(max_length=128)

    text = models.TextField()

    parent_comment = models.ForeignKey(’self’, on_delete=models.CASCADE)

    ...


如果在子模型中存在多个外键指向同一个主模型,必须给他们加上不同的related_name,用于反向查询。

外键字段在数据库中的列名是<外键名>_id,用来储存主表对象的id,因此,在得到主表id的情况下可以不调用外键而直接筛选:

QuerySet = <外键表>.filter(<外键名>_id=<主表id>)

#获得与“<主表id>=xxx的主对象”相关联的子对象


多对一的字段参数

on_delete=models.XXX

当主对象被删除时,关联的子对象的操作(因为主键不能随意删除,外键可以直接删除)

models.CASCADE:同时删除关联的子对象,Django默认

models.PROTECT:阻止CASCADE删除关联的子对象,并弹出ProtectedError异常

models.SET_NULL:将子对象的外键字段设为null(外键字段需设置null=True)

models.SET_DEFAULT:将子对象的外键字段设为默认值(外键字段需设置default=’xxx’)

models.DO_NOTHING:什么也不做

models.SET():设置为一个传递给SET()的值或一个回调函数的返回值

注:on_delete是Django2.0之后新增的必选项。


related_name= 

通过主对象反向引用子对象的通道名称,默认名称是<小写子模型名>_set。

如:

class Car(models.Model):

    factory = models.ForeignKey(

        Factory,      

        on_delete=models.CASCADE,

        related_name='car_by_factory',

    )

此时Factory主表取出所有关联的Car对象:factory.car_by_factory.all()

如果不想给外键设置反向关联名称,就用related_name=’+’或以+号结尾


related_query_name= 

主对象反向关联查询的名称,默认查询名称是<外键列>__<主表的某列>。

如:

class Tag(models.Model):

    article = models.ForeignKey(

        Article,

        on_delete=models.CASCADE,

        related_query_name="tag",

    )

    name = models.CharField(max_length=255)

此时用tag作为查询名称:Article.objects.filter(tag__name="A")


limit_choices_to={}

限制外键能关联的对象,用于Django的表单模块和admin后台,可以传入字典、Q对象、一个返回字典或Q对象的函数。

如:

staff_member = models.ForeignKey(

    User,

    on_delete=models.CASCADE,

    limit_choices_to={'is_staff': True},

)

此时,表单模块的staff_member字段列表中只会出现is_staff=True的Users对象,对admin后台非常有用。


to_field= 

让外键关联到指定的字段上(默认关联到主键),该字段必须有unique=True属性。


多对一的引用

子对象引用主对象:

<子对象>.<外键列>


主对象引用子对象:

<主对象>.<子表小写>_set

如:

<主对象>.<子表小写>_set.all()                          #所有关联子对象的集合

<主对象>.<子表小写>_set.create(<子表字段>=’xxx’, ...)     #创建关联的子对象

<主对象>.<子表小写>_set.count()                       #查询关联子对象的数量


添加多对一关系:

<子对象>.<外键列> = <主对象>

<子对象>.save()


删除多对一关系:

<子对象>.<外键列> = None     #外键列要设为null=True


多对一的查询

查询子对象的集合:

<子表>.objects.filter(<外键列>__<主表的某列>=’xxx’)

#获得与“<主表的某列>=xxx的主对象”相关联的子对象


查询主对象的集合:

<主表>.objects.filter(<子表小写> __<子表的某列>=’xxx’)

#获得与“<子表的某列>=xxx的子对象”相关联的主对象



多对多(ManyToManyField)

多对多字段可定义在任意一方,如:

models.ManyToManyField(‘<主表>’)

多对多字段不支持Django内置的validators验证功能。

null参数对ManyToManyField多对多字段无效,设置null=True毫无意义。

如果在子模型中存在多个多对多键指向同一个主模型,必须给他们加上不同的related_name,用于反向查询。


采用默认中间表的数据库结构:

<中间表id>  <多对多表>_id   <主表>_id

默认中间表通过保存两张表的id进行关联


采用自定义中间表并添加新字段的数据库结构:

<中间表id>  <新字段1>  <新字段2>  <多对多表>_id   <主表>_id


多对多字段的参数

related_name= 

主对象反向引用多对象时的名称,和多对一相同。


related_query_name= 

主对象反向关联查询的名称,和多对一相同。


through= 

自定义中间表,用于保存两表关系的附加数据,中间表要有两个外键字段分别指向关联的两个模型。


through_fields=(<字段1>, <字段2>)

当中间表有多个外键指向一个表的时候,用through_firlds指定中间表的两个连接字段,如:

class Person(models.Model):

    name = models.CharField(max_length=32)


class Group(models.Model):

    name = models.CharField(max_length=64)

    members = models.ManyToManyField(

        Person,

        through='Membership',

        through_fields=('group', 'person' ),     #指定两个连接字段

    )


class Membership(models.Model):

    group = models.ForeignKey(Group, on_delete=models.CASCADE)

    person = models.ForeignKey(Person, on_delete=models.CASCADE)

    inviter = models.ForeignKey(                       #另一个指向Person表的外键

        Person,

        on_delete=models.CASCADE,

        related_name="membership_invites",

    )

    invite_reason = models.CharField(max_length=128)


db_table= 

设置中间表的名称,默认为<多对多字段名>_<主表名>_<一串哈希码>


limit_choices_to={ }

限制多对多键关联的对象,和多对一相同,对于用through定义中间表的字段无效。

 

多对多的引用

多对象引用主对象:

<多对象>.<多键列>


主对象引用多对象:

<主对象>.<多表小写>_set


添加多对多关系:(默认中间表)

<多对象>.<多键列>.add(<主对象>)     #可同时添加多个主对象


添加多对多关系:(自定义中间表)

a = <主对象>

b = <多对象>

membership = <中间表>(<主表外键列>=a, <多表外键列>=b, <字段1>=’xxx’, <字段2>=’xxx’, ...)

membership.save()

#先创建主表和多表的实例,再创建中间表的连接关系

#自定义中间表不能用add()、create()、remove()和set()操作对象的关系


删除多对多关系:

<多对象>.<多键列>.clear()


获取中间表的附加数据:

a = <主对象>

b = <多对象>

membership = <中间表>.objects.get(<主表外键列>=a, <多表外键列>=b)

membership.<字段1>     #获取字段信息



一对一(OneToOneField)

反向关联的对象只有一个,多数用于从一个模型扩展出另一个模型的情况。

一对一通过子对象访问关联的主对象:

<子对象>.<一对一键>


一对一通过主对象访问关联的子对象:

<主对象>.<小写子模型名>

注意返回的是单个对象而不是集合。

你可能感兴趣的:(Django学习笔记:Models03 关系类型字段)