對於django的model,尤爲是related field,我建議從model的自己含義出發,而不要從數據庫的角度去看。python
related_field僅僅是表示model之間的關係,至於數據庫的實現,須要的時候再去了解。這樣才能比較容易的理解django的model設計思想。數據庫
好比ForeignKey的含義,就是多對一的關係。這裏並不是字段的對應,而是model的對應。也就是說,有多個model對應一個model。因此ForeignKey在django中,就是表示model的含義,而非字段。
django
ManyToManyField的含義,也是指定多個model對應於多個model的關係。app
先創建所需的model:ui
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是多對多的關係, 一個地區會生產多種水果,而一種水果也會被多個地區生產。
spa
Fruit與User是多對多的關係,一個用戶能夠喜歡多種水果,而一種水果也會被多個用戶喜歡。設計
Fruit與Color是多對一,一種水果相對有一種顏色。code
插入數據:
orm
首先向Color插入數據:對象
>>> 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的實例。
>>> 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是多對多的關係,必須先保存,而後在來指定二者的關係。
>>> 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添加數據,
>>> 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
>>> User.objects.filter(fruits__name='apple') <User: jack>, <User: july>]
這裏使用了雙下劃線, xxxx1__xxxx2。
xxxx1的獲取,
分爲兩種狀況
ManyToManyField在model中
直接獲取其字段名
ManyToManyField不在model中
a. 獲取ManyToManyField的related_query_name屬性。
b. 獲取ManyToManyField的related_name屬性。
c. 獲取對應model名的小寫格式。
xxxx2即爲字段名。
查詢有用戶是jack的喜歡的水果
>>> Fruit.objects.filter(related_query_name__name='jack') [<Fruit: apple>, <Fruit: orange>] >>> >>> User.objects.get(name='jack').fruits.all() [<Fruit: apple>, <Fruit: orange>]
查詢用戶名是j開頭的喜歡的水果
>>> 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字段,
fruits = models.ManyToManyField(Fruit, related_name='users', related_query_name='user')
最後有一點注意到,若是一個model會有兩個指向同一個model的外鍵。那麼這兩個外鍵必須指定related_name,而且還不能相同。舉例來講:
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
寫數據:
>>> 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。而且都互相發送了短信。
>>> 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>]