鍍金池/ 教程/ Python/ 模型實(shí)例參考
點(diǎn)擊劫持保護(hù)
安全問題歸檔
Model 類參考
將遺留數(shù)據(jù)庫(kù)整合到Django
關(guān)聯(lián)對(duì)象參考
內(nèi)建基于類的視圖的API
聚合
Django 中的用戶認(rèn)證
django.contrib.humanize
Django管理文檔生成器
分頁(yè)
使用Django輸出CSV
加密簽名
文件儲(chǔ)存API
安全
Django中的測(cè)試
國(guó)際化和本地化
為Django編寫首個(gè)補(bǔ)丁
條件表達(dá)式
日志
模型元選項(xiàng)
部署靜態(tài)文件
執(zhí)行查詢
使用Django認(rèn)證系統(tǒng)
基于類的視圖
中間件
編寫自定義的django-admin命令
Django 的設(shè)置
格式本地化
數(shù)據(jù)庫(kù)訪問優(yōu)化
錯(cuò)誤報(bào)告
基于類的內(nèi)建通用視圖
編寫自定義存儲(chǔ)系統(tǒng)
編寫你的第一個(gè) Django 程序 第3部分
編寫數(shù)據(jù)庫(kù)遷移
使用表單
編寫你的第一個(gè) Django 程序 第2部分
編寫你的第一個(gè) Django 程序 第1部分
如何使用會(huì)話
系統(tǒng)檢查框架
新手入門
信號(hào)
編寫視圖
如何使用WSGI 部署
編寫你的第一個(gè)Django應(yīng)用,第6部分
常見的網(wǎng)站應(yīng)用工具
Widgets
內(nèi)建的視圖
模型實(shí)例參考
視圖層
Django中的密碼管理
高級(jí)教程:如何編寫可重用的應(yīng)用
國(guó)際化和本地化
"本地特色"附加功能
TemplateResponse 和 SimpleTemplateResponse
模式編輯器
文件上傳
快速安裝指南
部署 Django
表單 API
表單素材 ( <code>Media</code> 類)
管理文件
其它核心功能
查找 API 參考
表單
Admin
數(shù)據(jù)庫(kù)函數(shù)
自定義查找
使用基于類的視圖處理表單
管理操作
開發(fā)過程
編寫你的第一個(gè)Django應(yīng)用,第5部分
進(jìn)行原始的sql查詢
模型層
多數(shù)據(jù)庫(kù)
編寫你的第一個(gè) Django 程序 第4部分
Django安全
Django 初探
Django異常
重定向應(yīng)用
按需內(nèi)容處理
管理器
視圖裝飾器
驗(yàn)證器
使用Django輸出PDF
File對(duì)象
Django 的快捷函數(shù)
基于類的通用視圖 —— 索引
為模型提供初始數(shù)據(jù)
模板層
URL調(diào)度器
中間件
模型

模型實(shí)例參考

該文檔詳細(xì)描述模型 的API。它建立在模型 和執(zhí)行查詢 的資料之上, 所以在閱讀這篇文檔之前,你可能會(huì)想要先閱讀并理解那兩篇文檔。

我們將用執(zhí)行查詢中所展現(xiàn)的 博客應(yīng)用模型 來貫穿這篇參考文獻(xiàn)。

創(chuàng)建對(duì)象

要?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_namesvalues 的順序相同,所以可以使用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 屬性中的addingdb 標(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)用。

從數(shù)據(jù)庫(kù)更新對(duì)象

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)證對(duì)象

驗(yàn)證一個(gè)模型涉及三個(gè)步驟:

  1. 驗(yàn)證模型的字段 —— Model.clean_fields()
  2. 驗(yàn)證模型的完整性 —— Model.clean()
  3. 驗(yàn)證模型的唯一性 —— 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_uniqueTrue),并引發(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 約束將不檢查。

對(duì)象保存

將一個(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 的文檔。

pk 屬性

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)你保存時(shí),發(fā)生了什么?

當(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=TrueDateField,那么預(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)作。

Django 如何知道是UPDATE 還是INSERT

你可能已經(jīng)注意到Django 數(shù)據(jù)庫(kù)對(duì)象使用同一個(gè)save() 方法來創(chuàng)建和改變對(duì)象。Django 對(duì)INSERTUPDATE SQL 語(yǔ)句的使用進(jìn)行抽象。當(dāng)你調(diào)用save() 時(shí),Django 使用下面的算法:

  • 如果對(duì)象的主鍵屬性為一個(gè)求值為True 的值(例如,非None 值或非空字符串),Django 將執(zhí)行UPDATE。
  • 如果對(duì)象的主鍵屬性沒有設(shè)置或者UPDATE 沒有更新任何記錄,Django 將執(zhí)行INSERT

現(xiàn)在應(yīng)該明白了,當(dāng)保存一個(gè)新的對(duì)象時(shí),如果不能保證主鍵的值沒有使用,你應(yīng)該注意不要顯式指定主鍵值。關(guān)于這個(gè)細(xì)微差別的更多信息,參見上文的顯示指定主鍵的值 和下文的強(qiáng)制使用INSERTUPDATE。

在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 以啟用舊的算法。

強(qiáng)制使用INSERT 或UPDATE

在一些很少見的場(chǎng)景中,需要強(qiáng)制save() 方法執(zhí)行SQL 的 INSERT 而不能執(zhí)行UPDATE。或者相反:更新一行而不是插入一個(gè)新行。在這些情況下,你可以傳遞force_insert=Trueforce_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ì)添加到更新的字段中。

刪除對(duì)象

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ù)定義的模型方法。

Pickling 對(duì)象

當(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。

其它的模型實(shí)例方法

有幾個(gè)實(shí)例方法具有特殊的目的。

在Python 3 上,因?yàn)樗械淖侄味荚徽J(rèn)為是Unicode,只需使用__str__() 方法(__unicode__() 方法被廢棄)。如果你想與Python 2 兼容,你可以使用python_2_unicode_compatible() 裝飾你的模型類。

__unicode__

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)換。

__str__

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))

__eq__

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í)例才是相等的。

__hash__

Model.__hash__()

__hash__ 方法基于實(shí)例主鍵的值。它等同于hash(obj.pk)。如果實(shí)例的主鍵還沒有值,將引發(fā)一個(gè)TypeError(否則,__hash__ 方法在實(shí)例保存的前后將返回不同的值,而改變一個(gè)實(shí)例的__hash__ 值在Python 中是禁止的)。

Changed in Django 1.7:

在之前的版本中,主鍵沒有值的實(shí)例是可以哈希的。

get_absolute_url

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 字符串。

額外的實(shí)例方法

除了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)

如果DateFieldDateTimeField沒有設(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ì)象上使用這些方法。

其它屬性

DoesNotExist

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。