W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
模型中最重要且唯一必要的是數(shù)據(jù)庫(kù)的字段定義。字段在類屬性中定義。定義字段名時(shí)應(yīng)小心避免使用與 模型 API 沖突的名稱, 如 ??clean
??, ??save
??或 ??delete
??等.
例如:
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
模型中每一個(gè)字段都應(yīng)該是某個(gè) ??Field
?類的實(shí)例, Django 利用這些字段類來(lái)實(shí)現(xiàn)以下功能:
INTEGER
??, ??VARCHAR
??, ??TEXT
??)。<input type="text">
??, ??<select>
??)。Django 內(nèi)置了數(shù)十種字段類型,如果 Django 內(nèi)置類型不能滿足你的需求,你可以很輕松地編寫自定義的字段類型。
每一種字段都需要指定一些特定的參數(shù)。 例如, ??CharField
??(以及它的子類)需要接收一個(gè) ??max_length
??參數(shù),用以指定數(shù)據(jù)庫(kù)存儲(chǔ) ??VARCHAR
??數(shù)據(jù)時(shí)用的字節(jié)數(shù)。一些可選的參數(shù)是通用的,可以用于任何字段類型,下面介紹一部分經(jīng)常用到的通用參數(shù):
null
???:如果設(shè)置為 ??True
??,當(dāng)該字段為空時(shí),Django 會(huì)將數(shù)據(jù)庫(kù)中該字段設(shè)置為 ??NULL
??。默認(rèn)為 ??False
??。blank
??:如果設(shè)置為 ?True
?,該字段允許為空。默認(rèn)為 ?False
?。注意該選項(xiàng)與 ?null
?不同, ?null
?選項(xiàng)僅僅是數(shù)據(jù)庫(kù)層面的設(shè)置,而 ?blank
?是涉及表單驗(yàn)證方面。如果一個(gè)字段設(shè)置為?blank=True
? ,在進(jìn)行表單驗(yàn)證時(shí),接收的數(shù)據(jù)該字段值允許為空,而設(shè)置為?blank=False
? 時(shí),不允許為空。choices
??:一系列二元組,用作此字段的選項(xiàng)。如果提供了二元組,默認(rèn)表單小部件是一個(gè)選擇框,而不是標(biāo)準(zhǔn)文本字段,并將限制給出的選項(xiàng)。??choices
??中一個(gè)選項(xiàng)列表:
YEAR_IN_SCHOOL_CHOICES = [
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
]
注意:每當(dāng) ??choices
??的順序變動(dòng)時(shí)將會(huì)創(chuàng)建新的遷移。
每個(gè)二元組的第一個(gè)值會(huì)儲(chǔ)存在數(shù)據(jù)庫(kù)中,而第二個(gè)值將只會(huì)用于在表單中顯示。對(duì)于一個(gè)模型實(shí)例,要獲取該字段二元組中相對(duì)應(yīng)的第二個(gè)值,使用 ??get_FOO_display()?
? 方法。例如:
from django.db import models
class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
你也可以使用枚舉類以簡(jiǎn)潔的方式來(lái)定義 ??choices
??:
from django.db import models
class Runner(models.Model):
MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
name = models.CharField(max_length=60)
medal = models.CharField(blank=True, choices=MedalType.choices, max_length=10)
default
?:該字段的默認(rèn)值??梢允且粋€(gè)值或者是個(gè)可調(diào)用的對(duì)象,如果是個(gè)可調(diào)用對(duì)象,每次實(shí)例化模型時(shí)都會(huì)調(diào)用該對(duì)象。help_text
?:額外的“幫助”文本,隨表單控件一同顯示。即便你的字段未用于表單,它對(duì)于生成文檔也是很有用的。primary_key
?:如果設(shè)置為 ??True
??,將該字段設(shè)置為該模型的主鍵。在一個(gè)模型中,如果你沒(méi)有對(duì)任何一個(gè)字段設(shè)置 ??primary_key=True
?? 選項(xiàng)。 Django 會(huì)自動(dòng)添加一個(gè) ??IntegerField
??字段,并設(shè)置為主鍵,因此除非你想重寫 Django 默認(rèn)的主鍵設(shè)置行為,你可以不手動(dòng)設(shè)置主鍵。
主鍵字段是只可讀的,如果你修改一個(gè)模型實(shí)例的主鍵并保存,這等同于創(chuàng)建了一個(gè)新的模型實(shí)例。例如:
from django.db import models
class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
<QuerySet ['Apple', 'Pear']>
??unique
??:如果設(shè)置為 ??True
??,這個(gè)字段的值必須在整個(gè)表中保持唯一。
默認(rèn)情況下,Django 給每個(gè)模型一個(gè)自動(dòng)遞增的主鍵,其類型在 ??AppConfig.default_auto_field
?? 中指定,或者在 ??DEFAULT_AUTO_FIELD
??配置中全局指定。例如:
id = models.BigAutoField(primary_key=True)
如果你想自己指定主鍵, 在你想要設(shè)置為主鍵的字段上設(shè)置參數(shù) ??primary_key=True
??。如果 Django 看到你顯式地設(shè)置了 ??Field.primary_key
??,將不會(huì)自動(dòng)在表(模型)中添加 ??id
??列。每個(gè)模型都需要擁有一個(gè)設(shè)置了 ??primary_key=True
?? 的字段(無(wú)論是顯式的設(shè)置還是 Django 自動(dòng)設(shè)置)。
在舊版本中,自動(dòng)創(chuàng)建的主鍵字段總是 ??AutoField
??。
除了 ??ForeignKey
??, ??ManyToManyField
??和 ??OneToOneField
??,任何字段類型都接收一個(gè)可選的位置參數(shù) ??verbose_name
??,如果未指定該參數(shù)值, Django 會(huì)自動(dòng)使用字段的屬性名作為該參數(shù)值,并且把下劃線轉(zhuǎn)換為空格。
在該例中:備注名為??"?person's first name?"
??:
first_name = models.CharField("person's first name", max_length=30)
在該例中:備注名為 ??"first name"?
?:
first_name = models.CharField(max_length=30)
??ForeignKey
??, ??ManyToManyField
??和??OneToOneField
??接收的第一個(gè)參數(shù)為模型的類名,后面可以添加一個(gè) ??verbose_name
??參數(shù):
poll = models.ForeignKey(
Poll,
on_delete=models.CASCADE,
verbose_name="the related poll",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
verbose_name="related place",
)
慣例是不將 ??verbose_name
??的首字母大寫,必要時(shí) Djanog 會(huì)自動(dòng)把首字母轉(zhuǎn)換為大寫。
顯然,關(guān)系型數(shù)據(jù)庫(kù)的強(qiáng)大之處在于各表之間的關(guān)聯(lián)關(guān)系。 Django 提供了定義三種最常見(jiàn)的數(shù)據(jù)庫(kù)關(guān)聯(lián)關(guān)系的方法:多對(duì)一,多對(duì)多,一對(duì)一。
定義一個(gè)多對(duì)一的關(guān)聯(lián)關(guān)系,使用 ??django.db.models.ForeignKey
?? 類。就和其它 ?Field?字段類型一樣,只需要在你模型中添加一個(gè)值為該類的屬性。??ForeignKey
??類需要添加一個(gè)位置參數(shù),即你想要關(guān)聯(lián)的模型類名。例如,如果一個(gè) ??Car
??模型有一個(gè)制造者 ??Manufacturer
??--就是說(shuō)一個(gè) ??Manufacturer
??制造許多輛車,但是每輛車都僅有一個(gè)制造者-- 那么使用下面的方法定義這個(gè)關(guān)系:
from django.db import models
class Manufacturer(models.Model):
# ...
pass
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
# ...
你也可以創(chuàng)建 自關(guān)聯(lián)關(guān)系 (一個(gè)模型與它本身有多對(duì)一的關(guān)系)和 與未定義的模型間的關(guān)聯(lián)關(guān)系 。建議設(shè)置 ??ForeignKey
??字段名(上例中的 ??manufacturer
??)為想要關(guān)聯(lián)的模型名,但是你也可以隨意設(shè)置為你想要的名稱,例如:
class Car(models.Model):
company_that_makes_it = models.ForeignKey(
Manufacturer,
on_delete=models.CASCADE,
)
# ...
定義一個(gè)多對(duì)多的關(guān)聯(lián)關(guān)系,使用 ??django.db.models.ManyToManyField
?類。就和其他 ??Field
??字段類型一樣,只需要在你模型中添加一個(gè)值為該類的屬性。??ManyToManyField
??類需要添加一個(gè)位置參數(shù),即你想要關(guān)聯(lián)的模型類名。例如:如果 ??Pizza
??含有多種 ??Topping
??(配料) -- 也就是一種 ??Topping
??可能存在于多個(gè) ??Pizza
??中,并且每個(gè) ??Pizza
??含有多種 ??Topping
??--那么可以這樣表示這種關(guān)系:
from django.db import models
class Topping(models.Model):
# ...
pass
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
和 ??ForeignKey
??類一樣,你也可以創(chuàng)建 自關(guān)聯(lián)關(guān)系 (一個(gè)對(duì)象與他本身有著多對(duì)多的關(guān)系)和 與未定義的模型的關(guān)系 。建議設(shè)置 ??ManyToManyField
??字段名(上例中的 ??toppings
??)為一個(gè)復(fù)數(shù)名詞,表示所要關(guān)聯(lián)的模型對(duì)象的集合。對(duì)于多對(duì)多關(guān)聯(lián)關(guān)系的兩個(gè)模型,可以在任何一個(gè)模型中添加 ??ManyToManyField
??字段,但只能選擇一個(gè)模型設(shè)置該字段,即不能同時(shí)在兩模型中添加該字段。一般來(lái)講,應(yīng)該把 ??ManyToManyField
??實(shí)例放到需要在表單中被編輯的對(duì)象中。在之前的例子中, ??toppings
??被放在 ??Pizza
??當(dāng)中(而不是 ??Topping
??中有指向 ??pizzas
??的 ??ManyToManyField
??實(shí)例 )因?yàn)橄噍^于配料被放在不同的披薩當(dāng)中,披薩當(dāng)中有很多種配料更加符合常理。按照先前說(shuō)的,在編輯 ??Pizza
??的表單時(shí)用戶可以選擇多種配料。
如果你只是想要一個(gè)類似于記錄披薩和配料之間混合和搭配的多對(duì)多關(guān)系,標(biāo)準(zhǔn)的 ??ManyToManyField
??就足夠你用了。但是,有時(shí)你可能需要將數(shù)據(jù)與兩個(gè)模型之間的關(guān)系相關(guān)聯(lián)。舉例來(lái)講,考慮一個(gè)需要跟蹤音樂(lè)人屬于哪個(gè)音樂(lè)組的應(yīng)用程序。在人和他們所在的組之間有一個(gè)多對(duì)多關(guān)系,你可以使用 ??ManyToManyField
??來(lái)代表這個(gè)關(guān)系。然而,你想要記錄更多的信息在這樣的關(guān)聯(lián)關(guān)系當(dāng)中,比如你想要記錄某人是何時(shí)加入一個(gè)組的。對(duì)于這些情況,Django 允許你指定用于控制多對(duì)多關(guān)系的模型。你可以在中間模型當(dāng)中添加額外的字段。在實(shí)例化 ??ManyToManyField
??的時(shí)候使用 ??through
??參數(shù)指定多對(duì)多關(guān)系使用哪個(gè)中間模型。對(duì)于我們舉的音樂(lè)家的例子,代碼如下:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
你需要在設(shè)置中間模型的時(shí)候,顯式地為多對(duì)多關(guān)系中涉及的中間模型指定外鍵。這種顯式聲明定義了這兩個(gè)模型之間是如何關(guān)聯(lián)的。
在中間模型當(dāng)中有一些限制條件:
Group
??)的外鍵,要么你必須通過(guò) ??ManyToManyField.through_fields
?? 參數(shù)在多個(gè)外鍵當(dāng)中手動(dòng)選擇一個(gè)外鍵,如果有多個(gè)外健且沒(méi)有用 ??through_fields
?參數(shù)選擇一個(gè)的話,會(huì)出現(xiàn)驗(yàn)證錯(cuò)誤。對(duì)于指向目標(biāo)模型(我們例子當(dāng)中的 ??Person
??)的外鍵也有同樣的限制。through_fields
??參數(shù),要不然會(huì)出現(xiàn)驗(yàn)證錯(cuò)誤。現(xiàn)在你已經(jīng)通過(guò)中間模型完成你的 ??ManyToManyField
??(例子中的 ??Membership
??),可以開(kāi)始創(chuàng)建一些多對(duì)多關(guān)系了。你通過(guò)實(shí)例化中間模型來(lái)創(chuàng)建關(guā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()
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<Group: The Beatles>]>
>>> m2 = Membership.objects.create(person=paul, group=beatles,
... date_joined=date(1960, 8, 1),
... invite_reason="Wanted to form a band.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
你也可以使用 ??add()?
?, ??create()
??, 或者 ??set()?
? 創(chuàng)建關(guān)系,只要你為任何必需的字段指定 ??through_defaults
??
>>> beatles.members.add(john, through_defaults={'date_joined': date(1960, 8, 1)})
>>> beatles.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)})
>>> beatles.members.set([john, paul, ringo, george], through_defaults={'date_joined': date(1960, 8, 1)})
你可能更傾向直接創(chuàng)建中間模型。如果自定義中間模型沒(méi)有強(qiáng)制? ?(model1, model2)?
? 對(duì)的唯一性,調(diào)用 ??remove()?
? 方法會(huì)刪除所有中間模型的實(shí)例:
>>> Membership.objects.create(person=ringo, group=beatles,
... date_joined=date(1968, 9, 4),
... invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
>>> # This deletes both of the intermediate model instances for Ringo Starr
>>> beatles.members.remove(ringo)
>>> beatles.members.all()
<QuerySet [<Person: Paul McCartney>]>
方法 ??clear()?
? 用于實(shí)例的所有多對(duì)多關(guān)系:
>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>
一旦你建立了自定義多對(duì)多關(guān)聯(lián)關(guān)系,就可以執(zhí)行查詢操作。和一般的多對(duì)多關(guān)聯(lián)關(guān)系一樣,你可以使用多對(duì)多關(guān)聯(lián)模型的屬性來(lái)查詢:
# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
<QuerySet [<Group: The Beatles>]>
當(dāng)你使用中間模型的時(shí)候,你也可以查詢他的屬性:
# Find all the members of the Beatles that joined after 1 Jan 1961
>>> Person.objects.filter(
... group__name='The Beatles',
... membership__date_joined__gt=date(1961,1,1))
<QuerySet [<Person: Ringo Starr]>
如果你想訪問(wèn)一個(gè)關(guān)系的信息時(shí)你可以直接查詢 ??Membership
??模型:
>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
另一種訪問(wèn)同樣信息的方法是通過(guò) ??Person
?對(duì)象來(lái)查詢多對(duì)多遞歸關(guān)聯(lián)關(guān)系 :
>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
使用 ??OneToOneField
??來(lái)定義一對(duì)一關(guān)系。就像使用其他類型的 ??Field
??一樣:在模型屬性中包含它。當(dāng)一個(gè)對(duì)象以某種方式“繼承”另一個(gè)對(duì)象時(shí),這對(duì)該對(duì)象的主鍵非常有用。??OneToOneField
??需要一個(gè)位置參數(shù):與模型相關(guān)的類。例如,當(dāng)你要建立一個(gè)有關(guān)“位置”信息的數(shù)據(jù)庫(kù)時(shí),你可能會(huì)包含通常的地址,電話等字段。接著,如果你想接著建立一個(gè)關(guān)于關(guān)于餐廳的數(shù)據(jù)庫(kù),除了將位置數(shù)據(jù)庫(kù)當(dāng)中的字段復(fù)制到 ??Restaurant
??模型,你也可以將一個(gè)指向 ??Place OneToOneField
?? 放到 ??Restaurant
??當(dāng)中(因?yàn)椴蛷d“是一個(gè)”地點(diǎn));事實(shí)上,在處理這樣的情況時(shí)最好使用 模型繼承 ,它隱含的包括了一個(gè)一對(duì)一關(guān)系。和 ??ForeignKey
??一樣,可以創(chuàng)建 自關(guān)聯(lián)關(guān)系 也可以創(chuàng)建 與尚未定義的模型的關(guān)系 。
??OneToOneField
??字段還接受一個(gè)可選的 ??parent_link
??參數(shù)。??OneToOneField
?? 類通常自動(dòng)的成為模型的主鍵,這條規(guī)則現(xiàn)在不再使用了(然而你可以手動(dòng)指定 ??primary_key
??參數(shù))。因此,現(xiàn)在可以在單個(gè)模型當(dāng)中指定多個(gè) ??OneToOneField
??字段。
關(guān)聯(lián)另一個(gè)應(yīng)用中的模型是當(dāng)然可以的。為了實(shí)現(xiàn)這一點(diǎn),在定義模型的文件開(kāi)頭導(dǎo)入需要被關(guān)聯(lián)的模型。接著就可以在其他有需要的模型類當(dāng)中關(guān)聯(lián)它了。比如:
from django.db import models
from geography.models import ZipCode
class Restaurant(models.Model):
# ...
zip_code = models.ForeignKey(
ZipCode,
on_delete=models.SET_NULL,
blank=True,
null=True,
)
Django 對(duì)模型的字段名有一些限制:
1、一個(gè)字段的名稱不能是 Python 保留字,因?yàn)檫@會(huì)導(dǎo)致 Python 語(yǔ)法錯(cuò)誤。比如:
class Example(models.Model):
pass = models.IntegerField() # 'pass' is a reserved word!
2、一個(gè)字段名稱不能包含連續(xù)的多個(gè)下劃線,原因在于 Django 查詢語(yǔ)法的工作方式。比如:
class Example(models.Model):
foo__bar = models.IntegerField() # 'foo__bar' has two underscores!
3、字段名不能以下劃線結(jié)尾,原因同上。
但是,這些限制是可以被解決的,因?yàn)樽侄蚊麤](méi)要求和數(shù)據(jù)庫(kù)列名一樣。
SQL保留字,例如 ??join
??, ??where
??或 ??select
??, 是 可以被用在模型字段名當(dāng)中的,因?yàn)?Django 在對(duì)底層的 SQL 查詢當(dāng)中清洗了所有的數(shù)據(jù)庫(kù)表名和字段名,通過(guò)使用特定數(shù)據(jù)庫(kù)引擎的引用語(yǔ)法。
如果已經(jīng)存在的模型字段不能滿足你的需求,或者你希望支持一些不太常見(jiàn)的數(shù)據(jù)庫(kù)列類型,你可以創(chuàng)建自己的字段類。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: