多表查詢是模型層的重要功能之一, Django提供了一套基於關聯字段獨特的解決方案.html
來自Django官方文檔的模型示例:python
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() class Author(models.Model): name = models.CharField(max_length=50) email = models.EmailField() class Entry(models.Model): blog = models.ForeignKey(Blog) authors = models.ManyToManyField(Author) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField()
ForeignKey字段接受一個Model類做爲參數, 類型與被參照的字段徹底相同:程序員
blog = models.ForeignKey(Blog)
關聯到的關聯對象的字段名稱。默認地,Django 使用關聯對象的主鍵。數據庫
blog = models.ForeignKey(Blog, to_field=Blog.name)
Django Model的ForeignKey字段的主要功能是維護一個一對多的關係, 以進行關聯查詢.django
只有在db_constraint=True
時Django model纔會在數據庫上創建外鍵約束, 在該值爲False時不創建約束.this
默認db_constraint=True
.spa
這個名稱用於讓關聯的對象反查到源對象.code
若是你不想讓Django 建立一個反向關聯,請設置related_name 爲 '+' 或者以'+' 結尾.htm
ForeignKey.related_query_name
以ForeignKey.related_name
做爲默認值, 二者功能的具體說明請參見相關文檔對象
若關係模型A包含與模型B關聯的關聯字段, 模型A的實例能夠經過關聯字段訪問與其關聯的模型B的實例:
>>> e = Entry.objects.get(id=2) >>> e.blog # Returns the related Blog object.
修改e.blog並調用save方法存入數據庫
>>> e.blog = some_blog >>> e.save()
若是ForeignKey 字段有null=True 設置(即它容許NULL值),能夠分配None來刪除對應的關聯性
>>> e = Entry.objects.get(id=2) >>> e.blog = None >>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"
Django提供了一種使用雙下劃線__
的查詢語法:
>>> Entry.objects.filter(blog__name='Beatles Blog')
被索引的關係模型能夠訪問全部參照它的模型的實例,如Entry.blog做爲Blog的外鍵,默認狀況下Blog.entry_set是包含全部參照Blog的Entry示例的查詢集,可使用查詢集API取出相應的實例。
>>>b = Blog.objects.get(id=1) >>>b.entry_set.all()
Entry.blog的related_name和related_query_name能夠設置該查詢集的名字。
來自Django官網的示例:
from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership', through_fields=('group', 'person')) class Membership(models.Model): group = models.ForeignKey(Group) person = models.ForeignKey(Person) inviter = models.ForeignKey(Person, related_name="membership_invites") invite_reason = models.CharField(max_length=64)
Django 會自動建立一個表來管理多對多關係, 若要手動指定關聯表則須要使用through關鍵字參數.
上文示例中Membership 有兩個外鍵指向Person (person 和inviter),這使得關聯關係含混不清並讓Django 不知道使用哪個。
在這種狀況下,必須使用through_fields 明確指定Django 應該使用哪些外鍵
through_fields 接收一個二元組('field1', 'field2'),其中field1 爲指向定義ManyToManyField 字段的模型的外鍵名稱(本例中爲group),field2 爲指向目標模型的外鍵的名稱(本例中爲person).
默認狀況下,關聯表的名稱使用多對多字段的名稱和包含這張表的模型的名稱以及Hash值生成,如:memberShip_person_3c1f5
若要想要手動指定表的名稱,可使用db_table
關鍵字參數指定.
下列API和ForeignKey中的同名API相同.
ManyToManyField.db_constraint
ManyToManyField.related_name
ManyToManyField.related_query_name
多對多關係和ForeignKey具備類似的API.
>>>e = Group.objects.get(id=3) >>>e.members.all() # Returns all members objects for this Group.
反向查詢:
>>>a = Person.objects.get(id=1) >>>a.group_set.all()
一樣related_name能夠設置反向查詢集的名稱。
由於ManyToManyField自動維護關聯表,程序員不便於直接訪問.ManyToManyField提供了API用於添加和刪除關聯(即through表中的記錄).
使用一個自動維護through表的模型做爲示例:
class User(models.Model): user_id = models.IntegerField(primary_key=True) class Flight(models.Model): flight_id = models.IntegerField(primary_key=True) reserve = models.ManyToManyField(User, related_name='flight_reserve')
首先得到要進行關聯的Flight和User實例:
flights = Flight.objects.filter(flight_id=flight_id) if flights.count() != 0: flight = flights[0] users = User.objects.filter(id=user_id) if users.count() != 0: user = users[0]
經過擁有關聯字段的Flight實例進行添加關聯操做:
flight.reserve.add(user) flight.save()
刪除操做與這相似:
flight.reserve.remove(user) flight.save()
參考資料: