Django contenttypes 框架詳解(小結(jié))
一、什么是Django ContentTypes?
Django ContentTypes是由Django框架提供的一個(gè)核心功能,它對(duì)當(dāng)前項(xiàng)目中所有基于Django驅(qū)動(dòng)的model提供了更高層次的抽象接口。 當(dāng)然我們不是說(shuō)的是http中的content-type!完全沒(méi)有任何關(guān)系!
下面將一步一步解釋Django ContentTypes在Django框架中做了什么,以及如何使用Django ContentTypes。
當(dāng)然,如果對(duì)于ContentTypes有了初步了解而只是不了解它的應(yīng)用場(chǎng)景,可以直接查閱一下原文檔:
https://docs.djangoproject.com/en/1.10/ref/contrib/contenttypes/
二、Django ContentTypes做了什么?
當(dāng)使用django-admin初始化一個(gè)django項(xiàng)目的時(shí)候,可以看到在默認(rèn)的INSTALL_APPS已經(jīng)包含了django.contrib.contenttypes:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
而且注意django.contrib.contenttypes是在django.contrib.auth之后,這是因?yàn)閍uth中的permission系統(tǒng)是根據(jù)contenttypes來(lái)實(shí)現(xiàn)的。
我們來(lái)查詢查閱了一下django.contrib.contenttypes.models文件:
class ContentType(models.Model):
app_label = models.CharField(max_length=100)
model = models.CharField(_('python model class name'), max_length=100)
objects = ContentTypeManager()
class Meta:
verbose_name = _('content type')
verbose_name_plural = _('content types')
db_table = 'django_content_type'
unique_together = (('app_label', 'model'),)
def __str__(self):
return self.name
大家可以看到ContentType就是一個(gè)簡(jiǎn)單的django model,而且它在數(shù)據(jù)庫(kù)中的表的名字為django_content_type。
這個(gè)表的名字一般都不會(huì)陌生,在第一次對(duì)Django的model進(jìn)行migrate之后,就可以發(fā)現(xiàn)在數(shù)據(jù)庫(kù)中出現(xiàn)了一張默認(rèn)生成的名為django_content_type的表。
如果沒(méi)有建立任何的model,默認(rèn)django_content_type是這樣的:

因此,django_content_type記錄了當(dāng)前的Django項(xiàng)目中所有model所屬的app(即app_label屬性)以及model的名字(即model屬性)。
當(dāng)然,django_content_type并不只是記錄屬性這么簡(jiǎn)單,contenttypes是對(duì)model的一次封裝,
因此可以通過(guò)contenttypes動(dòng)態(tài)的訪問(wèn)model類(lèi)型,而不需要每次import具體的model類(lèi)型。
- ContentType實(shí)例提供的接口
- ContentType.model_class()
- 獲取當(dāng)前ContentType類(lèi)型所代表的模型類(lèi)
- ContentType.get_object_for_this_type()
- 使用當(dāng)前ContentType類(lèi)型所代表的模型類(lèi)做一次get查詢
- ContentType管理器(manager)提供的接口
- ContentType.objects.get_for_id()
- 通過(guò)id尋找ContentType類(lèi)型,這個(gè)跟傳統(tǒng)的get方法的區(qū)別就是它跟get_for_model共享一個(gè)緩存,因此更為推薦。
- ContentType.objects.get_for_model()
- 通過(guò)model或者model的實(shí)例來(lái)尋找ContentType類(lèi)型
- ContentType.model_class()
三、Django ContentTypes的使用場(chǎng)景
在我們這個(gè)項(xiàng)目中各種商品的優(yōu)惠卷就運(yùn)用到了這個(gè)知識(shí)點(diǎn):
假使我們models下有這幾張表:
class Electrics(models.Model): #電器類(lèi)
name = models.CharField(max_length=32)
price= models.IntegerField(default=100)
def __str__(self):
return self.name
class Foods(models.Model): #食物類(lèi)
name = models.CharField(max_length=32)
price = models.IntegerField(default=100)
def __str__(self):
return self.name
class Clothes(models.Model): #衣服類(lèi)
name = models.CharField(max_length=32)
price= models.IntegerField(default=100)
def __str__(self):
return self.name
class Coupon(models.Model): #優(yōu)惠券
name = models.CharField(max_length=32)
def __str__(self):
return self.name
我們先來(lái)考慮一個(gè)問(wèn)題,如何把這些商品和優(yōu)惠卷相關(guān)聯(lián)?
一種商品一個(gè)優(yōu)惠卷,那我們就在表中加入一種商品的優(yōu)惠券,就是一個(gè)一對(duì)多的ForeignKey,那么多個(gè)商品就有各種優(yōu)惠卷,
但是一種商品的特定優(yōu)惠卷在表結(jié)構(gòu)中,就那個(gè)字段有值,別的不相關(guān)的記錄為null,而且每增加一個(gè)商品,又要手動(dòng)的去添加外鍵,
這是繁瑣的!
所以我們就使用contenttypes 應(yīng)用中提供的特殊字段GenericForeignKey,我們可以解決上面的問(wèn)題:
只需要以下三步:
- 在model中定義ForeignKey字段,并關(guān)聯(lián)到ContentType表。通常這個(gè)字段命名為“content_type”
- 在model中定義PositiveIntegerField字段,用來(lái)存儲(chǔ)關(guān)聯(lián)表中的主鍵。通常這個(gè)字段命名為“object_id”
- 在model中定義GenericForeignKey字段,傳入上述兩個(gè)字段的名字。
具體實(shí)例代碼:
class Coupon(models.Model):
name = models.CharField(max_length=32)
content_type = models.ForeignKey(to=ContentType) # step 1
object_id = models.PositiveIntegerField() # step 2
content_object = GenericForeignKey('content_type', 'object_id') # step 3
def __str__(self):
return self.name
這樣的話不管表的數(shù)據(jù)都可以查詢出來(lái),而且添加新的商品的商品,也不需要?jiǎng)觾?yōu)惠券的源碼。
但我們?cè)诓樵兊倪^(guò)程中,用ORM實(shí)在太繁瑣了,所以還有一個(gè)反向查詢的方法:
就是在每個(gè)商品中關(guān)聯(lián) 綁定一個(gè)關(guān)系:
coupons = GenericRelation(to='Coupon') # 用于反向查詢,不會(huì)生成表字段
這樣我們就可以直接ORM的.coupons找相應(yīng)的字段!
相關(guān)文章
Python使用win32com模塊實(shí)現(xiàn)數(shù)據(jù)庫(kù)表結(jié)構(gòu)自動(dòng)生成word表格的方法
這篇文章主要介紹了Python使用win32com模塊實(shí)現(xiàn)數(shù)據(jù)庫(kù)表結(jié)構(gòu)自動(dòng)生成word表格的方法,結(jié)合實(shí)例形式分析了win32com模塊下載、連接mysql、查詢獲取表結(jié)構(gòu)以及使用win32com生成word表格的相關(guān)操作技巧,需要的朋友可以參考下2018-07-07
在Debian下配置Python+Django+Nginx+uWSGI+MySQL的教程
這篇文章主要介紹了在Debian下配置Python+Django+Nginx+uWSGI+MySQL的教程,Debian系統(tǒng)和Nginx服務(wù)器皆是高性能的選擇,需要的朋友可以參考下2015-04-04
Python?Panda中索引和選擇?series?的數(shù)據(jù)
這篇文章主要介紹了Python?Panda中索引和選擇series的數(shù)據(jù),文章通過(guò)圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
Python語(yǔ)法學(xué)習(xí)之進(jìn)程間的通信方式
進(jìn)程在創(chuàng)建之后是沒(méi)有辦法獲取返回值的,但有的時(shí)候兩個(gè)進(jìn)程之間需要進(jìn)行相互之間的配合才能完成工作,這就需要通信的幫助。本文主要介紹了Python中進(jìn)程間的通信方式,需要的可以了解一下2022-04-04
通過(guò)python實(shí)現(xiàn)彈窗廣告攔截過(guò)程詳解
這篇文章主要介紹了通過(guò)python實(shí)現(xiàn)彈窗廣告攔截過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
python virtualenv虛擬環(huán)境配置與使用教程詳解
這篇文章主要介紹了python virtualenv虛擬環(huán)境配置與使用教程詳解,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07

