Django-Model中的ForeignKey,ManyToManyField与OneToOneField
關(guān)聯(lián)關(guān)系字段 (Relationship fields)
ForeignKey,ManyToManyField與OneToOneField分別在Model中定義多對(duì)一,多對(duì)多,一對(duì)一關(guān)系。
例如,一本書由一家出版社出版,一家出版社可以出版很多書。一本書由多個(gè)作者合寫,一個(gè)作者可以寫很多書。
class Author(models.Model): name=models.CharField(max_length=20) class Publisher(models.Model): name=models.CharField(max_length=20) class Book(models.Model): name=models.CharField(max_length=20) pub=models.ForeignKey(Publisher) authors=models.ManyToManyField(Author)1.關(guān)聯(lián)尚未定義的Model
如果你要與某個(gè)尚未定義的 model 建立關(guān)聯(lián) ,就使用 model 的名稱,而不是使用 model 對(duì)象本身。
例子中,如果Publisher與Author在Book后面定義,需要寫成下面的形式:
class Book(models.Model):name=models.CharField(max_length=20) pub=models.ForeignKey('Publisher') authors=models.ManyToManyField('Author')2.Model關(guān)聯(lián)自身
Model可以與自身做多對(duì)一關(guān)系
class People(models.Model):name=models.CharField(max_length=20) leader=models.ForeignKey('self',blank=True,null=True)Model也可以與自身做多對(duì)多關(guān)系
class Person(models.Model):friends = models.ManyToManyField("self")默認(rèn)情況下,這種關(guān)聯(lián)關(guān)系是對(duì)稱的,如果Person1是Person2的朋友,那么Person2也是Person1的朋友
p1=Person() p1.save() p2=Person() p2.save() p3=Person() p3.save() p1.friends.add(p2,p3)上述情況下,要查找p3的朋友,不用p3.person_set.all(),而直接用p3.friends.all()就可以了
如果想取消這種對(duì)稱關(guān)系,將symmetrical設(shè)為False
class Person2(models.Model):friends=(models.ManyToManyField("self",symmetrical=False)這樣查詢p3的朋友,就需要p3.person_set.all()了
3.反向名稱related_name
反向名稱,用來從被關(guān)聯(lián)字段指向關(guān)聯(lián)字段??? 。
注意,在你定義 抽象 model (abstract models) 時(shí),你必須顯式指定反向名稱; 只有在你這么做??? 了之后, 某些特別語法 (some special syntax) 才能正常使用。?
class Book(models.Model):name=models.CharField(max_length=20) pub=models.ForeignKey(Publisher,related_name='pub') authors=models.ManyToManyField(Author,related_name='author')這樣用Publisher或者Author反向查詢Book時(shí)可以用related_name了:publisher1.pub.all()或者author1.author.all()。
如果不想設(shè)置反向關(guān)系,設(shè)置related_name為'+'或者以'+'結(jié)束。
user = models.ForeignKey(User, related_name='+')如果有多個(gè)ManyToManyField指向同一個(gè)Model,這樣反向查詢FOO_set的時(shí)候就無法弄清是哪個(gè)ManyToManyField字段了,可以禁止反向關(guān)系:
users = models.ManyToManyField(User, related_name='u+') referents = models.ManyToManyField(User, related_name='ref+')4.數(shù)據(jù)庫(kù)表現(xiàn) (Database Representation)
多對(duì)一:Django 使用ForeignKey字段名稱+ "_id" 做為數(shù)據(jù)庫(kù)中的列名稱。在上面的例子中,BOOK model 對(duì)應(yīng)的數(shù)據(jù)表中會(huì)有 一個(gè) publisher_id 列。?
你可以通過顯式地指定 db_column 來改變?cè)撟侄蔚牧忻Q,不過,除非你想自定 義 SQL ,否則沒必要更改數(shù)據(jù)庫(kù)的列名稱。
多對(duì)多:Django 創(chuàng)建一個(gè)中間表來表示ManyToManyField關(guān)系。默認(rèn)情況下,中間表的名稱由兩個(gè)關(guān)系表名結(jié)合而成。?
由于某些數(shù)據(jù)庫(kù)對(duì)表名的長(zhǎng)度有限制,所以中間表的名稱會(huì)自動(dòng)限制在64個(gè)字符以內(nèi),并包含一個(gè)不重復(fù)的哈希字符串。這
意味著,你可能看到類似 book_authors_9cdf4 這樣的表名稱。你可以使用 db_table 選項(xiàng)手動(dòng)指定中間表名稱。
但是,如果你想手動(dòng)指定中間表,你可以用 through 選項(xiàng)來指定model 使用另外某個(gè) model 來管理多對(duì)多關(guān)系。而這個(gè) model 就是中間表所對(duì)應(yīng)的 model :
class Person(models.Model): name = models.CharField(max_length=128) def __unicode__(self): return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') def __unicode__(self): return self.name class Membership(models.Model): person = models.ForeignKey(Person) group = models.ForeignKey(Group) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)這樣,就可以記錄某個(gè)person何時(shí)加入group了。
要建立Person與Group的關(guān)系就不能用add,create,remove了,而是需要通過Membership進(jìn)行。
>>> ringo = Person.objects.create(name="Ringo Starr") >>> paul = Person.objects.create(name="Paul McCartney") >>> beatles = Group.objects.create(name="The Beatles") >>> m1 = Membership(person=ringo, group=beatles, ... date_joined=date(1962, 8, 16), ... invite_reason= "Needed a new drummer.") >>> m1.save()clear()還是可以使用的
>>> beatles.members.clear()當(dāng)多對(duì)多關(guān)系關(guān)聯(lián)自身時(shí),中間表的ForeignKey是可以指向同一個(gè)Model的,但是它們必須被看做ManyToManyField的兩邊,而不是對(duì)稱的,需要設(shè)置???? symmetrical=False。
5.其它參數(shù) (Arguments)
5.1 ForeignKey接受下列這些可選參數(shù),這些參數(shù)定義了關(guān)系是如何運(yùn)行的。?
ForeignKey.limit_choices_to
它是一個(gè)包含篩選條件和對(duì)應(yīng)值的字典,用來在 Django 管理后臺(tái)篩選 關(guān)聯(lián)對(duì)象。例如,利用 Python 的 datetime 模塊,過濾掉不符合篩選條件關(guān)聯(lián)對(duì)象:
limit_choices_to = {'pub_date__lte': datetime.date.today}
只有 pub_date 在當(dāng)前日期之前的關(guān)聯(lián)對(duì)象才允許被選。
也可以使用 Q 對(duì)象來代替字典,從而實(shí)現(xiàn)更復(fù)雜的篩選。當(dāng)limit_choices_to為Q對(duì)象時(shí),如果把此外鍵字段放在ModelAdmin的raw_id_fields時(shí)是不可用的。
ForeignKey.to_field
指定當(dāng)前關(guān)系與被關(guān)聯(lián)對(duì)象中的哪個(gè)字段關(guān)聯(lián)。默認(rèn)情況下,to_field 指向被關(guān)聯(lián)對(duì)象的主鍵。
ForeignKey.on_delete
當(dāng)一個(gè)model對(duì)象的ForeignKey關(guān)聯(lián)的對(duì)象被刪除時(shí),默認(rèn)情況下此對(duì)象也會(huì)一起被級(jí)聯(lián)刪除的。
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)CASCADE:默認(rèn)值,model對(duì)象會(huì)和ForeignKey關(guān)聯(lián)對(duì)象一起被刪除?
SET_NULL:將model對(duì)象的ForeignKey字段設(shè)為null。當(dāng)然需要將null設(shè)為True。
SET_DEFAULT:將model對(duì)象的ForeignKey字段設(shè)為默認(rèn)值。
Protect:刪除ForeignKey關(guān)聯(lián)對(duì)象時(shí)會(huì)生成一個(gè)ProtectedError,這樣ForeignKey關(guān)聯(lián)對(duì)象就不會(huì)被刪除了。
SET():將model對(duì)象的ForeignKey字段設(shè)為傳遞給SET()的值。
def get_sentinel_user():return User.objects.get_or_create(username='deleted')[0] class MyModel(models.Model): user = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user))DO_NOTHING:啥也不做。
5.2 ManyToManyField接受下列可選參數(shù),這些參數(shù)定義了關(guān)系是如何運(yùn)行的。?
ManyToManyField.limit_choices_to
和 ForeignKey.limit_choices_to 用法一樣。
limit_choices_to 對(duì)于通過 through 參數(shù)指定了中介表的 ManyToManyField 不起作用。
ManyToManyField.symmetrical
只要定義遞歸的多對(duì)多關(guān)系時(shí)起作用。
ManyToManyField.through
手動(dòng)指定中間表
ManyToManyField.db_table
指定數(shù)據(jù)庫(kù)中保存多對(duì)多關(guān)系數(shù)據(jù)的表名稱。如果沒有提供該選項(xiàng),Django 就會(huì)根據(jù)兩個(gè)關(guān)系表的名稱生成一個(gè)新的表名,做為中間表的名稱。
6.OneToOneField
class OneToOneField(othermodel[, parent_link=False, **options])
用來定義一對(duì)一關(guān)系。籠統(tǒng)地講,它與聲明了 unique=True 的 ForeignKey 非常相似,不同的是使用反向關(guān)聯(lián)的時(shí)候,得到的不是一個(gè)對(duì)象列表,而是一個(gè)單獨(dú)的對(duì)象。
在某個(gè) model 擴(kuò)展自另一個(gè) model 時(shí),這個(gè)字段是非常有用的;例如: 多表繼承 (Multi-tableinheritance) 就是通過在子 model 中添加一個(gè)指向父 model 的一對(duì)一關(guān)聯(lián)而實(shí)現(xiàn)的。
必須給該字段一個(gè)參數(shù):被關(guān)聯(lián)的 model 類。工作方式和 ForeignKey 一樣,連遞歸關(guān)聯(lián) (recursive) 和 延后關(guān)聯(lián) (lazy) 都一樣。
此外,OneToOneField 接受 ForeignKey 可接受的參數(shù),只有一個(gè)參數(shù)是 OnetoOneField 專有的:OneToOneField.parent_link
如果為 True ,并且作用于繼承自某個(gè)父 model 的子 model 上(這里不能是延后繼承,父 model 必須真實(shí)存在 ),那么該字段就會(huì)變成指向父類實(shí)例的引用(或者叫鏈接),
而不是象其他OneToOneField 那樣用于擴(kuò)展父類并繼承父類屬性。
from django.db import models, transaction, IntegrityErrorclass Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) def __unicode__(self): return u"%s the place" % self.name class Restaurant(models.Model): place = models.OneToOneField(Place, primary_key=True) serves_hot_dogs = models.BooleanField() serves_pizza = models.BooleanField() def __unicode__(self): return u"%s the restaurant" % self.place.name class Waiter(models.Model): restaurant = models.ForeignKey(Restaurant) name = models.CharField(max_length=50) def __unicode__(self): return u"%s the waiter at %s" % (self.name, self.restaurant)使用反向關(guān)聯(lián)的時(shí)候,得到的不是一個(gè)對(duì)象列表,而是一個(gè)單獨(dú)的對(duì)象:
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton') >>> p1.save() >>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False) >>> r.save() >>> p1.restaurant <Restaurant: Demon Dogs the restaurant> >>> Place.objects.get(restaurant__place__name__startswith="Demon") <Place: Demon Dogs the place> >>> Waiter.objects.filter(restaurant__place__name__startswith="Demon")轉(zhuǎn)載于:https://www.cnblogs.com/weiming-cheng/p/5319803.html
總結(jié)
以上是生活随笔為你收集整理的Django-Model中的ForeignKey,ManyToManyField与OneToOneField的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js 终止页面加载
- 下一篇: 十分钟搞懂什么是CGI