1. 程式人生 > >django 1.8 官方文件翻譯:2-1-1 模型語法

django 1.8 官方文件翻譯:2-1-1 模型語法

模型

模型是你的資料的唯一的、權威的資訊源。它包含你所儲存資料的必要欄位和行為。通常,每個模型對應資料庫中唯一的一張表。

基礎:

  • 模型的每個屬性都表示資料庫中的一個欄位。
  • Django 提供一套自動生成的用於資料庫訪問的API;詳見執行查詢

簡短的例子

這個例子定義一個Person模型,它有first_namelast_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_namelast_name是模型的兩個欄位。每個欄位都被指定成一個類屬性,每個屬性對映到一個數據庫的列。

上面的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,是根據 模型中的元資料自動生成的,也可以覆寫為別的名稱,詳見
    Table names
  • id 欄位是自動新增的,但這個行為可以被重寫。詳見自增主鍵欄位
  • 這個例子中的CREATE TABLE SQL 語句使用PostgreSQL 語法格式,要注意的是Django 會根據設定檔案 中指定的資料庫型別來使用相應的SQL 語句。

使用模型

定義好模型之後,你需要告訴Django 使用這些模型。你要做的就是修改配置檔案中的INSTALLED_APPS 設定,在其中新增models.py所在應用的名稱。

例如,如果你的應用的模型位於myapp.models模組(manage.py startapp 指令碼為一個應用建立的包結構),INSTALLED_APPS

部分看上去應該是:

INSTALLED_APPS = (
    #...
    'myapp',
    #...
)

欄位

模型中不可或缺且最為重要的,就是欄位集,它是一組資料庫欄位的列表。欄位被指定為類屬性。 要注意選擇的欄位名稱不要和模型 API 衝突,比如cleansave 或者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)
    name = models.CharField(max_length=100)
    release_date = models.DateField()
    num_stars = models.IntegerField()

欄位型別

模型中的每個欄位都是 Field 子類的某個例項。Django 根據欄位類的型別確定以下資訊:

  • 資料庫當中的列型別 (比如, INTEGER, VARCHAR)。
  • 渲染表單時使用的預設HTML 部件(例如,<input type="text">, <select>)。
  • 最低限度的驗證需求,它被用在 Django 管理站點和自動生成的表單中。

Django 自帶數十種內建的欄位型別;完整欄位型別列表可以在模型欄位參考 中找到。如果內建型別仍不能滿足你的要求,你可以自由地編寫符合你要求的欄位型別; 詳見編寫自定義的模型欄位

欄位選項

每個欄位有一些特有的引數,詳見模型欄位參考。例如,CharField(和它的派生類)需要max_length 引數來指定VARCHAR 資料庫欄位的大小。

還有一些適用於所有欄位的通用引數。 這些引數在參考中有詳細定義,這裡我們只簡單介紹一些最常用的:

null

如果為True,Django 將用NULL 來在資料庫中儲存空值。 預設值是 False.

blank

如果為True,該欄位允許不填。預設為False

要注意,這與 null 不同。null純粹是資料庫範疇的,而 blank 是資料驗證範疇的。如果一個欄位的blank=True,表單的驗證將允許該欄位是空值。如果欄位的blank=False,該欄位就是必填的。

由二元組組成的一個可迭代物件(例如,列表或元組),用來給欄位提供選擇項。 如果設定了choices ,預設的表單將是一個選擇框而不是標準的文字框,而且這個選擇框的選項就是choices 中的選項。

這是一個關於 choices 列表的例子:

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

每個元組中的第一個元素,是儲存在資料庫中的值;第二個元素是在管理介面或 ModelChoiceField 中用作顯示的內容。 在一個給定的 model 類的例項中,想得到某個 choices 欄位的顯示值,就呼叫 get_FOO_display 方法(這裡的 FOO 就是 choices 欄位的名稱 )。例如:

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'

