Django-1.11中文文檔-模型Models(一)


官方文檔鏈接

模型是數據信息的唯一並明確的來源。它包含了我們儲存的數據的基本字段和行為。通常,每個模型映射到一張數據庫表。 基本概念:
  • 每個模型都是django.db.models.Model的一個子類
  • 每個屬性代表數據庫中的一個字段
  • 在這些基礎上,Django為我們提供了一個自動生成的數據庫訪問API。

簡單示例

下面的示例模型定義了一個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是模型(model)的字段(fields).每個字段指定為類的一個屬性,每個屬性映射到數據庫的一列(column)。

上面的Person模型將建立類似下面這樣一個數據庫:

 CREATE TABLE myapp_person (
     "id" serial NOT NULL primary_key,
     "first_name" varchar(30) NOT NULL,
     "last_name" varchar(30) NOT NULL
 );

 

關於上面代碼的一些技術注釋:

  • 上面數據表的名稱"myapp_person",是從模型的元數據(metadata)自動導入的,但是可以覆寫(overridden)。具體參見文檔的Table names章節。
  • 自動添加了一個id字段,該行為也可以被覆寫。具體參見文檔的Automatic primary_key fields章節
  • 這是一段運用PostgreSQL語法建立數據表的SQL語句,但我們不用為此操心,針對后台settings file中設定好的數據庫,Django都有量身定做的SQL。

運用模型

一旦定義好模型之后,需要告訴Django我們將使用這些模型。方法是通過編輯setting.py文件,在INSTALLED_APPS設定中添加包含了我們models.py的模塊的名稱。

