在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

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

管理器

class Manager

管理器是一個接口,數(shù)據(jù)庫查詢操作通過它提供給django的模型。django應(yīng)用的每個模型至少擁有一個 管理器。

管理器類的工作方式在 執(zhí)行查詢文檔中闡述,而這篇文檔涉及了自定義管理器行為的模型選項。

管理器的名字

通常,django為每個模型類添加一個名為objects的管理器。然而,如果你想將objects用于字段名稱,或者你想使用其它名稱而不是objects訪問管理器,你可以在每個模型類中重命名它。在模型中定義一個值為models.Manager()的屬性,來重命名管理器。例如:

from django.db import models

class Person(models.Model):
    #...
    people = models.Manager()

使用例子中的模型, Person.objects會拋出AttributeError異常,而Person.people.all()會返回一個包含所有Person對象的列表。

自定義管理器

在一個特定的模型中,你可以通過繼承管理器類來構(gòu)建一個自定義的管理器,以及實例化你的自定義管理器。

你有兩個原因可能會自己定義管理器:向器類中添加額外的方法,或者修改管理器最初返回的查詢集。

添加額外的管理器方法

為你的模型添加表級(table-level)功能時,采用添加額外的管理器方法是更好的處理方式。如果要添加行級功能--就是說該功能只對某個模型的實例對象起作用。在這種情況下,使用 模型方法 比使用自定義的管理器方法要更好。)

自定義的管理器 方法可以返回你想要的任何數(shù)據(jù),而不只是查詢集。

例如,下面這個自定義的 管理器提供了一個 with_counts() 方法,它返回所有 OpinionPoll 對象的列表,而且列表中的每個對象都多了一個名為 num_responses的屬性,這個屬性保存一個聚合查詢(COUNT*)的結(jié)果:

from django.db import models

class PollManager(models.Manager):
    def with_counts(self):
        from django.db import connection
        cursor = connection.cursor()
        cursor.execute("""
            SELECT p.id, p.question, p.poll_date, COUNT(*)
            FROM polls_opinionpoll p, polls_response r
            WHERE p.id = r.poll_id
            GROUP BY p.id, p.question, p.poll_date
            ORDER BY p.poll_date DESC""")
        result_list = []
        for row in cursor.fetchall():
            p = self.model(id=row[0], question=row[1], poll_date=row[2])
            p.num_responses = row[3]
            result_list.append(p)
        return result_list

class OpinionPoll(models.Model):
    question = models.CharField(max_length=200)
    poll_date = models.DateField()
    objects = PollManager()

class Response(models.Model):
    poll = models.ForeignKey(OpinionPoll)
    person_name = models.CharField(max_length=50)
    response = models.TextField()

在這個例子中,你已經(jīng)可以使用 OpinionPoll.objects.with_counts() 得到所有含有 num_responses屬性的 OpinionPoll對象。

這個例子要注意的一點是: 管理器方法可以訪問 self.model來得到它所用到的模型類。

修改管理器初始的查詢集

管理器自帶的 查詢集返回系統(tǒng)中所有的對象。例如,使用下面這個模型:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

... Book.objects.all() 語句將返回數(shù)據(jù)庫中所有的 Book 對象。

你可以通過重寫 Manager.get_queryset() 的方法來覆蓋 管理器自帶的 查詢集。get_queryset() 會根據(jù)你所需要的屬性返回 查詢集。

例如,下面的模型有兩個 管理器,一個返回所有的對象,另一個則只返回作者是 Roald Dahl 的對象:

# First, define the Manager subclass.
class DahlBookManager(models.Manager):
    def get_queryset(self):
        return super(DahlBookManager, self).get_queryset().filter(author='Roald Dahl')

# Then hook it into the Book model explicitly.
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

    objects = models.Manager() # The default manager.
    dahl_objects = DahlBookManager() # The Dahl-specific manager.

在這個簡單的例子中,Book.objects.all()將返回數(shù)據(jù)庫中所有的圖書。而 Book.dahl_objects.all() 只返回作者是 Roald Dahl 的圖書。

由于 get_queryset() 返回的是一個 查詢集 對象,所以你仍可以對它使用 filter(), exclude()和其他 查詢集的方法。所以下面這些例子都是可用的:

Book.dahl_objects.all()
Book.dahl_objects.filter(title='Matilda')
Book.dahl_objects.count()

這個例子還展示了另外一個很有意思的技巧:在同一個模型中使用多個管理器。你可以隨你所意在一個模型里面添加多個 Manager() 實例。下面就用很簡單的方法,給模型添加通用過濾器:

例如:

