# 模型實例參考 #
該文檔詳細描述模型 的API。它建立在模型 和執行查詢 的資料之上, 所以在閱讀這篇文檔之前,你可能會想要先閱讀并理解那兩篇文檔。
我們將用執行查詢中所展現的 博客應用模型 來貫穿這篇參考文獻。
## 創建對象 ##
要創建模型的一個新實例,只需要像其它Python 類一樣實例化它:
`class Model(**kwargs)`
關鍵字參數就是在你的模型中定義的字段的名字。注意,實例化一個模型不會訪問數據庫;若要保存,你需要save() 一下。
> 注
>
> 也許你會想通過重寫 `__init__` 方法來自定義模型。無論如何,如果你這么做了,小心不要改變了調用簽名——任何改變都可能阻礙模型實例被保存。嘗試使用下面這些方法之一,而不是重寫__init__:
>
> 1\. 在模型類中增加一個類方法:
```
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
@classmethod
def create(cls, title):
book = cls(title=title)
# do something with the book
return book
book = Book.create("Pride and Prejudice")
```
> 2\. 在自定義管理器中添加一個方法(推薦):
```
class BookManager(models.Manager):
def create_book(self, title):
book = self.create(title=title)
# do something with the book
return book
class Book(models.Model):
title = models.CharField(max_length=100)
objects = BookManager()
book = Book.objects.create_book("Pride and Prejudice")
```
### 自定義模型加載 ###
`classmethod Model.from_db(db, field_names, values)`
```
New in Django 1.8.
```
`from_db()` 方法用于自定義從數據庫加載時模型實例的創建。
`db` 參數包含數據庫的別名,`field_names` 包含所有加載的字段的名稱,`values` 包含`field_names` 中每個字段加載的值。`field_names` 與`values` 的順序相同,所以可以使用`cls(**(zip(field_names, values)))` 來實例化對象。如果模型的所有字段都提供,會保證` values` 的順序與`__init__()` 所期望的一致。這表示此時實例可以通過`cls(*values)` 創建。可以通過`cls._deferred `來檢查是否提供所有的字段 —— 如果為 `False`,那么所有的字段都已經從數據庫中加載。
除了創建新模型之前,`from_db()` 必須設置新實例`_state` 屬性中的`adding` 和 `db` 標志位。
下面的示例演示如何保存從數據庫中加載進來的字段原始值:
```
@classmethod
def from_db(cls, db, field_names, values):
# default implementation of from_db() (could be replaced
# with super())
if cls._deferred:
instance = cls(**zip(field_names, values))
else:
instance = cls(*values)
instance._state.adding = False
instance._state.db = db
# customization to store the original field values on the instance
instance._loaded_values = zip(field_names, values)
return instance
def save(self, *args, **kwargs):
# Check how the current values differ from ._loaded_values. For example,
# prevent changing the creator_id of the model. (This example doesn't
# support cases where 'creator_id' is deferred).
if not self._state.adding and (
self.creator_id != self._loaded_values['creator_id']):
raise ValueError("Updating the value of creator isn't allowed")
super(...).save(*args, **kwargs)
```
上面的示例演示`from_db() `的完整實現。當然在這里的`from_db() `中完全可以只用`super()` 調用。
## 從數據庫更新對象 ##
`Model.refresh_from_db(using=None, fields=None, **kwargs)`
```
New in Django 1.8.
```
如果你需要從數據庫重新加載模型的一個值,你可以使用 `refresh_from_db()` 方法。當不帶參數調用這個方法時,將完成以下的動作:
模型的所有非延遲字段都更新成數據庫中的當前值。
之前加載的關聯實例,如果關聯的值不再合法,將從重新加載的實例中刪除。例如,如果重新加載的實例有一個外鍵到另外一個模型`Author`,那么如果 `obj.author_id != obj.author.id`,`obj.author` 將被扔掉并在下次訪問它時根據`obj.author_id` 的值重新加載。
注意,只有本模型的字段會從數據庫重新加載。其它依賴數據庫的值不會重新加載,例如聚合的結果。
重新加載使用的數據庫與實例加載時使用的數據庫相同,如果實例不是從數據庫加載的則使用默認的數據庫。可以使用`using` 參數來強制指定重新加載的數據庫。
可以回使用`fields` 參數強制設置加載的字段。
例如,要測試`update()` 調用是否得到預期的更新,可以編寫類似下面的測試:
```
def test_update_result(self):
obj = MyModel.objects.create(val=1)
MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
# At this point obj.val is still 1, but the value in the database
# was updated to 2. The object's updated value needs to be reloaded
# from the database.
obj.refresh_from_db()
self.assertEqual(obj.val, 2)
```
注意,當訪問延遲的字段時,延遲字段的加載會通過這個方法加載。所以可以自定義延遲加載的行為。下面的實例演示如何在重新加載一個延遲字段時重新加載所有的實例字段:
```
class ExampleModel(models.Model):
def refresh_from_db(self, using=None, fields=None, **kwargs):
# fields contains the name of the deferred field to be
# loaded.
if fields is not None:
fields = set(fields)
deferred_fields = self.get_deferred_fields()
# If any deferred field is going to be loaded
if fields.intersection(deferred_fields):
# then load all of them
fields = fields.union(deferred_fields)
super(ExampleModel, self).refresh_from_db(using, fields, **kwargs)
```
`Model.get_deferred_fields()`
```
New in Django 1.8.
```
一個輔助方法,它返回一個集合,包含模型當前所有延遲字段的屬性名稱。
## 驗證對象 ##
驗證一個模型涉及三個步驟:
1. 驗證模型的字段 —— `Model.clean_fields()`
2. 驗證模型的完整性 —— `Model.clean()`
3. 驗證模型的唯一性 —— `Model.validate_unique()`
當你調用模型的`full_clean()` 方法時,這三個方法都將執行。
當你使用`ModelForm`時,`is_valid()` 將為表單中的所有字段執行這些驗證。更多信息參見`ModelForm` 文檔。 如果你計劃自己處理驗證出現的錯誤,或者你已經將需要驗證的字段從`ModelForm` 中去除掉,你只需調用模型的`full_clean()` 方法。
`Model.full_clean(exclude=None, validate_unique=True)`
該方法按順序調用`Model.clean_fields()`、`Model.clean()` 和`Model.validate_unique()`(如果`validate_unique` 為`True`),并引發一個`ValidationError`,該異常的`message_dict` 屬性包含三個步驟的所有錯誤。
可選的`exclude` 參數用來提供一個可以從驗證和清除中排除的字段名稱的列表。`ModelForm` 使用這個參數來排除表單中沒有出現的字段,使它們不需要驗證,因為用戶無法修正這些字段的錯誤。
注意,當你調用模型的`save()` 方法時,`full_clean() `不會 自動調用。如果你想一步就可以為你手工創建的模型運行驗證,你需要手工調用它。例如:
```
from django.core.exceptions import ValidationError
try:
article.full_clean()
except ValidationError as e:
# Do something based on the errors contained in e.message_dict.
# Display them to a user, or handle them programmatically.
pass
```
`full_clean()` 第一步執行的是驗證每個字段。
`Model.clean_fields(exclude=None)`
這個方法將驗證模型的所有字段。可選的`exclude` 參數讓你提供一個字段名稱列表來從驗證中排除。如果有字段驗證失敗,它將引發一個`ValidationError`。
`full_clean()` 第二步執行的是調用`Model.clean()`。如要實現模型自定義的驗證,應該覆蓋這個方法。
`Model.clean()`
應該用這個方法來提供自定義的模型驗證,以及修改模型的屬性。例如,你可以使用它來給一個字段自動提供值,或者用于多個字段需要一起驗證的情形:
```
import datetime
from django.core.exceptions import ValidationError
from django.db import models
class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date.
if self.status == 'draft' and self.pub_date is not None:
raise ValidationError('Draft entries may not have a publication date.')
# Set the pub_date for published items if it hasn't been set already.
if self.status == 'published' and self.pub_date is None:
self.pub_date = datetime.date.today()
```
然而請注意,和`Model.full_clean()` 類似,調用模型的`save()` 方法時不會引起`clean()` 方法的調用。
在上面的示例中,`Model.clean()` 引發的`ValidationError` 異常通過一個字符串實例化,所以它將被保存在一個特殊的錯誤字典鍵`NON_FIELD_ERRORS`中。這個鍵用于整個模型出現的錯誤而不是一個特定字段出現的錯誤:
```
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
try:
article.full_clean()
except ValidationError as e:
non_field_errors = e.message_dict[NON_FIELD_ERRORS]
```
若要引發一個特定字段的異常,可以使用一個字典實例化`ValidationError`,其中字典的鍵為字段的名稱。我們可以更新前面的例子,只引發`pub_date` 字段上的異常:
```
class Article(models.Model):
...
def clean(self):
# Don't allow draft entries to have a pub_date.
if self.status == 'draft' and self.pub_date is not None:
raise ValidationError({'pub_date': 'Draft entries may not have a publication date.'})
...
```
最后,`full_clean()` 將檢查模型的唯一性約束。
`Model.validate_unique(exclude=None)`
該方法與`clean_fields()` 類似,只是驗證的是模型的所有唯一性約束而不是單個字段的值。可選的`exclude` 參數允許你提供一個字段名稱的列表來從驗證中排除。如果有字段驗證失敗,將引發一個 `ValidationError`。
注意,如果你提供一個`exclude` 參數給`validate_unique()`,任何涉及到其中一個字段的`unique_together` 約束將不檢查。
## 對象保存 ##
將一個對象保存到數據庫,需要調用 `save()`方法:
`Model.save([force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None])`
如果你想要自定義保存的動作,你可以重寫 `save()` 方法。請看 重寫預定義的模型方法 了解更多細節。
模型保存過程還有一些細節的地方要注意;請看下面的章節。
### 自增的主鍵 ###
如果模型具有一個`AutoField` —— 一個自增的主鍵 —— 那么該自增的值將在第一次調用對象的`save()` 時計算并保存:
```
>>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b2.id # Returns None, because b doesn't have an ID yet.
>>> b2.save()
>>> b2.id # Returns the ID of your new object.
```
在調用`save()` 之前無法知道ID 的值,因為這個值是通過數據庫而不是Django 計算。
為了方便,默認情況下每個模型都有一個`AutoField` 叫做`id`,除非你顯式指定模型某個字段的 `primary_key=True`。更多細節參見`AutoField` 的文檔。
#### pk 屬性 ####
`Model.pk`
無論你是自己定義還是讓Django 為你提供一個主鍵字段, 每個模型都將具有一個屬性叫做`pk`。它的行為類似模型的一個普通屬性,但實際上是模型主鍵字段屬性的別名。你可以讀取并設置它的值,就和其它屬性一樣,它會更新模型中正確的值。
#### 顯式指定自增主鍵的值 ####
如果模型具有一個`AutoField`,但是你想在保存時顯式定義一個新的對象`ID`,你只需要在保存之前顯式指定它而不用依賴`ID` 自動分配的值:
```
>>> b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b3.id # Returns 3.
>>> b3.save()
>>> b3.id # Returns 3.
```
如果你手工賦值一個自增主鍵的值,請確保不要使用一個已經存在的主鍵值!如果你使用數據庫中已經存在的主鍵值創建一個新的對象,Django 將假設你正在修改這個已存在的記錄而不是創建一個新的記錄。
接著上面的'`Cheddar Talk`' 博客示例,下面這個例子將覆蓋數據庫中之前的記錄:
```
b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.')
b4.save() # Overrides the previous blog with ID=3!
```
出現這種情況的原因,請參見下面的[Django 如何知道是UPDATE 還是INSERT](http://python.usyiyi.cn/django/ref/models/instances.html#how-django-knows-to-update-vs-insert)。
顯式指定自增主鍵的值對于批量保存對象最有用,但你必須有信心不會有主鍵沖突。
### 當你保存時,發生了什么? ###
當你保存一個對象時,Django 執行以下步驟:
1\. 發出一個`pre-save` 信號。 發送一個`django.db.models.signals.pre_save` 信號,以允許監聽該信號的函數完成一些自定義的動作。
2\. 預處理數據。 如果需要,對對象的每個字段進行自動轉換。
大部分字段不需要預處理 —— 字段的數據將保持原樣。預處理只用于具有特殊行為的字段。例如,如果你的模型具有一個`auto_now=True` 的`DateField`,那么預處理階段將修改對象中的數據以確保該日期字段包含當前的時間戳。(我們的文檔還沒有所有具有這種“特殊行為”字段的一個列表。)
3\. 準備數據庫數據。 要求每個字段提供的當前值是能夠寫入到數據庫中的類型。
大部分字段不需要數據準備。簡單的數據類型,例如整數和字符串,是可以直接寫入的Python 對象。但是,復雜的數據類型通常需要一些改動。
例如,`DateField` 字段使用Python 的 `datetime` 對象來保存數據。數據庫保存的不是`datetime` 對象,所以該字段的值必須轉換成ISO兼容的日期字符串才能插入到數據庫中。
4\. 插入數據到數據庫中。 將預處理過、準備好的數據組織成一個SQL 語句用于插入數據庫。
5\. 發出一個post-save 信號。 發送一個`django.db.models.signals.post_save` 信號,以允許監聽聽信號的函數完成一些自定義的動作。
### Django 如何知道是UPDATE 還是INSERT ###
你可能已經注意到Django 數據庫對象使用同一個`save()` 方法來創建和改變對象。Django 對`INSERT` 和`UPDATE` SQL 語句的使用進行抽象。當你調用`save()` 時,Django 使用下面的算法:
+ 如果對象的主鍵屬性為一個求值為`True` 的值(例如,非`None` 值或非空字符串),Django 將執行`UPDATE`。
+ 如果對象的主鍵屬性沒有設置或者`UPDATE` 沒有更新任何記錄,Django 將執行`INSERT`。
現在應該明白了,當保存一個新的對象時,如果不能保證主鍵的值沒有使用,你應該注意不要顯式指定主鍵值。關于這個細微差別的更多信息,參見上文的顯示指定主鍵的值 和下文的強制使用`INSERT` 或`UPDATE`。
在Django 1.5 和更早的版本中,在設置主鍵的值時,Django 會作一個 `SELECT`。如果`SELECT` 找到一行,那么Django 執行`UPDATE`,否則執行`INSERT`。舊的算法導致`UPDATE` 情況下多一次查詢。有極少數的情況,數據庫不會報告有一行被更新,即使數據庫包含該對象的主鍵值。有個例子是PostgreSQL 的`ON UPDATE` 觸發器,它返回NULL。在這些情況下,可能要通過將`select_on_save` 選項設置為`True` 以啟用舊的算法。
#### 強制使用INSERT 或UPDATE ####
在一些很少見的場景中,需要強制`save()` 方法執行SQL 的 `INSERT` 而不能執行`UPDATE`。或者相反:更新一行而不是插入一個新行。在這些情況下,你可以傳遞`force_insert=True` 或 `force_update=True` 參數給`save()` 方法。顯然,兩個參數都傳遞是錯誤的:你不可能同時插入和更新!
你應該極少需要使用這些參數。Django 幾乎始終會完成正確的事情,覆蓋它將導致錯誤難以跟蹤。這個功能只用于高級用法。
使用`update_fields` 將強制使用類似`force_update` 的更新操作。
### 基于已存在字段值的屬性更新 ###
有時候你需要在一個字段上執行簡單的算法操作,例如增加或者減少當前值。實現這點的簡單方法是像下面這樣:
```
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold += 1
>>> product.save()
```
如果從數據庫中讀取的舊的`number_sold` 值為10,那么寫回到數據庫中的值將為11。
通過將更新基于原始字段的值而不是顯式賦予一個新值,這個過程可以[避免競態條件](http://python.usyiyi.cn/django/ref/models/expressions.html#avoiding-race-conditions-using-f)而且更快。Django 提供`F 表達式` 用于這種類型的相對更新。利用`F 表達式`,前面的示例可以表示成:
```
>>> from django.db.models import F
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold = F('number_sold') + 1
>>> product.save()
```
更多細節,請參見`F 表達式` 和它們[在更新查詢中的用法](http://python.usyiyi.cn/django/topics/db/queries.html#topics-db-queries-update)。
### 指定要保存的字段 ###
如果傳遞給`save()` 的`update_fields` 關鍵字參數一個字段名稱列表,那么將只有該列表中的字段會被更新。如果你想更新對象的一個或幾個字段,這可能是你想要的。不讓模型的所有字段都更新將會帶來一些輕微的性能提升。例如:
```
product.name = 'Name changed again'
product.save(update_fields=['name'])
```
`update_fields` 參數可以是任何包含字符串的可迭代對象。空的`update_fields` 可迭代對象將會忽略保存。如果為`None` 值,將執行所有字段上的更新。
指定`update_fields` 將強制使用更新操作。
當保存通過延遲模型加載(`only()` 或`defer()`)進行訪問的模型時,只有從數據庫中加載的字段才會得到更新。這種情況下,有個自動的`update_fields`。如果你賦值或者改變延遲字段的值,該字段將會添加到更新的字段中。
## 刪除對象 ##
`Model.delete([using=DEFAULT_DB_ALIAS])`
發出一個SQL `DELETE` 操作。它只在數據庫中刪除這個對象;其Python 實例仍將存在并持有各個字段的數據。
更多細節,包括如何批量刪除對象,請參見[刪除對象](http://python.usyiyi.cn/django/topics/db/queries.html#topics-db-queries-delete)。
如果你想自定義刪除的行為,你可以覆蓋`delete()` 方法。詳見[覆蓋預定義的模型方法](http://python.usyiyi.cn/django/topics/db/models.html#overriding-model-methods)。
## Pickling 對象 ##
當你`pickle` 一個模型時,它的當前狀態是pickled。當你unpickle 它時,它將包含pickle 時模型的實例,而不是數據庫中的當前數據。
> 你不可以在不同版本之間共享pickles
>
> 模型的Pickles 只對于產生它們的Django 版本有效。如果你使用Django 版本N pickle,不能保證Django 版本N+1 可以讀取這個pickle。Pickles 不應該作為長期的歸檔策略。
>
> `New in Django 1.8.`
>
> 因為pickle 兼容性的錯誤很難診斷例如一個悄無聲息損壞的對象,當你unpickle 模型使用的Django 版本與pickle 時的不同將引發一個`RuntimeWarning`。
## 其它的模型實例方法 ##
有幾個實例方法具有特殊的目的。
> 注
>
> 在Python 3 上,因為所有的字段都原生被認為是Unicode,只需使用`__str__()` 方法(`__unicode__()` 方法被廢棄)。如果你想與Python 2 兼容,你可以使用`python_2_unicode_compatible()` 裝飾你的模型類。
### \_\_unicode\_\_ ###
`Model.__unicode__()`
`__unicode__()` 方法在每當你對一個對象調用unicode() 時調用。Django 在許多地方都使用`unicode(obj)`(或者相關的函數 `str(obj)`)。最明顯的是在Django 的Admin 站點顯示一個對象和在模板中插入對象的值的時候。所以,你應該始終讓`__unicode__()` 方法返回模型的一個友好的、人類可讀的形式。
例如:
```
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __unicode__(self):
return u'%s %s' % (self.first_name, self.last_name)
```
如果你定義了模型的`__unicode__()` 方法且沒有定義`__str__()` 方法,Django 將自動提供一個 `__str__()`,它調用`__unicode__()` 并轉換結果為一個UTF-8 編碼的字符串。下面是一個建議的開發實踐:只定義`__unicode__()` 并讓Django 在需要時負責字符串的轉換。
### \_\_str\_\_ ###
`Model.__str__()`
`__str__()` 方法在每當你對一個對象調用`str()` 時調用。在Python 3 中,Django 在許多地方使用`str(obj)`。 最明顯的是在Django 的Admin 站點顯示一個對象和在模板中插入對象的值的時候。 所以,你應該始終讓`__str__()` 方法返回模型的一個友好的、人類可讀的形式。
例如:
```
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
```
在Python 2 中,Django 內部對`__str__` 的直接使用主要在隨處可見的模型的`repr()` 輸出中(例如,調試時的輸出)。如果已經有合適的`__unicode__()` 方法就不需要`__str__()` 了。
前面`__unicode__()` 的示例可以使用`__str__()` 這樣類似地編寫:
```
from django.db import models
from django.utils.encoding import force_bytes
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
# Note use of django.utils.encoding.force_bytes() here because
# first_name and last_name will be unicode strings.
return force_bytes('%s %s' % (self.first_name, self.last_name))
```
### \_\_eq\_\_ ###
`Model.__eq__()`
定義這個方法是為了讓具有相同主鍵的相同實類的實例是相等的。對于代理模型,實類是模型第一個非代理父類;對于其它模型,它的實類就是模型類自己。
例如:
```
from django.db import models
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
class MyProxyModel(MyModel):
class Meta:
proxy = True
class MultitableInherited(MyModel):
pass
MyModel(id=1) == MyModel(id=1)
MyModel(id=1) == MyProxyModel(id=1)
MyModel(id=1) != MultitableInherited(id=1)
MyModel(id=1) != MyModel(id=2)
```
```
Changed in Django 1.7:
在之前的版本中,只有類和主鍵都完全相同的實例才是相等的。
```
### \_\_hash\_\_ ###
`Model.__hash__()`
`__hash__` 方法基于實例主鍵的值。它等同于hash(obj.pk)。如果實例的主鍵還沒有值,將引發一個`TypeError`(否則,`__hash__` 方法在實例保存的前后將返回不同的值,而改變一個實例的`__hash__` 值在Python 中是禁止的)。
```
Changed in Django 1.7:
在之前的版本中,主鍵沒有值的實例是可以哈希的。
```
### get_absolute_url ###
`Model.get_absolute_url()`
`get_absolute_url()` 方法告訴Django 如何計算對象的標準URL。對于調用者,該方法返回的字符串應該可以通過HTTP 引用到這個對象。
例如:
```
def get_absolute_url(self):
return "/people/%i/" % self.id
```
(雖然這段代碼正確又簡單,這并不是編寫這個方法可移植性最好的方式。通常使用`reverse()` 函數是最好的方式。)
例如:
```
def get_absolute_url(self):
from django.core.urlresolvers import reverse
return reverse('people.views.details', args=[str(self.id)])
```
Django 使用`get_absolute_url()` 的一個地方是在Admin 應用中。如果對象定義該方法,對象編輯頁面將具有一個“View on site”鏈接,可以將你直接導入由`get_absolute_url()` 提供的對象公開視圖。
類似地,Django 的另外一些小功能,例如[syndication feed 框架](http://python.usyiyi.cn/django/ref/contrib/syndication.html) 也使用`get_absolute_url()`。 如果模型的每個實例都具有一個唯一的URL 是合理的,你應該定義`get_absolute_url()`。
> 警告
>
> 你應該避免從沒有驗證過的用戶輸入構建URL,以減少有害的鏈接和重定向:
```
def get_absolute_url(self):
return '/%s/' % self.name
```
> 如果`self.name` 為'`/example.com`',將返回 '`//example.com/`', 而它是一個合法的相對URL而不是期望的'`/%2Fexample.com/`'。
在模板中使用`get_absolute_url()` 而不是硬編碼對象的URL 是很好的實踐。例如,下面的模板代碼很糟糕:
```
<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
```
下面的模板代碼要好多了:
```
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
```
如果你改變了對象的URL 結構,即使是一些簡單的拼寫錯誤,你不需要檢查每個可能創建該URL 的地方。在`get_absolute_url()` 中定義一次,然后在其它代碼調用它。
> 注
>
> `get_absolute_url()` 返回的字符串必須只包含ASCII 字符(URI 規范[RFC 2396](http://tools.ietf.org/html/rfc2396.html) 的要求),并且如需要必須要URL-encoded。
>
> 代碼和模板中對`get_absolute_url()` 的調用應該可以直接使用而不用做進一步處理。你可能想使用`django.utils.encoding.iri_to_uri()` 函數來幫助你解決這個問題,如果你正在使用ASCII 范圍之外的Unicode 字符串。
## 額外的實例方法 ##
除了`save()`、`delete()`之外,模型的對象還可能具有以下一些方法:
`Model.get_FOO_display()`
對于每個具有`choices` 的字段,每個對象將具有一個`get_FOO_display()` 方法,其中`FOO` 為該字段的名稱。這個方法返回該字段對“人類可讀”的值。
例如:
```
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=2, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
```
`Model.get_next_by_FOO(**kwargs)`
`Model.get_previous_by_FOO(**kwargs)`
如果`DateField` 和`DateTimeField`沒有設置 `null=True`,那么該對象將具有`get_next_by_FOO()` 和`get_previous_by_FOO()` 方法,其中`FOO` 為字段的名稱。它根據日期字段返回下一個和上一個對象,并適時引發一個`DoesNotExist`。
這兩個方法都將使用模型默認的管理器來執行查詢。如果你需要使用自定義的管理器或者你需要自定義的篩選,這個兩個方法還接受可選的參數,它們應該用字段查詢 中提到的格式。
注意,對于完全相同的日期,這些方法還將利用主鍵來進行查找。這保證不會有記錄遺漏或重復。這還意味著你不可以在未保存的對象上使用這些方法。
## 其它屬性 ##
### DoesNotExist ###
exception `Model.DoesNotExist`
ORM 在好幾個地方會引發這個異常,例如`QuerySet.get()` 根據給定的查詢參數找不到對象時。
Django 為每個類提供一個`DoesNotExist` 異常屬性是為了區別找不到的對象所屬的類,并讓你可以利用`try/except`捕獲一個特定模型的類。這個異常是`django.core.exceptions.ObjectDoesNotExist` 的子類。
> 譯者:[Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html),原文:[Instance methods](https://docs.djangoproject.com/en/1.8/ref/models/instances/)。
>
> 本文以 [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/cn/) 協議發布,轉載請保留作者署名和文章出處。
>
> [Django 文檔協作翻譯小組](http://python.usyiyi.cn/django/index.html)人手緊缺,有興趣的朋友可以加入我們,完全公益性質。交流群:467338606。
- 新手入門
- 從零開始
- 概覽
- 安裝
- 教程
- 第1部分:模型
- 第2部分:管理站點
- 第3部分:視圖和模板
- 第4部分:表單和通用視圖
- 第5部分:測試
- 第6部分:靜態文件
- 高級教程
- 如何編寫可重用的應用
- 為Django編寫首個補丁
- 模型層
- 模型
- 模型語法
- 元選項
- 模型類
- 查詢集
- 執行查詢
- 查找表達式
- 模型的實例
- 實例方法
- 訪問關聯對象
- 遷移
- 模式編輯器
- 編寫遷移
- 高級
- 管理器
- 原始的SQL查詢
- 聚合
- 多數據庫
- 自定義查找
- 條件表達式
- 數據庫函數
- 其它
- 遺留的數據庫
- 提供初始數據
- 優化數據庫訪問
- 視圖層
- 基礎
- URL配置
- 視圖函數
- 快捷函數
- 裝飾器
- 參考
- 內建的視圖
- TemplateResponse 對象
- 文件上傳
- 概覽
- File 對象
- 儲存API
- 管理文件
- 自定義存儲
- 基于類的視圖
- 概覽
- 內建顯示視圖
- 內建編輯視圖
- API參考
- 分類索引
- 高級
- 生成 CSV
- 生成 PDF
- 中間件
- 概覽
- 內建的中間件類
- 模板層
- 基礎
- 面向設計師
- 語言概覽
- 人性化
- 面向程序員
- 表單
- 基礎
- 概覽
- 表單API
- 內建的Widget
- 高級
- 整合媒體
- 開發過程
- 設置
- 概覽
- 應用程序
- 異常
- 概覽
- django-admin 和 manage.py
- 添加自定義的命令
- 測試
- 介紹
- 部署
- 概述
- WSGI服務器
- 部署靜態文件
- 通過email追蹤代碼錯誤
- Admin
- 管理操作
- 管理文檔生成器
- 安全
- 安全概述
- 說明Django中的安全問題
- 點擊劫持保護
- 加密簽名
- 國際化和本地化
- 概述
- 本地化WEB UI格式化輸入
- “本地特色”
- 常見的網站應用工具
- 認證
- 概覽
- 使用認證系統
- 密碼管理
- 日志
- 分頁
- 會話
- 數據驗證
- 其它核心功能
- 按需內容處理
- 重定向
- 信號
- 系統檢查框架