例如,如果我們應用程序的模型存放在myapp.models模塊中(該包結構在通過manage.py startapp命令創建應用程序時形成的),INSTALLED_APP應該一部分看起來如下:

 

 INSTALLED_APPS = [
      #...
      'myapp',
      #...

當添加apps到INSTALLED_APPS以后,確保要運行mangae.py migrate指令,有時候還需要先用manage.py makemigrations進行遷移。

字段(Field)

一個模型最重要也是唯一要求的部分,就是定義數據庫的字段。字段是由類的屬性指定的。注意不要選擇與模型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()

 

字段類型(Field types)

Each field in your model should be an instance of the appropriate Field class. Django uses the field class types to determine a few things:

模型的每一個字段都是相應字段類的一個實例。Django用字段類的類型來決定一些東西:

  • 列類型(column type),告訴數據庫儲存什么樣的數據(比如INTERGER, VARCHAR, TEXT 等)。
  • 渲染表單字段時用默認的HTML部件(比如<input type="text">, <select>等)
  • Django的管理系統(admin)和自動生成的表單中,運用最低的驗證要求。

Django擁有許多內置的字段類型;完整的清單參見model field reference。如果內置的字段滿足不了要求,我們也可以方便的編寫自己的字段,具體參見Writing custom model fields


 字段選項(Field options)

每個字段都有一些特定的參數(參見 model field reference),例如,CharField(及其子類)要求一個最大長度參數來規定數據庫VARCHAR字段的大小。

也有一些每種字段都通用的參數,都是可選的。在reference中有完整的解釋,這里對最常用的一些做個快速的概覽: 

null

如果值為True,在數據庫中Django將把空值儲存為Null。默認值為False。 

blank

如果值為True,字段允許為空。默認值為False。

注意它與null是不同的。null是純粹數據庫相關的,而blank是驗證相關的。如果一個字段設置了blank=True, 表單驗證將允許輸入空值。如果設置了blank=False,該字段則是必需的。 

choices

一個包含了二維元組的可迭代對象(比如,列表或者元組)作為字段的選項,默認的表單部件將從標准的文本換成選擇框,選項限定為choice參數。

chiices列表看起來像這樣:

YEAR_IN_SCHOOL_CHOICES = (
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
)

 每個元組中的第一個元素是將儲存在數據庫中的值。第二個元素將通過默認的表單部件顯示,或者放在ModelChoiceField中。給出一個模型實例,可以通過get_FOO_display()方法來訪問choices field正在顯示的值。

示例:

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'
default
字段的默認值。可以是一個值或者一個可調用的對象。如果是后者,每次新對象創建時都會調用。
help text
表單部件顯示附加的幫助信息。如果字段不是用在表單上,該參數對文檔還是很有用的。
primary_key
如果值為True,該字段設為模型的主鍵。
如果沒有指定任何字段為主鍵,Django會自動添加一個IntegerField做為主鍵。所以如果不想覆寫默認的主鍵,可以不設定任何字段的primary_key=True。
主鍵字段是只讀的,如果你改寫了一個原有主鍵的值然后儲存,舊對象的旁邊將會建立一個新對象。示例如下:
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

如果為True,該字段在表中必須是唯一的。
再說一次,這些只是常用字段選項的簡短描述,完整的信息請查看
common model field option reference

自動主鍵字段(Automatic primary_key fields)

默認情況下,Django中每個模型都有以下字段:
id = models.AutoField(primary_key=True)

這是一個自動增長的主鍵。

如果你想指定一個自定義的主鍵,只要將某個字段的選項設置primary_key=True。如果Django發現你已經明確了字段的主鍵(Field.primary_key),它就不會再添加自動的id列。

每個模型要求必須有一個字段設定為primary_key=True(明確指定的或者自動添加的都可以)。


詳細字段名稱(Verbose field names)

除ForeignKey, ManyToManyField 和 OneToOneField以外,每種字段都有一個第一位置參數-詳細名稱。如果該詳細名稱沒有給出,Django會自動把字段的屬性名稱(下划線替換成空格)作為詳細名稱。

下面這個例子,詳細名稱是"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 要求第一位置參數為模型類,所以使用verbose_name關鍵字屬性:

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的首字母大寫,Django會再需要的時候自動將其首字母大寫。


關系(Relationships)

很明顯,關系型數據庫的能力來源於相互關聯的表。Django提供了方法定義三種最常見的數據庫關系:many-to-one, many-to-many and one-to-one。

一對多關系(Many-to-one relationships)

通過django.db.models.ForeignKey來定義一對多關系。我們可以像使用其他字段類型一樣:將其作為類屬性包含在我們的模型中。

外鍵(ForeignKey)要求一個位置參數:該模型關聯到哪個類。

比如,一個廠家制造了很多汽車,但是每輛汽車只有一個廠家,可以如下定義:

from django.db import models

class Manufacturer(models.Model):
    # ...
    pass

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
    # ...

你也可以創建一個遞歸關系recursive relationships(一個對象有一個指向自身的外鍵)以及與尚未定義的模型的關系relationships to models not yet defined,具體參見he model field reference

建議,但沒規定,將關聯模型的小寫名稱作為外鍵字段的名稱(上一個示例中的manufacturer)。當然,你可以叫外鍵字段任何名字,比如{

class Car(models.Model):
    company_that_makes_it = models.ForeignKey(
        Manufacturer,
        on_delete=models.CASCADE,
    )
    # ...

參考信息

外鍵字段接收多種其他參數,具體參見the model field reference。這些選項幫助定義關系怎么工作,都是可選的。

關於訪問向后相關(backwards-related)對象的細節,參見Following relationships backward example

關於示例代碼,參見Many-to-one relationship model example


多對多關系(Many-to-many relationships)

要定義一個多對多關系,用MangToManyField。

我們可以像使用其他字段類型一樣:將其作為類屬性包含在我們的模型中。

MangToManyField要求一個位置參數:該模型關聯到哪個類。

比如,一個披薩有多種配料,一種配料也可以用在多個披薩上。可以這樣描述:

from django.db import models

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)
跟外鍵一樣,你也可以創建遞歸關系以及與尚未定義的模型的關系。
建議,但未規定,用關聯模型對象的復數描述作為ManyToManyField的名稱(上面示例中的toppings)。
多對多的兩個模型中哪一個設置ManyToManyField都可以,但是只能設定一個,不能都設定。
通常,ManyToManyField實例會通過表單填寫。在上面的示例中,tappings在Pizza中(而不是Topping有一個pizzas ManyToManyField)。因為一個有多種配料的披薩要比一種用在多個披薩上的配料要自然些。上面示例中,披薩表單中讓用戶可以選擇配料。
參考信息
ManyToManyField接收多種其他參數,具體參見 the model field reference。這些選項幫助定義關系怎么工作,都是可選的。

多對多關系中的額外字段

當你只需要處理簡單的多對多關系時,比如混合搭配披薩和配料,標准的多對多字段就夠了。然而,有時候你需要兩個模型之間關系的輔助數據。

例如,設想有一種程序用來追蹤音樂家屬於哪個樂隊。人和樂隊之間是一種多對多的關系,所以我們可以用一個多對多字段來描述該關系。然而,還有很多其他相關信息我們也想收集,比如某人加入某個樂隊的日期。

針對這種情況,Django允許我們指定模型,用來管理該多對多關系。這樣我們可以在中間模型中設置額外的字段。通過設置through參數來指出哪個模型作為媒介,將中間模型與多對多字段聯合起來。我們的樂隊示例,代碼應該差不多像這樣:

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)

 當我們建立中間模型時,我們明確指定了到該多對多關系相關模型的外鍵。此明確聲明定義了這兩個模型時怎么關聯的。

