django.relatedField-关联域

本文详细介绍了Django Model中几种特殊的关系字段,如ForeignKey、ManyToMany、OneToOne等,通过实例展示了如何创建和操作这些关系,以及如何查询和过滤相关数据。重点强调了从模型本身的含义出发理解字段的重要性,而不是仅仅从数据库角度考虑。
在django的model中,有几个特殊的field,来表示model之间的关系。比如ForeignKey,ManyToMany,OnetoOne

对于django的model,尤其是related field,我建议从model的本身含义出发,而不要从数据库的角度去看。

related_field仅仅是表示model之间的关系,至于数据库的实现,需要的时候再去了解。这样才能比较容易的理解django的model设计思想。

比如ForeignKey的含义,就是多对一的关系。这里并非字段的对应,而是model的对应。也就是说,有多个model对应一个model。所以ForeignKey在django中,就是表示model的含义,而非字段。

ManyToManyField的含义,也是指定多个model对应于多个model的关系。

先建立所需的model:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class  Color(models.Model):
     name  =  models.CharField(max_length = 10 )
     
     def  __str__( self )
         return  self .name
 
 
class  Fruit(models.Model):
     name  =  models.CharField(max_length = 10 )
     price  =  models.IntegerField()
     color  =  models.ForeignKey(Color)
     
     def  __str__( self )
         return  self .name
 
class  Area(models.Model):
     province  =  models.CharField(max_length = 10 )
     fruits  =  models.ManyToManyField(Fruit)
     
     def  __str__( self )
         return  self .name
 
class  User(models.Model):
     name  =  models.CharField(max_length = 10 )
     fruits  =  models.ManyToManyField(Fruit, related_name = 'related_name' , related_query_name = 'related_query_name' )
     
     def  __str__( self )
         return  self .name


Fruit与Area是多对多的关系, 一个地区会生产多种水果,而一种水果也会被多个地区生产。

Fruit与User是多对多的关系,一个用户可以喜欢多种水果,而一种水果也会被多个用户喜欢。

Fruit与Color是多对一,一种水果相对有一种颜色。


插入数据:

首先向Color插入数据:

?
1
2
3
4
5
6
>>> color_red  =  Color(name = 'red' )
>>> color_yellow  =  Color(name = 'yellow' )
>>> color_red.save()
>>> color_yellow.save()
>>> color_green  =  Color(name = 'green' )
>>> color_green.save()

然后向Fruit插入数据。注意color是Fruit的外键,所以添加时,需要指定color为Color的实例。

?
1
2
3
4
5
6
>>> apple  =  Fruit(name = 'apple' , price = 10 , color = color_red)
>>> apple.save()
>>> orange  =  Fruit(name = 'orange' , price = 5 , color = color_yellow)
>>> orange.save()
>>> watermelon  =  Fruit(name = 'watermelon' , price = 20 , color = color_green)
>>> watermelon.save()

然后向Area添加数据。注意Area和Fruit是多对多的关系,必须先保存,然后在来指定两者的关系。

?
1
2
3
4
5
6
7
>>> shanghai  =  Area(province = 'shanghai' )
>>> shanghai.save()
>>> guangzhou  =  Area(province = 'guangzhou' )
>>> guangzhou.save()
 
>>> shanghai.fruits.add(apple)
>>> apple.area_set.add(guangzhou)

    关系的添加和删除是由ManyRelatedManager对象管理的。

    它的获取方式与ManyToManyField的定义的位置有关。

    如果在有ManyToManyField的model中,直接提取字段名就可以。

    在没有ManyToManyField的model中, 使用related_name获取,如果没有默认为xxx_set, xxx为对应的model名。

向User添加数据,

?
1
2
3
4
5
6
7
8
>>> jack  =  User(name = 'jack' )
>>> jack.save()
>>> jack.fruits.add(apple)
>>> orange.related_name.add(jack)
 
>>> july  =  User(name = 'july' )
>>> july.save()
>>> july.fruits.add(apple)


查询数据

查询有喜欢apple的user

?
1
2
>>> User.objects. filter (fruits__name = 'apple' )
<User: jack>, <User: july>]

这里使用了双下划线, xxxx1__xxxx2。

xxxx1的获取,

    分为两种情况

  1. ManyToManyField在model中

    直接获取其字段名

  2. ManyToManyField不在model中

        a.  获取ManyToManyField的related_query_name属性。

        b. 获取ManyToManyField的related_name属性。

        c. 获取对应model名的小写格式。

xxxx2即为字段名。


查询有用户是jack的喜欢的水果

?
1
2
3
4
5
>>> Fruit.objects. filter (related_query_name__name = 'jack' )
[<Fruit: apple>, <Fruit: orange>]
>>>
>>> User.objects.get(name = 'jack' ).fruits. all ()
[<Fruit: apple>, <Fruit: orange>]


查询用户名是j开头的喜欢的水果

?
1
2
>>> Fruit.objects. filter (related_query_name__name__startswith = 'j' )
[<Fruit: apple>, <Fruit: orange>, <Fruit: apple>]


这里指定了related_name和related_query_name的属性值,比较特殊,是为了更好的解释其作用。

一般来说,我习惯把related_name设为model的名字加上s, related_query_name设为model的名。

比如上面的User中fruits字段, 

?
1
fruits  =  models.ManyToManyField(Fruit, related_name = 'users' , related_query_name = 'user' )


最后有一点注意到,如果一个model会有两个指向同一个model的外键。那么这两个外键必须指定related_name,并且还不能相同。举例来说:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
class  User(models.Model):
     name  =  models.CharField(max_length = 20 )
     
     def  __str__( self ):
         return  self .name
 
class  Message(models.Model):
     content  =  models.CharField(max_length = 200 )
     sender  =  models.ForeignKey(User, related_name = 'send_messages' )
     receiver  =  models.ForeignKey(User, related_name = 'receive_messages' )
     
     def  __str__( self ):
         return  self .content

写数据:

?
1
2
3
4
5
6
7
8
9
10
>>> names  =  [ 'Mary' 'Jim' 'Sam' ]
>>>  for  name  in  names:
         user  =  User(name = name)
         user.save()
>>>  import  itertools
>>> users  =  User.objects. all ()
>>>  for  sender, receiver  in  itertools.permutations(users,  2 ):
         content  =  '%s-to-%s'  %  (sender.name, receiver.name)
         msg  =  Message(content = content, sender = sender, receiver = receiver)
         msg.save()

在上面代码中,实例化三个人Mary,Jim,Sam。并且都互相发送了短信。

?
1
2
3
4
5
6
7
8
9
>>> Mary  =  User.objects.get(name = 'Mary' )
 
# get messages which Mary sends
>>> Mary.send_messages. all ()
[<Message: Mary - to - Jim>, <Message: Mary - to - Sam>]
 
# get messages which Mary reveives
>>> Mary.receive_messages. all ()
[<Message: Jim - to - Mary>, <Message: Sam - to - Mary>]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值