該文檔詳細(xì)描述模型 的API。它建立在模型 和執(zhí)行查詢 的資料之上, 所以在閱讀這篇文檔之前,你可能會(huì)想要先閱讀并理解那兩篇文檔。
我們將用執(zhí)行查詢中所展現(xiàn)的 博客應(yīng)用模型 來貫穿這篇參考文獻(xiàn)。
要?jiǎng)?chuàng)建模型的一個(gè)新實(shí)例,只需要像其它Python 類一樣實(shí)例化它:
class Model(**kwargs)
關(guān)鍵字參數(shù)就是在你的模型中定義的字段的名字。注意,實(shí)例化一個(gè)模型不會(huì)訪問數(shù)據(jù)庫(kù);若要保存,你需要save() 一下。
注
也許你會(huì)想通過重寫
__init__
方法來自定義模型。無論如何,如果你這么做了,小心不要改變了調(diào)用簽名——任何改變都可能阻礙模型實(shí)例被保存。嘗試使用下面這些方法之一,而不是重寫init:1. 在模型類中增加一個(gè)類方法:
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. 在自定義管理器中添加一個(gè)方法(推薦):
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()
方法用于自定義從數(shù)據(jù)庫(kù)加載時(shí)模型實(shí)例的創(chuàng)建。
db
參數(shù)包含數(shù)據(jù)庫(kù)的別名,field_names
包含所有加載的字段的名稱,values
包含field_names
中每個(gè)字段加載的值。field_names
與values
的順序相同,所以可以使用cls(**(zip(field_names, values)))
來實(shí)例化對(duì)象。如果模型的所有字段都提供,會(huì)保證values
的順序與__init__()
所期望的一致。這表示此時(shí)實(shí)例可以通過cls(*values)
創(chuàng)建。可以通過cls._deferred
來檢查是否提供所有的字段 —— 如果為 False
,那么所有的字段都已經(jīng)從數(shù)據(jù)庫(kù)中加載。
除了創(chuàng)建新模型之前,from_db()
必須設(shè)置新實(shí)例_state
屬性中的adding
和 db
標(biāo)志位。
下面的示例演示如何保存從數(shù)據(jù)庫(kù)中加載進(jìn)來的字段原始值:
@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()
的完整實(shí)現(xiàn)。當(dāng)然在這里的from_db()
中完全可以只用super()
調(diào)用。
Model.refresh_from_db(using=None, fields=None, **kwargs)
New in Django 1.8.
如果你需要從數(shù)據(jù)庫(kù)重新加載模型的一個(gè)值,你可以使用 refresh_from_db()
方法。當(dāng)不帶參數(shù)調(diào)用這個(gè)方法時(shí),將完成以下的動(dòng)作:
模型的所有非延遲字段都更新成數(shù)據(jù)庫(kù)中的當(dāng)前值。
之前加載的關(guān)聯(lián)實(shí)例,如果關(guān)聯(lián)的值不再合法,將從重新加載的實(shí)例中刪除。例如,如果重新加載的實(shí)例有一個(gè)外鍵到另外一個(gè)模型Author
,那么如果 obj.author_id != obj.author.id
,obj.author
將被扔掉并在下次訪問它時(shí)根據(jù)obj.author_id
的值重新加載。
注意,只有本模型的字段會(huì)從數(shù)據(jù)庫(kù)重新加載。其它依賴數(shù)據(jù)庫(kù)的值不會(huì)重新加載,例如聚合的結(jié)果。
重新加載使用的數(shù)據(jù)庫(kù)與實(shí)例加載時(shí)使用的數(shù)據(jù)庫(kù)相同,如果實(shí)例不是從數(shù)據(jù)庫(kù)加載的則使用默認(rèn)的數(shù)據(jù)庫(kù)??梢允褂?code>using 參數(shù)來強(qiáng)制指定重新加載的數(shù)據(jù)庫(kù)。
可以回使用fields
參數(shù)強(qiáng)制設(shè)置加載的字段。
例如,要測(cè)試update()
調(diào)用是否得到預(yù)期的更新,可以編寫類似下面的測(cè)試:
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)
注意,當(dāng)訪問延遲的字段時(shí),延遲字段的加載會(huì)通過這個(gè)方法加載。所以可以自定義延遲加載的行為。下面的實(shí)例演示如何在重新加載一個(gè)延遲字段時(shí)重新加載所有的實(shí)例字段:
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.
一個(gè)輔助方法,它返回一個(gè)集合,包含模型當(dāng)前所有延遲字段的屬性名稱。
驗(yàn)證一個(gè)模型涉及三個(gè)步驟:
Model.clean_fields()
Model.clean()
Model.validate_unique()
當(dāng)你調(diào)用模型的full_clean()
方法時(shí),這三個(gè)方法都將執(zhí)行。
當(dāng)你使用ModelForm
時(shí),is_valid()
將為表單中的所有字段執(zhí)行這些驗(yàn)證。更多信息參見ModelForm
文檔。 如果你計(jì)劃自己處理驗(yàn)證出現(xiàn)的錯(cuò)誤,或者你已經(jīng)將需要驗(yàn)證的字段從ModelForm
中去除掉,你只需調(diào)用模型的full_clean()
方法。
Model.full_clean(exclude=None, validate_unique=True)
該方法按順序調(diào)用Model.clean_fields()
、Model.clean()
和Model.validate_unique()
(如果validate_unique
為True
),并引發(fā)一個(gè)ValidationError
,該異常的message_dict
屬性包含三個(gè)步驟的所有錯(cuò)誤。
可選的exclude
參數(shù)用來提供一個(gè)可以從驗(yàn)證和清除中排除的字段名稱的列表。ModelForm
使用這個(gè)參數(shù)來排除表單中沒有出現(xiàn)的字段,使它們不需要驗(yàn)證,因?yàn)橛脩魺o法修正這些字段的錯(cuò)誤。
注意,當(dāng)你調(diào)用模型的save()
方法時(shí),full_clean()
不會(huì) 自動(dòng)調(diào)用。如果你想一步就可以為你手工創(chuàng)建的模型運(yùn)行驗(yàn)證,你需要手工調(diào)用它。例如:
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()
第一步執(zhí)行的是驗(yàn)證每個(gè)字段。
Model.clean_fields(exclude=None)
這個(gè)方法將驗(yàn)證模型的所有字段。可選的exclude
參數(shù)讓你提供一個(gè)字段名稱列表來從驗(yàn)證中排除。如果有字段驗(yàn)證失敗,它將引發(fā)一個(gè)ValidationError
。
full_clean()
第二步執(zhí)行的是調(diào)用Model.clean()
。如要實(shí)現(xiàn)模型自定義的驗(yàn)證,應(yīng)該覆蓋這個(gè)方法。
Model.clean()
應(yīng)該用這個(gè)方法來提供自定義的模型驗(yàn)證,以及修改模型的屬性。例如,你可以使用它來給一個(gè)字段自動(dòng)提供值,或者用于多個(gè)字段需要一起驗(yàn)證的情形:
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()
然而請(qǐng)注意,和Model.full_clean()
類似,調(diào)用模型的save()
方法時(shí)不會(huì)引起clean()
方法的調(diào)用。
在上面的示例中,Model.clean()
引發(fā)的ValidationError
異常通過一個(gè)字符串實(shí)例化,所以它將被保存在一個(gè)特殊的錯(cuò)誤字典鍵NON_FIELD_ERRORS
中。這個(gè)鍵用于整個(gè)模型出現(xiàn)的錯(cuò)誤而不是一個(gè)特定字段出現(xiàn)的錯(cuò)誤:
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]
若要引發(fā)一個(gè)特定字段的異常,可以使用一個(gè)字典實(shí)例化ValidationError
,其中字典的鍵為字段的名稱。我們可以更新前面的例子,只引發(fā)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()
類似,只是驗(yàn)證的是模型的所有唯一性約束而不是單個(gè)字段的值??蛇x的exclude
參數(shù)允許你提供一個(gè)字段名稱的列表來從驗(yàn)證中排除。如果有字段驗(yàn)證失敗,將引發(fā)一個(gè) ValidationError
。
注意,如果你提供一個(gè)exclude
參數(shù)給validate_unique()
,任何涉及到其中一個(gè)字段的unique_together
約束將不檢查。
將一個(gè)對(duì)象保存到數(shù)據(jù)庫(kù),需要調(diào)用 save()
方法:
Model.save([force_insert=False, force_update=False, using=DEFAULT_DB_ALIAS, update_fields=None])
如果你想要自定義保存的動(dòng)作,你可以重寫 save()
方法。請(qǐng)看 重寫預(yù)定義的模型方法 了解更多細(xì)節(jié)。
模型保存過程還有一些細(xì)節(jié)的地方要注意;請(qǐng)看下面的章節(jié)。
如果模型具有一個(gè)AutoField
—— 一個(gè)自增的主鍵 —— 那么該自增的值將在第一次調(diào)用對(duì)象的save()
時(shí)計(jì)算并保存:
>>> 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.
在調(diào)用save()
之前無法知道ID 的值,因?yàn)檫@個(gè)值是通過數(shù)據(jù)庫(kù)而不是Django 計(jì)算。
為了方便,默認(rèn)情況下每個(gè)模型都有一個(gè)AutoField
叫做id
,除非你顯式指定模型某個(gè)字段的 primary_key=True
。更多細(xì)節(jié)參見AutoField
的文檔。
Model.pk
無論你是自己定義還是讓Django 為你提供一個(gè)主鍵字段, 每個(gè)模型都將具有一個(gè)屬性叫做pk
。它的行為類似模型的一個(gè)普通屬性,但實(shí)際上是模型主鍵字段屬性的別名。你可以讀取并設(shè)置它的值,就和其它屬性一樣,它會(huì)更新模型中正確的值。
如果模型具有一個(gè)AutoField
,但是你想在保存時(shí)顯式定義一個(gè)新的對(duì)象ID
,你只需要在保存之前顯式指定它而不用依賴ID
自動(dòng)分配的值:
>>> b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b3.id # Returns 3.
>>> b3.save()
>>> b3.id # Returns 3.
如果你手工賦值一個(gè)自增主鍵的值,請(qǐng)確保不要使用一個(gè)已經(jīng)存在的主鍵值!如果你使用數(shù)據(jù)庫(kù)中已經(jīng)存在的主鍵值創(chuàng)建一個(gè)新的對(duì)象,Django 將假設(shè)你正在修改這個(gè)已存在的記錄而不是創(chuàng)建一個(gè)新的記錄。
接著上面的'Cheddar Talk
' 博客示例,下面這個(gè)例子將覆蓋數(shù)據(jù)庫(kù)中之前的記錄:
b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.')
b4.save() # Overrides the previous blog with ID=3!
出現(xiàn)這種情況的原因,請(qǐng)參見下面的Django 如何知道是UPDATE 還是INSERT。
顯式指定自增主鍵的值對(duì)于批量保存對(duì)象最有用,但你必須有信心不會(huì)有主鍵沖突。
當(dāng)你保存一個(gè)對(duì)象時(shí),Django 執(zhí)行以下步驟:
1. 發(fā)出一個(gè)pre-save
信號(hào)。 發(fā)送一個(gè)django.db.models.signals.pre_save
信號(hào),以允許監(jiān)聽該信號(hào)的函數(shù)完成一些自定義的動(dòng)作。
2. 預(yù)處理數(shù)據(jù)。 如果需要,對(duì)對(duì)象的每個(gè)字段進(jìn)行自動(dòng)轉(zhuǎn)換。
大部分字段不需要預(yù)處理 —— 字段的數(shù)據(jù)將保持原樣。預(yù)處理只用于具有特殊行為的字段。例如,如果你的模型具有一個(gè)auto_now=True
的DateField
,那么預(yù)處理階段將修改對(duì)象中的數(shù)據(jù)以確保該日期字段包含當(dāng)前的時(shí)間戳。(我們的文檔還沒有所有具有這種“特殊行為”字段的一個(gè)列表。)
3. 準(zhǔn)備數(shù)據(jù)庫(kù)數(shù)據(jù)。 要求每個(gè)字段提供的當(dāng)前值是能夠?qū)懭氲綌?shù)據(jù)庫(kù)中的類型。
大部分字段不需要數(shù)據(jù)準(zhǔn)備。簡(jiǎn)單的數(shù)據(jù)類型,例如整數(shù)和字符串,是可以直接寫入的Python 對(duì)象。但是,復(fù)雜的數(shù)據(jù)類型通常需要一些改動(dòng)。
例如,DateField
字段使用Python 的 datetime
對(duì)象來保存數(shù)據(jù)。數(shù)據(jù)庫(kù)保存的不是datetime
對(duì)象,所以該字段的值必須轉(zhuǎn)換成ISO兼容的日期字符串才能插入到數(shù)據(jù)庫(kù)中。
4. 插入數(shù)據(jù)到數(shù)據(jù)庫(kù)中。 將預(yù)處理過、準(zhǔn)備好的數(shù)據(jù)組織成一個(gè)SQL 語(yǔ)句用于插入數(shù)據(jù)庫(kù)。
5. 發(fā)出一個(gè)post-save 信號(hào)。 發(fā)送一個(gè)django.db.models.signals.post_save
信號(hào),以允許監(jiān)聽聽信號(hào)的函數(shù)完成一些自定義的動(dòng)作。
你可能已經(jīng)注意到Django 數(shù)據(jù)庫(kù)對(duì)象使用同一個(gè)save()
方法來創(chuàng)建和改變對(duì)象。Django 對(duì)INSERT
和UPDATE
SQL 語(yǔ)句的使用進(jìn)行抽象。當(dāng)你調(diào)用save()
時(shí),Django 使用下面的算法:
True
的值(例如,非None
值或非空字符串),Django 將執(zhí)行UPDATE
。UPDATE
沒有更新任何記錄,Django 將執(zhí)行INSERT
。現(xiàn)在應(yīng)該明白了,當(dāng)保存一個(gè)新的對(duì)象時(shí),如果不能保證主鍵的值沒有使用,你應(yīng)該注意不要顯式指定主鍵值。關(guān)于這個(gè)細(xì)微差別的更多信息,參見上文的顯示指定主鍵的值 和下文的強(qiáng)制使用INSERT
或UPDATE
。
在Django 1.5 和更早的版本中,在設(shè)置主鍵的值時(shí),Django 會(huì)作一個(gè) SELECT
。如果SELECT
找到一行,那么Django 執(zhí)行UPDATE
,否則執(zhí)行INSERT
。舊的算法導(dǎo)致UPDATE
情況下多一次查詢。有極少數(shù)的情況,數(shù)據(jù)庫(kù)不會(huì)報(bào)告有一行被更新,即使數(shù)據(jù)庫(kù)包含該對(duì)象的主鍵值。有個(gè)例子是PostgreSQL 的ON UPDATE
觸發(fā)器,它返回NULL。在這些情況下,可能要通過將select_on_save
選項(xiàng)設(shè)置為True
以啟用舊的算法。
在一些很少見的場(chǎng)景中,需要強(qiáng)制save()
方法執(zhí)行SQL 的 INSERT
而不能執(zhí)行UPDATE
。或者相反:更新一行而不是插入一個(gè)新行。在這些情況下,你可以傳遞force_insert=True
或 force_update=True
參數(shù)給save()
方法。顯然,兩個(gè)參數(shù)都傳遞是錯(cuò)誤的:你不可能同時(shí)插入和更新!
你應(yīng)該極少需要使用這些參數(shù)。Django 幾乎始終會(huì)完成正確的事情,覆蓋它將導(dǎo)致錯(cuò)誤難以跟蹤。這個(gè)功能只用于高級(jí)用法。
使用update_fields
將強(qiáng)制使用類似force_update
的更新操作。
有時(shí)候你需要在一個(gè)字段上執(zhí)行簡(jiǎn)單的算法操作,例如增加或者減少當(dāng)前值。實(shí)現(xiàn)這點(diǎn)的簡(jiǎn)單方法是像下面這樣:
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold += 1
>>> product.save()
如果從數(shù)據(jù)庫(kù)中讀取的舊的number_sold
值為10,那么寫回到數(shù)據(jù)庫(kù)中的值將為11。
通過將更新基于原始字段的值而不是顯式賦予一個(gè)新值,這個(gè)過程可以避免競(jìng)態(tài)條件而且更快。Django 提供F 表達(dá)式
用于這種類型的相對(duì)更新。利用F 表達(dá)式
,前面的示例可以表示成:
>>> from django.db.models import F
>>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
>>> product.number_sold = F('number_sold') + 1
>>> product.save()
更多細(xì)節(jié),請(qǐng)參見F 表達(dá)式
和它們在更新查詢中的用法。
如果傳遞給save()
的update_fields
關(guān)鍵字參數(shù)一個(gè)字段名稱列表,那么將只有該列表中的字段會(huì)被更新。如果你想更新對(duì)象的一個(gè)或幾個(gè)字段,這可能是你想要的。不讓模型的所有字段都更新將會(huì)帶來一些輕微的性能提升。例如:
product.name = 'Name changed again'
product.save(update_fields=['name'])
update_fields
參數(shù)可以是任何包含字符串的可迭代對(duì)象??盏?code>update_fields 可迭代對(duì)象將會(huì)忽略保存。如果為None
值,將執(zhí)行所有字段上的更新。
指定update_fields
將強(qiáng)制使用更新操作。
當(dāng)保存通過延遲模型加載(only()
或defer()
)進(jìn)行訪問的模型時(shí),只有從數(shù)據(jù)庫(kù)中加載的字段才會(huì)得到更新。這種情況下,有個(gè)自動(dòng)的update_fields
。如果你賦值或者改變延遲字段的值,該字段將會(huì)添加到更新的字段中。
Model.delete([using=DEFAULT_DB_ALIAS])
發(fā)出一個(gè)SQL DELETE
操作。它只在數(shù)據(jù)庫(kù)中刪除這個(gè)對(duì)象;其Python 實(shí)例仍將存在并持有各個(gè)字段的數(shù)據(jù)。
更多細(xì)節(jié),包括如何批量刪除對(duì)象,請(qǐng)參見刪除對(duì)象。
如果你想自定義刪除的行為,你可以覆蓋delete()
方法。詳見覆蓋預(yù)定義的模型方法。
當(dāng)你pickle
一個(gè)模型時(shí),它的當(dāng)前狀態(tài)是pickled。當(dāng)你unpickle 它時(shí),它將包含pickle 時(shí)模型的實(shí)例,而不是數(shù)據(jù)庫(kù)中的當(dāng)前數(shù)據(jù)。
你不可以在不同版本之間共享pickles
模型的Pickles 只對(duì)于產(chǎn)生它們的Django 版本有效。如果你使用Django 版本N pickle,不能保證Django 版本N+1 可以讀取這個(gè)pickle。Pickles 不應(yīng)該作為長(zhǎng)期的歸檔策略。
New in Django 1.8.
因?yàn)閜ickle 兼容性的錯(cuò)誤很難診斷例如一個(gè)悄無聲息損壞的對(duì)象,當(dāng)你unpickle 模型使用的Django 版本與pickle 時(shí)的不同將引發(fā)一個(gè)
RuntimeWarning
。
有幾個(gè)實(shí)例方法具有特殊的目的。
注
在Python 3 上,因?yàn)樗械淖侄味荚徽J(rèn)為是Unicode,只需使用
__str__()
方法(__unicode__()
方法被廢棄)。如果你想與Python 2 兼容,你可以使用python_2_unicode_compatible()
裝飾你的模型類。
Model.__unicode__()
__unicode__()
方法在每當(dāng)你對(duì)一個(gè)對(duì)象調(diào)用unicode() 時(shí)調(diào)用。Django 在許多地方都使用unicode(obj)
(或者相關(guān)的函數(shù) str(obj)
)。最明顯的是在Django 的Admin 站點(diǎn)顯示一個(gè)對(duì)象和在模板中插入對(duì)象的值的時(shí)候。所以,你應(yīng)該始終讓__unicode__()
方法返回模型的一個(gè)友好的、人類可讀的形式。
例如:
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 將自動(dòng)提供一個(gè) __str__()
,它調(diào)用__unicode__()
并轉(zhuǎn)換結(jié)果為一個(gè)UTF-8 編碼的字符串。下面是一個(gè)建議的開發(fā)實(shí)踐:只定義__unicode__()
并讓Django 在需要時(shí)負(fù)責(zé)字符串的轉(zhuǎn)換。
Model.__str__()
__str__()
方法在每當(dāng)你對(duì)一個(gè)對(duì)象調(diào)用str()
時(shí)調(diào)用。在Python 3 中,Django 在許多地方使用str(obj)
。 最明顯的是在Django 的Admin 站點(diǎn)顯示一個(gè)對(duì)象和在模板中插入對(duì)象的值的時(shí)候。 所以,你應(yīng)該始終讓__str__()
方法返回模型的一個(gè)友好的、人類可讀的形式。
例如:
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 內(nèi)部對(duì)__str__
的直接使用主要在隨處可見的模型的repr()
輸出中(例如,調(diào)試時(shí)的輸出)。如果已經(jīng)有合適的__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))
Model.__eq__()
定義這個(gè)方法是為了讓具有相同主鍵的相同實(shí)類的實(shí)例是相等的。對(duì)于代理模型,實(shí)類是模型第一個(gè)非代理父類;對(duì)于其它模型,它的實(shí)類就是模型類自己。
例如:
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:
在之前的版本中,只有類和主鍵都完全相同的實(shí)例才是相等的。
Model.__hash__()
__hash__
方法基于實(shí)例主鍵的值。它等同于hash(obj.pk)。如果實(shí)例的主鍵還沒有值,將引發(fā)一個(gè)TypeError
(否則,__hash__
方法在實(shí)例保存的前后將返回不同的值,而改變一個(gè)實(shí)例的__hash__
值在Python 中是禁止的)。
Changed in Django 1.7:
在之前的版本中,主鍵沒有值的實(shí)例是可以哈希的。
Model.get_absolute_url()
get_absolute_url()
方法告訴Django 如何計(jì)算對(duì)象的標(biāo)準(zhǔn)URL。對(duì)于調(diào)用者,該方法返回的字符串應(yīng)該可以通過HTTP 引用到這個(gè)對(duì)象。
例如:
def get_absolute_url(self):
return "/people/%i/" % self.id
(雖然這段代碼正確又簡(jiǎn)單,這并不是編寫這個(gè)方法可移植性最好的方式。通常使用reverse()
函數(shù)是最好的方式。)
例如:
def get_absolute_url(self):
from django.core.urlresolvers import reverse
return reverse('people.views.details', args=[str(self.id)])
Django 使用get_absolute_url()
的一個(gè)地方是在Admin 應(yīng)用中。如果對(duì)象定義該方法,對(duì)象編輯頁(yè)面將具有一個(gè)“View on site”鏈接,可以將你直接導(dǎo)入由get_absolute_url()
提供的對(duì)象公開視圖。
類似地,Django 的另外一些小功能,例如syndication feed 框架 也使用get_absolute_url()
。 如果模型的每個(gè)實(shí)例都具有一個(gè)唯一的URL 是合理的,你應(yīng)該定義get_absolute_url()
。
警告
你應(yīng)該避免從沒有驗(yàn)證過的用戶輸入構(gòu)建URL,以減少有害的鏈接和重定向:
def get_absolute_url(self):
return '/%s/' % self.name
如果
self.name
為'/example.com
',將返回 '//example.com/
', 而它是一個(gè)合法的相對(duì)URL而不是期望的'/%2Fexample.com/
'。
在模板中使用get_absolute_url()
而不是硬編碼對(duì)象的URL 是很好的實(shí)踐。例如,下面的模板代碼很糟糕:
<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a>
下面的模板代碼要好多了:
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>
如果你改變了對(duì)象的URL 結(jié)構(gòu),即使是一些簡(jiǎn)單的拼寫錯(cuò)誤,你不需要檢查每個(gè)可能創(chuàng)建該URL 的地方。在get_absolute_url()
中定義一次,然后在其它代碼調(diào)用它。
注
get_absolute_url()
返回的字符串必須只包含ASCII 字符(URI 規(guī)范RFC 2396 的要求),并且如需要必須要URL-encoded。代碼和模板中對(duì)
get_absolute_url()
的調(diào)用應(yīng)該可以直接使用而不用做進(jìn)一步處理。你可能想使用django.utils.encoding.iri_to_uri()
函數(shù)來幫助你解決這個(gè)問題,如果你正在使用ASCII 范圍之外的Unicode 字符串。
除了save()
、delete()
之外,模型的對(duì)象還可能具有以下一些方法:
Model.get_FOO_display()
對(duì)于每個(gè)具有choices
的字段,每個(gè)對(duì)象將具有一個(gè)get_FOO_display()
方法,其中FOO
為該字段的名稱。這個(gè)方法返回該字段對(duì)“人類可讀”的值。
例如:
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
沒有設(shè)置 null=True
,那么該對(duì)象將具有get_next_by_FOO()
和get_previous_by_FOO()
方法,其中FOO
為字段的名稱。它根據(jù)日期字段返回下一個(gè)和上一個(gè)對(duì)象,并適時(shí)引發(fā)一個(gè)DoesNotExist
。
這兩個(gè)方法都將使用模型默認(rèn)的管理器來執(zhí)行查詢。如果你需要使用自定義的管理器或者你需要自定義的篩選,這個(gè)兩個(gè)方法還接受可選的參數(shù),它們應(yīng)該用字段查詢 中提到的格式。
注意,對(duì)于完全相同的日期,這些方法還將利用主鍵來進(jìn)行查找。這保證不會(huì)有記錄遺漏或重復(fù)。這還意味著你不可以在未保存的對(duì)象上使用這些方法。
exception Model.DoesNotExist
ORM 在好幾個(gè)地方會(huì)引發(fā)這個(gè)異常,例如QuerySet.get()
根據(jù)給定的查詢參數(shù)找不到對(duì)象時(shí)。
Django 為每個(gè)類提供一個(gè)DoesNotExist
異常屬性是為了區(qū)別找不到的對(duì)象所屬的類,并讓你可以利用try/except
捕獲一個(gè)特定模型的類。這個(gè)異常是django.core.exceptions.ObjectDoesNotExist
的子類。
譯者:Django 文檔協(xié)作翻譯小組,原文:Instance methods。
本文以 CC BY-NC-SA 3.0 協(xié)議發(fā)布,轉(zhuǎn)載請(qǐng)保留作者署名和文章出處。
Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群:467338606。