中間模型中有一些約束:

  • 中間模型必須有且只有一個到源模型(我們示例中的Group)的外鍵, 或者明確指定ManyToManyField.through_fields如果有超過一個外鍵而且沒有指定through_fields,會引發驗證錯誤。到目標模型(我們示例中的Person)的外鍵也有同樣的限制
  • 當一個模型通過中間模型到自身有多對多關系,指向同一個模型的兩個外鍵是允許的,但是它們要按多對多關系的不同側來處理。如果存在超過兩個外鍵,也必須跟上面一樣指定through_fields,否則會引發驗證錯誤。
  • 當使用中間模型定義模型到自身的多對多關系時,必須使用symmetrical=False (參照 the model field reference)。

現在我們已經設置好ManyToMany字段來使用我們的中間模型(示例中的Membership),已為建立一些多對多關系做好准備。可以通過創建中間模型的實例來實行:

>>> 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() 去創建關系:

>>> # The following statements will not work
>>> beatles.members.add(john)
>>> beatles.members.create(name="George Harrison")
>>> beatles.members.set([john, paul, ringo, george])

 

為什么?我們不能只創建人和樂隊之間的關系,我們還需要指定Membership模型要求的關系的所有信息。簡單的add, create無法指定額外的信息。所以,運用中間模型的多對多關系是禁用它們的。創建這種類型關系的唯一方法是創建中間模型的實例。

出於類似的原因, remove()方法也被禁用了。因為有時候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 will not work because it cannot tell which membership to remove
>>> beatles.members.remove(ringo)

 

然而,clear()方法可以刪除一個實例的所有多對多關系:

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

 

一旦通過創建中間模型實例建立了多對多關系,我們就可以進行查詢了。就像普通多對多關系一樣,我們可以通過相關模型的屬性進行查詢:

# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
<QuerySet [<Group: The Beatles>]>

 

也可以通過中間模型的屬性進行查詢:

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

 

如果需要訪問中間模型的信息,我們可以直接對中間模型進行查詢:

>>> 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對象查詢many-to-many reverse relationship

>>> 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.'

一對一關系(One-to-one relationships)

用OneToOneField定義一對一關系。像任何其他字段類型一樣使用:作為屬性包含在模型中。

如果一個對象繼承自其他對象,一對一關系最適合用於它的主鍵。

OneToOneField要求一個位置參數:哪個模型是相關的。

例如,我們要建立一個關於“處所”的數據庫,可能要在數據庫中建立很多標准的東西,如地址、電話號碼等。這時,如果你還想在這些處所的基礎上再建立一個餐廳的數據庫,不必在餐廳模型中再重復指定這些字段,只需要在餐廳模型中建立一個指向處所模型的一對一字段。(因為一間餐廳也是一個處所。實際上,這種情況我們通常使用繼承inheritance,它是毫無疑問的一對一關系。

跟外鍵一樣,你也可以創建遞歸關系以及與尚未定義的模型的關系。

 

參考信息

完整實例請參見One-to-one relationship model example 。

一對一字段也接收一個可選的 parent_link 參數。

一對一字段類以前會自動成為模型的主鍵,現在不是這樣了(盡管可以手動設置primary_key參數,如果我們想的話)。因此,現在同一個模型中可以有多個一對一字段。

 

跨文件的模型

訪問其他應用的模型是非常容易的。 在文件頂部我們定義模型的地方,導入相關的模型就可以了。然后,無論在哪里需要的話,都可以引用它。例如:

from django.db import models
from geography.models import ZipCode

class Restaurant(models.Model):
    # ...
    zip_code = models.ForeignKey(ZipCode)

 


字段命名的限制

Django 對字段的命名只有兩個限制:

  1. 字段的名稱不能是Python 保留的關鍵字,因為這將導致一個Python 語法錯誤。例如:

    class Example(models.Model):
        pass = models.IntegerField() # 'pass' is a reserved word!

     

  2. 由於Django 查詢語法的工作方式,字段名稱中連續的下划線不能超過一個。例如:

    class Example(models.Model):
        foo__bar = models.IntegerField() # 'foo__bar' has two underscores!

     

這些限制有變通的方法,因為沒有要求字段名稱必須與數據庫的列名匹配。參 見db_column 選項。

SQL 的保留字例如joinwhere 和select,可以用作模型的字段名,因為Django 會對底層的SQL 查詢語句中的數據庫表名和列名進行轉義。 它根據你的數據庫引擎使用不同的引用語法。


自定義字段類型

如果已有的模型字段都不合適,或者你想用到一些很少見的數據庫列類型的優點,你可以創建你自己的字段類型。創建你自己的字段在編寫自定義的模型字段中有完整講述。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM