Django 模型

2022-07-20 17:47 更新

簡介

模型是有關(guān)數(shù)據(jù)的唯一確定的信息源。它包含要存儲數(shù)據(jù)的基本字段和行為。通常,每個模型都映射到單個數(shù)據(jù)庫表。

  • 每一個模型是django.db.models.Model的子類
  • 每一個模型屬性代表數(shù)據(jù)表的一個字段。
  • Django提供了自動生成的數(shù)據(jù)庫訪問API,使用模型操作數(shù)據(jù)庫很方便

快速示例

此示例模型定義了一個Person,其中包含first_name和 last_name

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

first_name并且last_name是場模型。每個字段都指定為類屬性,并且每個屬性都映射到數(shù)據(jù)庫列。

上面的Person模型將創(chuàng)建一個數(shù)據(jù)庫表,如下所示:

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);
一些技術(shù)說明:
  • 表的名稱myapp_person是自動從某些模型元數(shù)據(jù)派生而來的,但是可以被覆蓋。
  • 一個id字段被自動添加,但這種行為可以被覆蓋。
  • 在此示例中,SQL是使用PostgreSQL語法格式化的,但是值得注意的是Django使用了針對設(shè)置文件中指定的數(shù)據(jù)庫后端定制的SQL 。CREATE TABLE

詳情參考官網(wǎng): https://docs.djangoproject.com/en/3.0/topics/db/models/

定義模型

Django根據(jù)屬性的類型確定以下信息:

  • 當(dāng)前選擇的數(shù)據(jù)庫支持字段的類型
  • 渲染管理表單時使用的默認html控件
  • 在管理站點最低限度的驗證

django會為表創(chuàng)建自動增長的主鍵列,每個模型只能有一個主鍵列,如果使用選項設(shè)置某屬性為主鍵列后django不會再創(chuàng)建自動增長的主鍵列。

默認創(chuàng)建的主鍵列屬性為id,可以使用pk代替,pk全拼為primary key。

pk是主鍵的別名,若主鍵名為id2,那么pk是id2的別名。

屬性命名限制:

  • 不能是python的保留關(guān)鍵字。
  • 不允許使用連續(xù)的下劃線,這是由django的查詢方式?jīng)Q定的,在第4節(jié)會詳細講解查詢。
  • 定義屬性時需要指定字段類型,通過字段類型的參數(shù)指定選項。

       具體語法如下:

       屬性=models.字段類型(選項)

模型字段類表

 字段類 默認小組件 說明
 AutoField N/A 根據(jù) ID 自動遞增的 IntegerField
 BigIntegerField NumberInput 64 位整數(shù),與 IntegerField 很像,但取值范圍是 -9223372036854775808 到 9223372036854775807 。
 BinaryField N/A 存儲原始二進制數(shù)據(jù)的字段。只支持 bytes 類型。注意,這個字段的功能有限。
 BooleanField CheckboxInput 真假值字段。如果想接受 null 值,使用 NullBooleanField 。
 CharField TextInput 字符串字段,針對長度較小的字符串。大量文本應(yīng)該使用 TextField 。有個額外的必須參數(shù):max_length ,即字段的最大長度(字符個數(shù))。
 DateField DateInput 日期,在 Python 中使用 datetime.date 實例表示。有兩個額外的可選參數(shù): auto_now ,每次保存對象時自動設(shè)為當(dāng)前日期 auto_now_add ,創(chuàng)建對象時自動設(shè)為當(dāng)前日期。
 DateTimeField DateTimeInput 日期和時間,在 Python 中使用 datetime.datetime 實例表示。與 DateField 具有相同的額外參數(shù)。
 DecimalField TextInput 固定精度的小數(shù),在 Python 中使用 Decimal 實例表示。有兩個必須的參數(shù): max_digits 和 decimal_places 。
 DurationField TextInput 存儲時間跨度,在 Python 中使用 timedelta 表示。
 EmailField TextInput 一種 CharField ,使用 EmailValidator 驗證輸入。max_length 的默認值為 254 。
 FileField ClearableFileInput 文件上傳字段。詳情見下面。
 FilePathField Select 一種 CharField ,限定只能在文件系統(tǒng)中的特定目錄里選擇文件。
 FloatField NumberInput 浮點數(shù),在 Python 中使用 float 實例表示。注意, field.localize 的值為 False 時,默認的小組件是 TextInput 。
 ImageField ClearableFileInput 所有屬性和方法都繼承自 FileField ,此外驗證上傳的對象是不是有效的圖像。增加了 height 和 width 兩個屬性。需要 Pillow 庫支持。

字段選項

  • 通過字段選項,可以實現(xiàn)對字段的約束
  • 在字段對象時通過關(guān)鍵字參數(shù)指定
  • null:如果為True,Django 將空值以NULL 存儲到數(shù)據(jù)庫中,默認值是 False
  • blank:如果為True,則該字段允許為空白,默認值是 False
  • 對比:null是數(shù)據(jù)庫范疇的概念,blank是表單驗證證范疇的
  • db_column:字段的名稱,如果未指定,則使用屬性的名稱
  • db_index:若值為 True, 則在表中會為此字段創(chuàng)建索引
  • default:默認值
  • primary_key:若為 True, 則該字段會成為模型的主鍵字段
  • unique:如果為 True, 這個字段在表中必須有唯一值