class AuthorManager(models.Manager):
    def get_queryset(self):
        return super(AuthorManager, self).get_queryset().filter(role='A')

class EditorManager(models.Manager):
    def get_queryset(self):
        return super(EditorManager, self).get_queryset().filter(role='E')

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    role = models.CharField(max_length=1, choices=(('A', _('Author')), ('E', _('Editor'))))
    people = models.Manager()
    authors = AuthorManager()
    editors = EditorManager()

在這個例子中,你使用 Person.authors.all(), Person.editors.all(),以及 Person.people.all(), 都會得到和名稱相符的結(jié)果。

默認(rèn)管理器

如果你使用了自定義 管理器對象,要注意 Django 中的第一個 管理器 (按照模型中出現(xiàn)的順序而定) 擁有特殊的地位。Django 會將模型中定義的管理器解釋為默認(rèn)的 管理器,并且 Django 中的一部分應(yīng)用(包括數(shù)據(jù)備份)會使用默認(rèn)的管理器,除了前面那個模型。因此,要決定默認(rèn)的管理器時,要小心謹(jǐn)慎,仔細(xì)考量,這樣才能避免重寫 get_queryset() 導(dǎo)致無法正確地獲得數(shù)據(jù)。

使用管理器訪問關(guān)聯(lián)對象

默認(rèn)情況下,在訪問相關(guān)對象時(例如choice.poll),Django 并不使用相關(guān)對象的默認(rèn)管理器,而是使用一個"樸素"管理器類的實例來訪問。這是因為 Django 要能從關(guān)聯(lián)對象中獲得數(shù)據(jù),但這些數(shù)據(jù)有可能被默認(rèn)管理器過濾掉,或是無法進(jìn)行訪問。

如果普通的樸素管理器類(django.db.models.Manager)并不適用于你的應(yīng)用,那么你可以通過在管理器類中設(shè)置 use_for_related_fields ,強(qiáng)制 Django 在你的模型中使用默認(rèn)的管理器。這部分內(nèi)容在 下面有 詳細(xì)介紹。

調(diào)用自定義的查詢集

雖然大多數(shù)標(biāo)準(zhǔn)查詢集的方法可以從管理器中直接訪問到,但是這是一個例子,訪問了定義在自定義 查詢集上的額外方法,如果你也在管理器上面實現(xiàn)了它們:

class PersonQuerySet(models.QuerySet):
    def authors(self):
        return self.filter(role='A')

    def editors(self):
        return self.filter(role='E')

class PersonManager(models.Manager):
    def get_queryset(self):
        return PersonQuerySet(self.model, using=self._db)

    def authors(self):
        return self.get_queryset().authors()

    def editors(self):
        return self.get_queryset().editors()

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    role = models.CharField(max_length=1, choices=(('A', _('Author')), ('E', _('Editor'))))
    people = PersonManager()

這個例子展示了如何直接從管理器 Person.people調(diào)用authors() 和 editors()。

創(chuàng)建管理器

django 1.7 中新增

對于上面的例子,同一個方法需要在查詢集 和 管理器上創(chuàng)建兩份副本,作為替代,QuerySet.as_manager()可以創(chuàng)建一個管理器的實例,它擁有自定義查詢集的方法:

class Person(models.Model):
    ...
    people = PersonQuerySet.as_manager()

通過QuerySet.as_manager()創(chuàng)建的管理器 實例,實際上等價于上面例子中的PersonManager。

并不是每個查詢集的方法都在管理器層面上有意義。比如 QuerySet.delete(),我們有意防止它復(fù)制到管理器 中。

方法按照以下規(guī)則進(jìn)行復(fù)制:

  • 公共方法默認(rèn)被復(fù)制。
  • 私有方法(前面帶一個下劃線)默認(rèn)不被復(fù)制。
  • 帶queryset_only 屬性,并且值為False的方法總是被復(fù)制。
  • 帶 queryset_only 屬性,并且值為True 的方法不會被復(fù)制。

例如:

class CustomQuerySet(models.QuerySet):
    # Available on both Manager and QuerySet.
    def public_method(self):
        return

    # Available only on QuerySet.
    def _private_method(self):
        return

    # Available only on QuerySet.
    def opted_out_public_method(self):
        return
    opted_out_public_method.queryset_only = True

    # Available on both Manager and QuerySet.
    def _opted_in_private_method(self):
        return
    _opted_in_private_method.queryset_only = False

from_queryset

classmethod from_queryset(queryset_class)

在進(jìn)一步的使用中,你可能想創(chuàng)建一個自定義管理器和一個自定義查詢集。你可以調(diào)用Manager.from_queryset(),它會返回管理器的一個子類,帶有自定義查詢集所有方法的副本:

class BaseManager(models.Manager):
    def manager_only_method(self):
        return

class CustomQuerySet(models.QuerySet):
    def manager_and_queryset_method(self):
        return

class MyModel(models.Model):
    objects = BaseManager.from_queryset(CustomQueryset)()

你也可以在一個變量中儲存生成的類:

CustomManager = BaseManager.from_queryset(CustomQueryset)

class MyModel(models.Model):
    objects = CustomManager()

自定義管理器和模型繼承

類繼承和模型管理器兩者之間配合得并不是很好。 管理器一般只對其定義所在的類起作用,在子類中對其繼承絕對不是一個好主意。 而且,因為第一個 管理器會被 Djange 聲明為默認(rèn)的管理器,所以對默認(rèn)的管理器 進(jìn)行控制是非常必要的。下面就是 Django 如何處理自定義管理器和模型繼承(model inheritance)的:

  • 定義在非抽象基類中的管理器是 不會 被子類繼承的。如果你想從一個非抽象基類中重用管理器,只能在子類中重定義管理器。 這是因為這種管理器與定義它的模型 綁定得非常緊密,所以繼承它們經(jīng)常會導(dǎo)致異常的結(jié)果(特別是默認(rèn)管理器運(yùn)行的時候)。 因此,它們不應(yīng)繼承給子類。
  • 定義在抽象基類中的管理器總是被子類繼續(xù)的,是按 Python 的命名解析順序解析的(首先是子類中的命名覆蓋所有的,然后是第一個父類的,以此類推)。 抽象類用來提取子類中的公共信息和行為,定義公共管理器也是公共信息的一部分。
  • 如果類當(dāng)中顯示定義了默認(rèn)管理器,Django 就會以此做為默認(rèn)管理器;否則就會從第一個抽象基類中繼承默認(rèn)管理器; 如果沒有顯式聲明默認(rèn)管理器,那么 Django 就會自動添加默認(rèn)管理器。

如果你想在一組模型上安裝一系列自定義管理器,上面提到的這些規(guī)則就已經(jīng)為你的實現(xiàn)提供了必要的靈活性。你可以繼承一個抽象基類,但仍要自定義默認(rèn)的管理器。例如,假設(shè)你的基類是這樣的:

class AbstractBase(models.Model):
    # ...
    objects = CustomManager()

    class Meta:
        abstract = True

如果你在基類中沒有定義管理器,直接使用上面的代碼,默認(rèn)管理器就是從基類中繼承的 objects:

class ChildA(AbstractBase):
    # ...
    # This class has CustomManager as the default manager.
    pass

如果你想從 AbstractBase繼承,卻又想提供另一個默認(rèn)管理器,那么你可以在子類中定義默認(rèn)管理器:

class ChildB(AbstractBase):
    # ...
    # An explicit default manager.
    default_manager = OtherManager()

在這個例子中, default_manager就是默認(rèn)的 管理器。從基類中繼承的 objects 管理器仍是可用的。只不過它不再是默認(rèn)管理器罷了。

最后再舉個例子,假設(shè)你想在子類中再添加一個額外的管理器,但是很想使用從 AbstractBase繼承的管理器做為默認(rèn)管理器。那么,你不在直接在子類中添加新的管理器,否則就會覆蓋掉默認(rèn)管理器,而且你必須對派生自這個基類的所有子類都顯示指定管理器。 解決辦法就是在另一個基類中添加新的管理器,然后繼承時將其放在默認(rèn)管理器所在的基類 之后。例如:

class ExtraManager(models.Model):
    extra_manager = OtherManager()

    class Meta:
        abstract = True

class ChildC(AbstractBase, ExtraManager):
    # ...
    # Default manager is CustomManager, but OtherManager is
    # also available via the "extra_manager" attribute.
    pass

注意在抽象模型上面定義一個自定義管理器的時候,不能調(diào)用任何使用這個抽象模型的方法。就像:

ClassA.objects.do_something()

是可以的,但是:

AbstractBase.objects.do_something()

會拋出一個異常。這是因為,管理器被設(shè)計用來封裝對象集合管理的邏輯。由于抽象的對象中并沒有一個集合,管理它們是毫無意義的。如果你寫了應(yīng)用在抽象模型上的功能,你應(yīng)該把功能放到抽象模型的靜態(tài)方法,或者類的方法中。

實現(xiàn)上的注意事項

無論你向自定義管理器中添加了什么功能,都必須可以得到 管理器實例的一個淺表副本:例如,下面的代碼必須正常運(yùn)行:

>>> import copy
>>> manager = MyManager()
>>> my_copy = copy.copy(manager)