欄位的預設值。可以是一個值或者可呼叫物件。如果可呼叫 ,每有新物件被建立它都會被呼叫。

表單部件額外顯示的幫助內容。即使欄位不在表單中使用,它對生成文件也很有用。

如果為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)
['Apple', 'Pear']

如果該值設定為 True, 這個資料欄位的值在整張表中必須是唯一的

再說一次,這些僅僅是常用欄位的簡短介紹, 要了解詳細內容,請檢視 通用 model 欄位選項參考(common model field option reference).

自增主鍵欄位

預設情況下,Django 會給每個模型新增下面這個欄位:

id = models.AutoField(primary_key=True)

這是一個自增主鍵欄位。

如果你想指定一個自定義主鍵欄位,只要在某個欄位上指定 primary_key=True 即可。如果 Django 看到你顯式地設定了 Field.primary_key,就不會自動新增 id 列。

每個模型只能有一個欄位指定primary_key=True(無論是顯式宣告還是自動新增)。

欄位的自述名

ForeignKeyManyToManyFieldOneToOneField 之外,每個欄位型別都接受一個可選的位置引數 —— 欄位的自述名。如果沒有給定自述名,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)
poll = models.ForeignKey(Poll, verbose_name="the related poll")
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(Place, verbose_name="related place")

習慣上,verbose_name 的首字母不用大寫。Django 在必要的時候會自動大寫首字母。

關係

顯然,關係資料庫的威力體現在表之間的相互關聯。 Django 提供了三種最常見的資料庫關係:多對一(many-to-one),多對多(many-to-many),一對一(one-to-one)。

多對一關係 

Django 使用 django.db.models.ForeignKey 定義多對一關係。和使用其它欄位型別一樣:在模型當中把它做為一個類屬性包含進來。

ForeignKey 需要一個位置引數:與該模型關聯的類。

比如,一輛Car有一個Manufacturer —— 但是一個Manufacturer 生產很多Car,每一輛Car 只能有一個Manufacturer —— 使用下面的定義:

from django.db import models

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

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

建議你用被關聯的模型的小寫名稱做為ForeignKey 欄位的名字(例如,上面manufacturer)。當然,你也可以起別的名字。例如:

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

另見

ForeignKey 欄位還接受許多別的引數,在模型欄位參考有詳細介紹。這些選項幫助定義關聯關係應該如何工作;它們都是可選的引數。

多對多關係

ManyToManyField 用來定義多對多關係,用法和其他Field 欄位型別一樣:在模型中做為一個類屬性包含進來。

例如,一個Pizza可以有多種Topping —— 一種Topping 可以位於多個Pizza 上,而且每個Pizza 可以有多種Topping —— 如下:

from django.db import models

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

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

建議你以被關聯模型名稱的複數形式做為ManyToManyField 的名字(例如上例中的toppings)。

在哪個模型中設定 ManyToManyField 並不重要,在兩個模型中任選一個即可 —— 不要兩個模型都設定。

通常,ManyToManyField 例項應該位於可以編輯的表單中。在上面的例子中,toppings 位於Pizza 中(而不是在 Topping 裡面設定pizzasManyToManyField 欄位),因為設想一個Pizza 有多種Topping 比一個Topping 位於多個Pizza 上要更加自然。按照上面的方式,在Pizza 的表單中將允許使用者選擇不同的Toppings。

另見

ManyToManyField 欄位還接受別的引數,在模型欄位參考中有詳細介紹。這些選項幫助定義關係應該如何工作;它們都是可選的。

多對多關係中的其他欄位

處理類似搭配 pizza 和 topping 這樣簡單的多對多關係時,使用標準的ManyToManyField  就可以了。但是,有時你可能需要關聯資料到兩個模型之間的關係上。

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

對於這些情況,Django 允許你指定一個模型來定義多對多關係。 你可以將其他欄位放在中介模型裡面。源模型的ManyToManyField 欄位將使用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)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