關(guān)聯(lián)關(guān)系

多對一 (ForeignKey)

Django提供了定義了幾種最常見的數(shù)據(jù)庫關(guān)聯(lián)關(guān)系的方法:多對一,多對多,一對一。

多對一關(guān)系,需要兩個位置參數(shù),一個是關(guān)聯(lián)的模型,另一個是 on_delete 選項,外鍵要定義在多的一方,如一個汽車廠生產(chǎn)多種汽車,一輛汽車只有一個生產(chǎn)廠家

from django.db import models

class Manufacturer(models.Model):

    # ...

    pass

class Car(models.Model):

    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)

多對多關(guān)系的額外字段:throuth

例如:這樣一個應(yīng)用,它記錄音樂家所屬的音樂小組。 我們可以用一個ManyToManyField 表示小組和成員之間的多對多關(guān)系。 但是,有時你可能想知道更多成員關(guān)系的細節(jié),比如成員是何時加入小組的。

對于這些情況,Django 允許你指定一個中介模型來定義多對多關(guān)系。 你可以將其他字段放在中介模型里面。 源模型的ManyToManyField 字段將使用through 參數(shù)指向中介模型。 對于上面的音樂小組的例子,代碼如下:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):              # __unicode__ on Python 2
        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è)置中間模型的時候,顯式地為多對多關(guān)系中涉及的中間模型指定外鍵。這種顯式聲明定義了這兩個模型之間是如何關(guān)聯(lián)的。

在中間模型當(dāng)中有一些限制條件:

  • 你的模型中間要么有且僅有一個指向源模型(我們例子當(dāng)中的Group)的外鍵,你要么必須通過ManyToManyField.through_fields參數(shù)在多個外鍵當(dāng)中手動選擇一個外鍵,有如果外個多鍵盤沒有用through_fields 參數(shù)選擇一個的話,會出現(xiàn)驗證錯誤。對于某個目標(biāo)模型(我們示例當(dāng)中的Person)的外鍵也有同樣的限制。
  • 在一個有用的描述模型當(dāng)中自己指向自己的多對多關(guān)系的中間模型當(dāng)中,可以有兩個指向同一個模型的外健,但這兩個外健分表代表多對多關(guān)系(不同)的兩端。如果外健的個數(shù)超過兩個,你必須和上面一樣的指定through_fields參數(shù),要不然會出現(xiàn)驗證錯誤。

現(xiàn)在你已經(jīng)通過中間模型完成你的ManyToManyField(示例中的Membership),可以開始創(chuàng)建一些多對多關(guān)系了。你通過實例化中間模型來創(chuàng)建關(guān)系:

>>> 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)造中間模型。

如果自定義中間模型沒有強制對的唯一性,調(diào)用方法會刪除所有中間模型的實例:(model1, model2)remove()

>>> 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()用于實例的所有多對多關(guān)系:

>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>

一旦你建立了自定義多對多關(guān)聯(lián)關(guān)系,就可以執(zhí)行查詢操作。和一般的多對多關(guān)聯(lián)關(guān)系一樣,你可以使用多對多關(guān)聯(lián)模型的屬性來查詢:

# 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)你使用中間模型的時候,你也可以查詢他的屬性:

# 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]>

如果你想訪問一個關(guān)系的信息時你可以直接查詢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.'

另一種訪問同樣信息的方法是通過Person對象來查詢多對多遞歸關(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.'

一對一關(guān)聯(lián)

使用OneToOneField來定義一對一關(guān)系。就像使用其他類型的Field一樣:在模型屬性中包含它。

當(dāng)一個對象以某種方式“繼承”另一個對象時,這那個對象的主鍵非常有用。

OneToOneField需要一個位置參數(shù):與模型相關(guān)的類。

例如,當(dāng)你要建立一個有關(guān)“位置”信息的數(shù)據(jù)庫時,你可能會包含通常的地址,電話等分支。然后,如果你想接著建立一個關(guān)于關(guān)于餐廳的數(shù)據(jù)庫,除了將位置數(shù)據(jù)庫當(dāng)中的一部分復(fù)制到Restaurant模型,你也可以將一個指向Place OneToOneField放到Restaurant當(dāng)中(因為餐廳“是一個”地點);事實上,在處理這樣的情況時最好使用模型繼承,它隱含的包括了一個一對一關(guān)系。

和 ForeignKey一樣,可以創(chuàng)建自關(guān)聯(lián)關(guān)系也可以創(chuàng)建與尚未定義的模型的關(guān)系。

OneToOneField初步還接受一個可選的parent_link參數(shù)。

OneToOneField類通常自動的成為模型的主鍵,這條規(guī)則現(xiàn)在不再使用了(而你可以手動指定primary_key參數(shù))。因此,現(xiàn)在可以在其中的模型當(dāng)中指定多個OneToOneField分段。


詳情參考官網(wǎng):  https://www.khan.pub/django3.0/index.html


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號