Django中自定義模型管理器(Manager)及方法
1.自定義管理器(Manager)
在語(yǔ)句Book.objects.all()中, objects 是一個(gè)特殊的屬性,通過它來查詢數(shù)據(jù)庫(kù),它就是模型的一個(gè)Manager.
每個(gè)Django模型至少有一個(gè)manager,你可以創(chuàng)建自定義manager以定制數(shù)據(jù)庫(kù)的訪問.
這里有兩個(gè)方法創(chuàng)建自定義manager:添加額外的manager;修改manager返回的初始Queryset.
添加額外的manager
增加額外的manager是為模塊添加 表級(jí)功能 的首選辦法.(至于 行級(jí)功能 ,也就是只作用于模型實(shí)例對(duì)象的函數(shù),則通過自定義模型方法實(shí)現(xiàn)).
例如,為Book模型添加一個(gè) title_count() 的manger方法,它接收一個(gè) keyword ,并返回標(biāo)題中包含 keyword 的書的數(shù)量.
from django.db import models
# 自定義模型管理器類
class BookManager(models.Manager):
#自定義模型管理器中的方法
def title_count(self, keyword):
return self.filter(title_icountains=keyword).count()
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
...
objects = BookManager()
def __str__(self):
return self.title
1.我們創(chuàng)建一個(gè)BookManager類,繼承自 django.db.models.Manager .它只有一個(gè)方法 title_count() ,來進(jìn)行統(tǒng)計(jì).注意,這個(gè)方法使用了 self.filter() ,這個(gè)self指manager本身.
2.將BookManager()賦值給模型的objects屬性.它將取代模型的默認(rèn)manager(objects).把它命名為objects是為了與默認(rèn)的manager保持一致.
現(xiàn)在我們可以進(jìn)行下面的操作:
>>> Books.objects.title_count('django') #這是我們自定義的manager中的查詢方法
>>> Books.objects.filter(title__icontains='django').count() # 默認(rèn)的查詢方法依然可用
這樣我們可以將經(jīng)常使用的查詢進(jìn)行封裝,就不必重復(fù)寫代碼了.
修改初始Manager Queryset
manager的基礎(chǔ)Queryset返回系統(tǒng)中的所有對(duì)象.例如, Book.objects.all() 返回book數(shù)據(jù)庫(kù)中的所有書籍.你而已通過覆蓋 Manager.get_queryset() 方法來重寫manager的基礎(chǔ)Queryset. get_queryset() 應(yīng)該按照你的需求返回一個(gè)Queryset.
例如,下面的模型有兩個(gè)manger--一個(gè)返回所有對(duì)象,另一個(gè)僅返回作者是Roald Dahl的書
from django.db import models
#首先,定義一個(gè)Manager的子類
class DahlBookManager(models.Manager):
def get_queryset(self):
return super(DahlBookManager, self).get_queryset().filter(author='Roald Dahl')
# 然后,將它顯式地插入到Book模型中
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=50)
...
objects = models.Manager() # 默認(rèn)Manager
dahl_objects = DahlBookManager() # 自定義的特殊Manager
在這個(gè)示例模型中, Book.objects.all() 將返回?cái)?shù)據(jù)庫(kù)中的所有書籍,而 Book.dahl_objects.all() 只返回作者是Roald Dahl的書籍.注意我們明確的將 objects 設(shè)置為默認(rèn) Manger 的一個(gè)實(shí)例,因?yàn)槿绻覀儾贿@樣做,那么dahl_objects將成為唯一一個(gè)可用的manager.
由于 get_queryset() 返回一個(gè)Queryset對(duì)象,所以你可以使用 filter() , exclude() 和其他所有的Queryset方法.
如果你使用自定義的Manager對(duì)象,請(qǐng)注意,Django遇到的第一個(gè)Manager(以它在模型中被定義的位置為準(zhǔn))會(huì)有一個(gè)特殊狀態(tài)。 Django將會(huì)把第一個(gè)Manager 定義為默認(rèn)Manager ,Django的許多部分(但是不包括admin應(yīng)用)將會(huì)明確地為模型使用這個(gè)manager。 結(jié)論是,你應(yīng)該小心地選擇你的默認(rèn)manager。因?yàn)楦采w get_queryset() 了,你可能接受到一個(gè)無用的返回對(duì)像,你必須避免這種情況.
2.自定義模型方法
為了給你的對(duì)像添加一個(gè)行級(jí)功能,那就定義一個(gè)自定義方法.鑒于manager經(jīng)常被用來用一些整表操作(table-wide).模型方法應(yīng)該只對(duì)特殊模型實(shí)例起作用.
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):
# Return the person's full name
return f'{self.first_name} {self.last_name}'
full_name = property(_get_full_name) # 將類方法包裝為屬性
這些方法的使用:
>>> p = Person.objects.get(first_name='Barack', last_name='Obama') >>> p.birth_date datetime.date(1961, 8, 4) >>> p.baby_boomer_status() 'Baby boomer' >>> p.full_name # 注意這不是一個(gè)方法 -- 它被視為一個(gè)屬性 'Barack Obama'
3.重寫預(yù)定義的模型方法
還有一組模型方法了封裝了一些你可能想要自定義的數(shù)據(jù)庫(kù)行為.特別是你可能想要修改 save() 和 delete() 的工作方式.你可以自由的重寫這些方法(以及其他的模型方法)來改變行為.重寫內(nèi)置方法的經(jīng)典用例就是你想要在保存一個(gè)對(duì)象是做些其他的什么.例如:
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) ,它確保該對(duì)象仍被保存到數(shù)據(jù)庫(kù)中.如果你忘記調(diào)用超類方法,那么默認(rèn)的行為將不會(huì)發(fā)生,也不會(huì)發(fā)生數(shù)據(jù)庫(kù)操作.
同樣重要的是,您要傳遞可以傳遞給模型方法的參數(shù)——這就是 *args, **kwargs 所做的事情。Django將不時(shí)擴(kuò)展內(nèi)置模型方法的功能,并添加新的參數(shù)。如果您在方法定義中使用了 *args, **kwargs ,您將保證您的代碼在添加時(shí)將自動(dòng)支持這些參數(shù)。
Model.clean()
應(yīng)用這個(gè)方法來提供自定義的模型驗(yàn)證,以及修改模型的屬性.例如,你可以使用它來給一個(gè)字段自動(dòng)提供值,或者用于多個(gè)字段需要一起驗(yàn)證的情形:
import detetime
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 done:
raise ValidationEroor('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()
注意,調(diào)用模型的 save() 方法時(shí),不會(huì)自動(dòng)調(diào)用 clean() 方法,需要views手動(dòng)調(diào)用.
上面的示例中, clean() 引發(fā)的ValidationError異常通過一個(gè)字符串實(shí)例化,所以它將被保存在一個(gè)特殊的錯(cuò)誤字典中,鍵為 NON_FIELD_ERRORS .這個(gè)鍵用于整個(gè)模型出現(xiàn)的錯(cuò)誤而不是一個(gè)特定字段穿線的錯(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.'})
...
總結(jié)
以上所述是小編給大家介紹的Django中自定義模型管理器(Manager)及方法,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
Python SMTP發(fā)送郵件遇到的一些問題及解決辦法
今天小編就為大家分享一篇關(guān)于Python SMTP發(fā)送郵件遇到的一些問題及解決辦法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-10-10
Python多線程與多進(jìn)程相關(guān)知識(shí)總結(jié)
進(jìn)程(process)和線程(thread)是操作系統(tǒng)的基本概念,是操作系統(tǒng)程序運(yùn)行的基本單元,本文簡(jiǎn)要介紹進(jìn)程和線程的概念以及Python中的多進(jìn)程和多線程.需要的朋友可以參考下2021-05-05
python try except返回異常的信息字符串代碼實(shí)例
這篇文章主要介紹了python try except返回異常的信息字符串代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
Python獲取excel的數(shù)據(jù)并繪制箱型圖和直方圖的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Python獲取excel的數(shù)據(jù)并繪制箱型圖和直方圖的相關(guān)資料,好的圖表能幫助我們深化數(shù)據(jù)的記憶點(diǎn),文中通過圖文以及代碼示例將實(shí)現(xiàn)的方法介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
Python編程利用科赫曲線實(shí)現(xiàn)三維飄雪效果示例過程
這篇文章主要介紹了Python編程實(shí)現(xiàn)三維飄雪效果示例過程,通過本示例你可以自己做出一個(gè)浪漫的雪花飄落效果,有需要的朋友可以借鑒參考下2021-10-10
python簡(jiǎn)單的函數(shù)定義和用法實(shí)例
這篇文章主要介紹了python簡(jiǎn)單的函數(shù)定義和用法,實(shí)例分析了Python自定義函數(shù)及其使用方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-05-05