在設定中介模型時,要顯式指定外來鍵並關聯到多對多關係涉及的模型。這個顯式宣告定義兩個模型之間是如何關聯的。

中介模型有一些限制:

  • 中介模型必須有且只有一個外來鍵到源模型(上面例子中的Group),或者你必須使用ManyToManyField.through_fields 顯式指定Django 應該使用的外來鍵。如果你的模型中存在超個一個的外來鍵,並且through_fields沒有指定,將會觸發一個無效的錯誤。 對目標模型的外來鍵有相同的限制(上面例子中的 Person)。
  • 對於通過中介模型與自己進行多對多關聯的模型,允許存在到同一個模型的兩個外來鍵,但它們將被作為多對多關聯關係的兩個(不同的)方面。如果有超過 兩個外來鍵,同樣你必須像上面一樣指定through_fields,否則將引發一個驗證錯誤。

Changed in Django 1.7:

在Django 1.6 及之前的版本中,中介模型禁止包含多於一個的外來鍵。

既然你已經設定好ManyToManyField 來使用中介模型(在這個例子中就是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()
[<Person: Ringo Starr>]
>>> ringo.group_set.all()
[<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()
[<Person: Ringo Starr>, <Person: Paul McCartney>]

與普通的多對多欄位不同,你不能使用addcreate和賦值語句(比如,beatles.members = [...])來建立關係:

# THIS WILL NOT WORK
>>> beatles.members.add(john)
# NEITHER WILL THIS
>>> beatles.members.create(name="George Harrison")
# AND NEITHER WILL THIS
>>> beatles.members = [john, paul, ringo, george]

為什麼不能這樣做? 這是因為你不能只建立 PersonGroup之間的關聯關係,你還要指定 Membership模型中所需要的所有資訊;而簡單的addcreate 和賦值語句是做不到這一點的。所以它們不能在使用中介模型的多對多關係中使用。此時,唯一的辦法就是建立中介模型的例項。

remove()方法被禁用也是出於同樣的原因。但是clear() 方法卻是可用的。它可以清空某個例項所有的多對多關係:

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

通過建立中介模型的例項來建立對多對多關係後,你就可以執行查詢了。 和普通的多對多欄位一樣,你可以直接使用被關聯模型的屬性進行查詢:

# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
[<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))
[<Person: Ringo Starr]

如果你需要訪問一個成員的資訊,你可以直接獲取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物件上查詢多對多反轉關係

>>> 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用來定義一對一關係。 用法和其他欄位型別一樣:在模型裡面做為類屬性包含進來。

當某個物件想擴充套件自另一個物件時,最常用的方式就是在這個物件的主鍵上新增一對一關係。

例如,你想建一個“places” 資料庫,裡面有一些常用的欄位,比如address、 phone number 等等。 接下來,如果你想在Place 資料庫的基礎上建立一個Restaurant 資料庫,而不想將已有的欄位複製到Restaurant模型,那你可以在 Restaurant 新增一個OneToOneField 欄位,這個欄位指向Place(因為Restaurant 本身就是一個Place;事實上,在處理這個問題的時候,你應該使用一個典型的 繼承,它隱含一個一對一關係)。

另見

OneToOneField欄位也接受一個特定的可選的parent_link引數,在模型欄位參考 中有詳細介紹。

在以前的版本中,OneToOneField 欄位會自動變成模型 的主鍵。不過現在已經不這麼做了(不過要是你願意的話,你仍可以傳遞 primary_key引數來建立主鍵欄位)。所以一個 模型 中可以有多個OneToOneField 欄位。

跨檔案的模型

訪問其他應用的模型是非常容易的。 在檔案頂部你定義模型的地方,匯入相關的模型來實現它。然後,無論在哪裡需要的話,都可以引用它。例如:

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 的保留字例如joinwhereselect,可以用作模型的欄位名,因為Django 會對底層的SQL 查詢語句中的資料庫表名和列名進行轉義。 它根據你的資料庫引擎使用不同的引用語法。

自定義欄位型別

如果已有的模型欄位都不合適,或者你想用到一些很少見的資料庫列型別的優點,你可以建立你自己的欄位型別。建立你自己的欄位在編寫自定義的模型欄位中有完整講述。

元選項

使用內部的class Meta 定義模型的元資料,例如:

from django.db import models

class Ox(models.Model):
    horn_length = models.IntegerField()

    class Meta:
        ordering = ["horn_length"]
        verbose_name_plural = "oxen"

模型元資料是“任何不是欄位的資料”,比如排序選項(ordering),資料表名(db_table)或者人類可讀的單複數名稱(verbose_nameverbose_name_plural)。在模型中新增class Meta是完全可選的,所有選項都不是必須的。

所有選項的完整列表可以在模型選項參考找到。

模型的屬性

objects

The most important attribute of a model is the
Manager. It’s the interface through which
database query operations are provided to Django models and is used to
retrieve the instances from the database. If no
custom Manager is defined, the default name is
objects. Managers are only accessible via
model classes, not the model instances.

模型的方法

可以在模型上定義自定義的方法來給你的物件新增自定義的“底層”功能。Manager 方法用於“表範圍”的事務,模型的方法應該著眼於特定的模型例項。

這是一個非常有價值的技術,讓業務邏輯位於同一個地方 —— 模型中。

例如,下面的模型具有一些自定義的方法:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    birth_date = models.DateField()

    def baby_boomer_status(self):
        "Returns the person's baby-boomer status."
        import datetime
        if self.birth_date < datetime.date(1945, 8, 1):
            return "Pre-boomer"
        elif self.birth_date < datetime.date(1965, 1, 1):
            return "Baby boomer"
        else:
            return "Post-boomer"

    def _get_full_name(self):
        "Returns the person's full name."
        return '%s %s' % (self.first_name, self.last_name)
    full_name = property(_get_full_name)

這個例子中的最後一個方法是一個property

模型例項參考 具有一個完整的為模型自動生成的方法 列表。你可以覆蓋它們 —— 參見下文覆蓋模型預定義的方法 —— 但是有些方法你會始終想要重新定義:

Python 3 equivalent of __unicode__().

一個Python “魔法方法”,返回物件的Unicode “表示形式”。當模型例項需要強制轉換並顯示為普通的字串時,Python 和Django 將使用這個方法。最明顯是在互動式控制檯或者管理站點顯示一個物件的時候。

將將永遠想要定義這個方法;預設的方法幾乎沒有意義。

它告訴Django 如何計算一個物件的URL。Django 在它的管理站點中使用到這個方法,在其它任何需要計算一個物件的URL 時也將用到。

任何具有唯一標識自己的URL 的物件都應該定義這個方法。

覆蓋預定義的模型方法

還有另外一部分封裝資料庫行為的模型方法,你可能想要自定義它們。特別是,你將要經常改變save()delete() 的工作方式。

你可以自由覆蓋這些方法(和其它任何模型方法)來改變它們的行為。

覆蓋內建模型方法的一個典型的使用場景是,你想在儲存一個物件時做一些其它事情。例如(參見save() 中關於它接受的引數的文件):

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        do_something()
        super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
        do_something_else()

你還可以阻止儲存:

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        if self.name == "Yoko Ono's blog":
            return # Yoko shall never have her own blog!
        else:
            super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.

必須要記住呼叫超類的方法—— super(Blog, self).save(*args, **kwargs) —— 來確保物件被儲存到資料庫中。如果你忘記呼叫超類的這個方法,預設的行為將不會發生且資料庫不會有任何改變。

還要記住傳遞引數給這個模型方法 —— 即*args, **kwargs。 Django 未來將一直會擴充套件內建模型方法的功能並新增新的引數。如果在你的方法定義中使用*args, **kwargs,將保證你的程式碼自動支援這些新的引數。

Overridden model methods are not called on bulk operations

執行自定義的SQL

另外一個常見的需求是在模型方法和模組級別的方法中編寫自定義的SQL 語句。關於使用原始SQL 語句的更多細節,參見使用原始 SQL 的文件。

模型繼承

Django 中的模型繼承與 Python 中普通類繼承方式幾乎完全相同,但是本頁頭部列出的模型基本的要求還是要遵守。這表示自定義的模型類應該繼承django.db.models.Model

你唯一需要作出的決定就是你是想讓父模型具有它們自己的資料庫表,還是讓父模型只持有一些共同的資訊而這些資訊只有在子模型中才能看到。

在Django 中有3中風格的繼承。

  1. 通常,你只想使用父類來持有一些資訊,你不想在每個子模型中都敲一遍。這個類永遠不會單獨使用,所以你使用抽象基類
  2. 如果你繼承一個已經存在的模型且想讓每個模型具有它自己的資料庫表,那麼應該使用多表繼承
  3. 最後,如果你只是想改變模組Python 級別的行為,而不用修改模型的欄位,你可以使用代理模型

抽象基類

當你想將一些常見資訊儲存到很多model的時候,抽象化類是十分有用的。你編寫完基類之後,在 Meta類中設定 abstract=True ,該類就不能建立任何資料表。取而代之的是,當它被用來作為一個其他model的基礎類時,它將被加入那一子類中。如果抽象化基礎類和它的子類有相同的項,那麼將會出現error(並且Django將返回一個exception)。

一個例子

from django.db import models

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()

    class Meta:
        abstract = True

class Student(CommonInfo):
    home_group = models.CharField(max_length=5)

Student 模型將有三個項:name, agehome_groupCommonInfo 模型無法像一般的Django模型一樣使用,因為它是一個抽象化基礎類。它無法生成資料表單或者管理器,並且不能例項化或者儲存。

對很多使用者來說, 這種型別的模型繼承就是你想要的。它提供一種在 Python 語言層級上提取公共資訊的方式,但在資料庫層級上,各個子類仍然只建立一個數據庫。

繼承

當一個抽象類被建立的時候, Django會自動把你在基類中定義的 Meta 作為子類的一個屬性。如果子類沒有宣告自己的Meta 類, 他將會繼承父類的Meta. 如果子類想要擴充套件父類  的,可以繼承父類的 Meta 即可,例如

from django.db import models

class CommonInfo(models.Model):
    # ...
    class Meta:
        abstract = True
        ordering = ['name']

class Student(CommonInfo):
    # ...
    class Meta(CommonInfo.Meta):
        db_table = 'student_info'

繼承時,Django 會對基類的 Meta類做一個調整:在安裝 Meta屬性之前,Django 會設定 abstract=False。這意味著抽象基類的子類不會自動變成抽象類。 當然,你可以讓一個抽象類繼承另一個抽象基類,不過每次都要顯式地設定 abstract=True

對於抽象基類而言,有些屬性放在  Meta 內嵌類裡面是沒有意義的。例如,包含 db_table將意味著所有的子類(是指那些沒有指定自己的 Meta 類的子類)都使用同一張資料表,一般來說,這並不是我們想要的。

小心使用 related_name

如果你在 ForeignKey或  ManyToManyField欄位上使用  related_name屬性,你必須總是為該欄位指定一個唯一的反向名稱。但在抽象基類上這樣做就會引發一個很嚴重的問題。因為 Django 會將基類欄位新增到每個子類當中,而每個子類的欄位屬性值都完全相同 (這裡面就包括related_name)。

當你在(且僅在)抽象基類中使用 related_name 時,如果想繞過這個問題,名稱中就要包含'%(app_label)s'和 '%(class)s'

  • '%(class)s' 會替換為子類的小寫加下劃線格式的名稱,欄位在子類中使用。
  • '%(app_label)s' 會替換為應用的小寫加下劃線格式的名稱,應用包含子類。每個安裝的應用名稱都應該是唯一的,而且應用裡每個模型類的名稱也應該是唯一的,所以產生的名稱應該彼此不同。

例如,假設有一個app叫做common/models.py

from django.db import models

class Base(models.Model):
    m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related")

    class Meta:
        abstract = True

class ChildA(Base):
    pass

class ChildB(Base):
    pass

以及另一個應用 rare/models.py

from common.models import Base

class ChildB(Base):
    pass

ChildA.m2m 欄位的反向名稱是 childa_related,而 ChildB.m2m 欄位的反向名稱是 childb_related。這取決於你如何使用  '%(class)s''%(app_label)s來構造你的反向名稱。如果你沒有這樣做,Django 就會在驗證 model (或執行 migrate) 時丟擲錯誤。

果你沒有在抽象基類中為某個關聯欄位定義 related_name 屬性,那麼預設的反向名稱就是子類名稱加上'_set',它能否正常工作取決於你是否在子類中定義了同名欄位。例如,在上面的程式碼中,如果去掉 related_name屬性,在 ChildA中,m2m 欄位的反向名稱就是 childa_set;而 ChildB的 m2m 欄位的反向名稱就是 childb_set

多表繼承

這是 Django 支援的第二種繼承方式。使用這種繼承方式時,同一層級下的每個子 model 都是一個真正意義上完整的 model 。 每個子 model 都有專屬的資料表,都可以查詢和建立資料表。 繼承關係在子 model 和它的每個父類之間都新增一個連結 (通過一個自動建立的 OneToOneField來實現)。 例如:

from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.
            
           

相關推薦

django 1.8 官方翻譯 2-5-7 自定義查詢

自定義查詢 New in Django 1.7. Django為過濾提供了大量的內建的查詢(例如,exact和icontains)。這篇文件闡述瞭如何編寫自定義查詢,以及如何修改現存查詢的功能。關於查詢的API參考,詳見查詢API參考。 一個簡單的

django 1.8 官方翻譯 2-2-1 執行查詢

執行查詢 一旦你建立好資料模型之後,django會自動生成一套資料庫抽象的API,可以讓你執行增刪改查的操作。這篇文件闡述瞭如何使用這些API。關於所有模型檢索選項的詳細內容,請見。 在整個文件(以及參考)中,我們會大量使用下面的模型,它構成了一個部落格應用

django 1.8 官方翻譯2-1-1 模型語法

模型 模型是你的資料的唯一的、權威的資訊源。它包含你所儲存資料的必要欄位和行為。通常,每個模型對應資料庫中唯一的一張表。 基礎: 模型的每個屬性都表示資料庫中的一個欄位。 Django 提供一套自動生成的用於資料庫訪問的API;詳見執行查詢。

django 1.8 官方翻譯7-2 管理操作

管理操作 簡而言之,Django管理後臺的基本流程是,“選擇一個物件並改變它”。在大多數情況下,這是非常適合的。然而當你一次性要對多個物件做相同的改變,這個流程是非常的單調乏味的。 在這些例子中,Django管理後臺可以讓你實現和註冊“操作” —— 僅僅只是

Hyperledger Fabric 1.3 官方翻譯(三)關鍵概念 (Key Concepts)

身份(Identity) 什麼是身份(What is an Identity)? The different actors in a blockchain network include peers, orderers, client applications,

Hyperledger Fabric 1.3 官方翻譯(五)教程 (Tutorials)

構建你的第一個網路(Building Your First Network) These instructions have been verified to work against the latest stable Docker images and t

Spark官方翻譯Spark Programming Guide(一)

Overview At a high level, every Spark application consists of a driver program that runs the user’s main function and executes var

Storm Kafka Integration (0.10.x+)官方翻譯storm與kafka整合

Storm Kafka Integration (0.10.x+) 相容性 Apache Kafka版本0.10以上 向kafka寫資料作為拓撲的一部分 你可以建立一個org.apache.storm.kafka.bolt.KafkaBolt的例項,

1.solr5官方中文快速入門

1.1安裝solr 1.1.1 環境準備 需要安裝JRE,版本1.7以上 1.1.2安裝solr 到solr官網http://lucene.apache.org/solr/下載安裝包。 Linux/Unix/OSX系統下載.tgz檔案包,windows系統下載.zip檔

django 2.1官方翻譯-模板(進行中)

django的官方文件在transifex上翻譯,本來想貢獻一下,結果發現那個介面實在是受不了。自己翻吧 模板 作為一個Web框架,Django需要一種動態生成HTML的便捷方式。最常見的方法是使用模板。模板包含HTML輸出的靜態部分以及能插入動態內容的一些特殊語法。有關使用模板建立HT

【Gradle官方翻譯】起步2建立構建掃描

構建掃描是對構建的可分享的專門記錄,可以看到“構建中發生了那些行為以及為什麼會發生這種行為”。通過在專案中使用構建掃描外掛,開發者可以免費地在https://scans.gradle.com/上釋出構建掃描。 將要建立的 本文會展示如何在不對任何構建指令碼進行

Cloudera 從5.2.0升級到最新5.8.2官方翻譯

最近把叢集升級了,升級同時把官方文件翻譯了一下。初始文件整理在pages中,怎麼轉換過來格式都不太好看,先發圖片的吧,格式不太好的文字部分在後面。 ----------------------------------------------我是格式不好的文字的分割

Django快取框架詳解(官方翻譯來)

首先看Django官網的介紹:    動態網站的一個基本權衡就是他們是動態的,每次一個使用者請求一個頁面,web伺服器進行各種各樣的計算-從資料庫查詢到模板渲染到業務邏輯-從而生成站點訪問者看到的頁面。從處理開銷的角度來看,相比標準的從檔案系統讀取檔案的伺服器排程,這是昂貴了

Spring官方翻譯1~6章)