Django 在一些查詢中會創(chuàng)建管理器的淺表副本;如果你的管理器不能被復(fù)制,查詢就會失敗。

這對于大多數(shù)自定義管理器不是什么大問題。如果你只是添加一些簡單的方法到你的管理器中,不太可能會把你的管理器實例變?yōu)椴豢蓮?fù)制的。但是,如果你覆蓋了__getattr__,或者其它管理器中控制對象狀態(tài)的私有方法,你應(yīng)該確保不會影響到管理器的復(fù)制。

控制自動管理器的類型

這篇文檔已經(jīng)提到了Django創(chuàng)建管理器類的一些位置:默認(rèn)管理器和用于訪問關(guān)聯(lián)對象的“樸素” 管理器。在 Django 的實現(xiàn)中也有很多地方用到了臨時的樸素管理器。 正常情況下,django.db.models.Manager 類的實例會自動創(chuàng)建管理器。

在整個這一節(jié)中,我們將那種由 Django 為你創(chuàng)建的管理器稱之為 "自動管理器",既有因為沒有管理器而被 Django 自動添加的默認(rèn)管理器, 也包括在訪問關(guān)聯(lián)模型時使用的臨時管理器。

有時,默認(rèn)管理器也并非是自動管理器。 一個例子就是 Django 自帶的django.contrib.gis 應(yīng)用,所有 gis模型都必須使用一個特殊的管理器類(GeoManager),因為它們需要運(yùn)行特殊的查詢集(GeoQuerySet)與數(shù)據(jù)庫進(jìn)行交互。這表明無論自動管理器是否被創(chuàng)建,那些要使用特殊的管理器的模型仍要使用這個特殊的管理器類。

Django 為自定義管理器的開發(fā)者提供了一種方式:無論開發(fā)的管理器類是不是默認(rèn)的管理器,它都應(yīng)該可以用做自動管理器。 可以通過在管理器類中設(shè)置 use_for_related_fields 屬性來做到這點:

class MyManager(models.Manager):
    use_for_related_fields = True
    # ...

如果在模型中的默認(rèn) 管理器(在這些情況中僅考慮默認(rèn)管理器)中設(shè)置了這個屬性,那么無論它是否需要被自動創(chuàng)建,Django 都會自動使用它。否則 Django 就會使用 django.db.models.Manager.

歷史回顧

從它使用目的來看,這個屬性的名稱(use_for_related_fields)好象有點古怪。原本,這個屬性僅僅是用來控制訪問關(guān)聯(lián)字段的管理器的類型,這就是它名字的由來。 后來它的作用更加拓寬了,但是名稱一直未變。 因為要保證現(xiàn)在的代碼在 Django 以后的版本中仍可以正常工作(continue to work),這就是它名稱不變的原因。

在自動管理器實例中編寫正確的管理器

在上面的django.contrib.gis 已經(jīng)提到了, use_for_related_fields這個特性是在需要返回一個自定義查詢集子類的管理器中使用的。要在你的管理器中提供這個功能,要注意以下幾點。

不要在這種類型的管理器子類中過濾掉任何結(jié)果

一個原因是自動管理器是用來訪問關(guān)聯(lián)模型 的對象。 在這種情況下,Django 必須要能看到相關(guān)模型的所有對象,所以才能根據(jù)關(guān)聯(lián)關(guān)系得到任何數(shù)據(jù) 。

如果你重寫了 get_queryset() 方法并且過濾掉了一些行數(shù)據(jù),Django 將返回不正確的結(jié)果。不要這么做! 在 get_queryset()方法中過濾掉數(shù)據(jù),會使得它所在的管理器不適于用做自動管理器。

設(shè)置 use_for_related_fields

use_for_related_fields屬性必須在管理器類中設(shè)置,而不是在類的 實例中設(shè)置。上面已經(jīng)有例子展示如何正確地設(shè)置,下面這個例子就是一個錯誤的示范:

# BAD: Incorrect code
class MyManager(models.Manager):
    # ...
    pass

# Sets the attribute on an instance of MyManager. Django will
# ignore this setting.
mgr = MyManager()
mgr.use_for_related_fields = True

class MyModel(models.Model):
    # ...
    objects = mgr

# End of incorrect code.

你也不應(yīng)該在模型中使用這個屬性之后,在類上改變它。這是因為在模型類被創(chuàng)建時,這個屬性值馬上就會被處理,而且隨后不會再讀取這個屬性值。 這節(jié)的第一個例子就是在第一次定義的時候在管理器上設(shè)置use_for_related_fields屬性,所有的代碼就工作得很好。

上一篇:Django 初探下一篇:分頁