Spring框架是一個輕量級的解決方案,可以一站式地構建企業級應用。Spring是模組化的,所以可以只使用其中需要的部分。可以在任何web框架上使用控制反轉(IoC),也可以只使用Hibernate整合程式碼或JDBC抽象層。它支援宣告式事務管理、通

Django 2.0 之Models(模型) 官方翻譯(一)

以下翻譯是自己學習的時候順便記下的,如果有不對的地方還請指正。 模型是關於你的資料的唯一、確定的資料來源。它包含你所儲存的資料的基本欄位和行為。通常,每個模型對映到一個數據庫表。 基礎知識: 每一個模型都是一個Python類,它是 django.db.models.Mo

ABP官方翻譯 6.2.1 ASP.NET Core集成

mic 模型 binder let 轉換 span optional document clas ASP.NET Core 介紹 遷移到ASP.NET Core? 啟動模板 配置 啟動類 模塊配置 控制器 應用服務作為控制器

C# MulticolorWin2.1.8彩色

操作系統 彩色 並且 2個 完成 無法使用 至少 styles com 一、系統介紹 本軟件主要讓你的文件夾多彩多樣化,而不是千篇一律黃色的文件夾,相信豐富多彩的顏色更便於記憶、能讓心情愉快些。 文件夾顏色眾多,到底有多少種呢,10種? 100種? 1000種

#pragma comment 官方翻譯

一 格式 #pragma comment(comment-type [,commentstring] ) 作用 Places a comment record into an object file or executable file. 翻譯:將一個註釋記錄放入一個object檔案

著色器shader官方翻譯

近期打算好好學習shader,期望能做出大海波浪等絢麗的效果。 官方文件的翻譯,算是我的附帶產出,增強對shader的瞭解,也是為後人參考學習提供捷徑。 ---------------------------------------------------------------------

Hibernate官方翻譯-(第二章,入門)

第二章:使用原生Hibernate API 和hbm.xml對映 (示例程式碼下載地址http://sourceforge.net/projects/hibernate/files/hibernate4/) 2.1. Hibernate configuration 檔案 資原始檔hibern