Django Contenttype

 ????在django中巫延,有一個記錄了項目中所有model元數(shù)據(jù)的表效五,就是ContentType,表中一條記錄對應著一個存在的model炉峰,所以可以通過一個ContentType表的id和一個具體表中的id找到任何記錄畏妖,及先通過ContenType表的id可以得到某個model,再通過model的id得到具體的對象疼阔。

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


def demo(request):

? ? ????obj = models.ContentType.objects.get(id=10)

? ????? print(obj.model_class()) #

? ? ????returnHttpResponse('............')

過model_class就可以獲取對應的類戒劫。也就是說,今后婆廊,我們?nèi)绻约憾xmodel如果有外鍵關聯(lián)到這個ContentType上迅细,我們就能找到對應的model名稱


django_content_type記錄了當前的Django項目中所有model所屬的app(即app_label屬性)以及model的名字(即model屬性)。 當然淘邻,django_content_type并不只是記錄屬性這么簡單茵典,contenttypes是對model的一次封裝,因此可以通過contenttypes動態(tài)的訪問model類型列荔,而不需要每次import具體的model類型敬尺。


ContentType實例提供的接口?

? ? ? ? 1.ContentType.model_class() :獲取當前ContentType類型所代表的模型類

????????2.ContentType.get_object_for_this_type() :使用當前ContentType類型所代表的模型類做一次get查詢

ContentType管理器(manager)提供的接口?

? ? ? ? 1.ContentType.objects.get_for_id() :通過id尋找ContentType類型,這個跟傳統(tǒng)的get方法的區(qū)別就是它跟get_for_model共享一個緩存贴浙,因此更為推薦砂吞。

????????2.ContentType.objects.get_for_model() :通過model或者model的實例來尋找ContentType類型


Django ContentTypes的使用場景

ContentType的通用類型

from django.db import models

from django.contrib.auth.models importUser

class Post(models.Model):?

?????????author = models.ForeignKey(User)

????????title = models.CharField(max_length=75)

????????slug = models.SlugField(unique=True)

????????body = models.TextField(blank=True)

class Picture(models.Model):?

?????????author = models.ForeignKey(User)

????????image = models.ImageField()

????????caption = models.TextField(blank=True)

class Comment(models.Model):?

? ? ? ? author = models.ForeignKey(User)

????????body = models.TextField(blank=True)

????????post = models.ForeignKey(Post,null=True)

????????picture = models.ForeignKey(Picture,null=True)

(Comment是分別和Picture或者Post中其中一個對應即可,一個Comment并不既需要Post又需要Picture才能建立)


????????通過Contenttype框架對以上代碼進行改進崎溃,ContentType提供了一種GenericForeignKey的類型蜻直,通過這種類型可以實現(xiàn)在Comment對其余所有model的外鍵關系:

class Comment(models.Model):

????????author = models.ForeignKey(User)? ??

????????body = models.TextField(blank=True)? ??

????????content_type = models.ForeignKey(ContentType)? ??

????????object_id = models.PositiveIntegerField()? ??

????????content_object = fields.GenericForeignKey()

????????在這里,通過使用一個content_type屬性代替了實際的model(如Post袁串,Picture)概而,而object_id則代表了實際model中的一個實例的主鍵,其中囱修,content_type和object_id的字段命名都是作為字符串參數(shù)傳進content_object的赎瑰,即:

????????content_object=fields.GenericForeignKey('content_type','object_id')


Django-ContentType-signals 

轉(zhuǎn)載:https://www.cnblogs.com/vipchenwei/p/7891890.html

????????django的signal結(jié)合contenttypes可以實現(xiàn)好友最新動態(tài),新鮮事破镰,消息通知等功能餐曼⊙勾ⅲ總體來說這個功能就是在用戶發(fā)生某個動作的時候?qū)⑵溆涗浵聛砘蛘吒郊幽承┎僮?/b>,比如通知好友源譬。要實現(xiàn)這種功能可以在動作發(fā)生的代碼里實現(xiàn)也可以通過數(shù)據(jù)庫觸發(fā)器等實現(xiàn)集惋,但在django中,一個很簡單的方法的就是使用signals踩娘。

????????當django保存一個object的時候會發(fā)出一系列的signals刮刑,可以通過對這些signals注冊listener,從而在相應的signals發(fā)出時執(zhí)行一定的代碼养渴。

????????使用signals來監(jiān)聽用戶的動作有很多好處雷绢,1、不管這個動作是發(fā)生在什么頁面理卑,甚至在很多頁面都可以發(fā)生這個動作习寸,都只需要寫一次代碼來監(jiān)聽保存object這個動作就可以了。2傻工、可以完全不修改原來的代碼就可以添加監(jiān)聽signals的功能霞溪。3、你幾乎可以在signals監(jiān)聽代碼里寫任何代碼中捆,包括做一些判斷是不是第一次發(fā)生此動作還是一個修改行為等等鸯匹。

????????想要記錄下每個操作,同時還能追蹤到這個操作的具體動作泄伪。

????????*首先用信號機制殴蓬,監(jiān)聽信號,實現(xiàn)對信號的響應函數(shù)蟋滴,在響應函數(shù)中記錄發(fā)生的動作(記錄在一張記錄表染厅,相當于下文的Event)。

????????*其次就是為了能追蹤到操作的具體動作津函,必須從這張表中得到相應操作的model肖粮,這就得用到上面說的ContentType

  對于新鮮事這個功能來說就是使用GenericRelation來產(chǎn)生一個特殊的外鍵尔苦,它不像models.ForeignKey那樣涩馆,必須指定一個Model來作為它指向的對象。GenericRelation可以指向任何Model對象允坚,有點像C語言中 void* 指針魂那。

  這樣關于保存用戶所產(chǎn)生的這個動作,比如用戶寫了一片日志稠项,我們就可以使用Generic relations來指向某個Model實例比如Post涯雅,而那個Post實例才真正保存著關于用戶動作的完整信息,即Post實例本身就是保存動作信息最好的地方展运。這樣我們就可以通過存取Post實例里面的字段來描述用戶的那個動作了活逆,需要什么信息就往那里面去取轻腺。而且使用Generic relations的另外一個好處就是在刪除了Post實例后,相應的新鮮事實例也會自動刪除划乖。

  怎么從這張操作記錄表中得到相應操作的model呢,這就得用到fields.GenericForeignKey挤土,它是一個特殊的外鍵琴庵,可以指向任何Model的實例,在這里就可以通過這個字段來指向類似Post這樣保存著用戶動作信息的Model實例仰美。

from django.db import models

from django.contrib.auth.models import User

from django.contrib.contenttypes import fields

from django.db.models import signals

class Post(models.Model):

? ? ????author = models.ForeignKey(User)

? ? ????title = models.CharField(max_length=255)

? ? ? ?content = models.TextField()

? ? ????created = models.DateTimeField(u'發(fā)表時間', auto_now_add=True)

? ? ????updated = models.DateTimeField(u'最后修改時間', auto_now=True)

? ????? events = fields.GenericRelation('Event')

? ? ????def __str__(self):

? ? ? ? ????????return self.title

? ? ????def description(self):

? ? ? ? ????????return u'%s 發(fā)表了日志《%s》' % (self.author, self.title)


class Event(models.Model):

? ? ????user = models.ForeignKey(User)

? ? ????content_type = models.ForeignKey(ContentType)

? ? ????object_id = models.PositiveIntegerField()

? ? ????content_object= fields.GenericForeignKey('content_type', 'object_id')

? ? ????created = models.DateTimeField(u'事件發(fā)生時間', auto_now_add=True)

? ? ????def __str__(self):

? ? ? ? ????????return "%s的事件: %s" % (self.user, self.description())

? ? ? ?def description(self):

? ? ? ? ????????return self.content_object.description()

????????def post_post_save(sender, instance, signal, *args, **kwargs):

? ? ????????????"""

? ????????????????????? :param sender:監(jiān)測的類:Post類

? ????????????????????? :param instance: 監(jiān)測的類:Post類

????????????????????? ? :param signal: 信號類

????????? ? """

? ? ????????post = instance

? ????????? event = Event(user=post.author, content_object=post)

? ????????? event.save()

????????????signals.post_save.connect(post_post_save, sender=Post)

????????????#signals.post_save.connect(post_post_sace,sender=Book)可以監(jiān)聽多個類


只要model中有object的保存操作迷殿,都將執(zhí)行post_post_save函數(shù),故可以在這個接受函數(shù)中實現(xiàn)通知好友等功能咖杂。

前面說到django在保存一個object的時候會發(fā)出一系列signals庆寺,在這里我們所監(jiān)聽的是signals.post_save這個signal,這個signal是在django保存完一個對象后發(fā)出的诉字,django中已定義好得一些signal, 在django/db/models/signal.py中可以查看懦尝,同時也可以自定義信號。

利用connect這個函數(shù)來注冊監(jiān)聽器壤圃, connect原型為:

def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):

第一個參數(shù)是要執(zhí)行的函數(shù)陵霉,第二個參數(shù)是指定發(fā)送信號的Class,這里指定為Post這個Model伍绳,對其他Model所發(fā)出的signal并不會執(zhí)行注冊的函數(shù)踊挠。

instance這個參數(shù),即剛剛保存完的Model對象實例效床。創(chuàng)建事件的時候看到可以將post這個instance直接賦給generic.GenericForeignKey類型的字段谨朝,從而event實例就可以通過它來獲取事件的真正信息了字币。

最后有一點需要的注意的是共缕,Post的Model定義里現(xiàn)在多了一個字段:

content_object= GenericRelation(‘Event’)

? ? ? 通過這個字段可以得到與某篇post相關聯(lián)的所有事件洗出,最重要的一點是如果沒有這個字段,那么當刪除一篇post的時候图谷,與該post關聯(lián)的事件是不會自動刪除的。反之有這個字段就會進行自動的級聯(lián)刪除

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末隘梨,一起剝皮案震驚了整個濱河市程癌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌轴猎,老刑警劉巖嵌莉,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異捻脖,居然都是意外死亡锐峭,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門可婶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來只祠,“玉大人,你說我怎么就攤上這事扰肌∨浊蓿” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵曙旭,是天一觀的道長盗舰。 經(jīng)常有香客問我,道長桂躏,這世上最難降的妖魔是什么钻趋? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮剂习,結(jié)果婚禮上蛮位,老公的妹妹穿的比我還像新娘。我一直安慰自己鳞绕,他們只是感情好失仁,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著们何,像睡著了一般萄焦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天拂封,我揣著相機與錄音茬射,去河邊找鬼。 笑死冒签,一個胖子當著我的面吹牛在抛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播萧恕,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼刚梭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了廊鸥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤辖所,失蹤者是張志新(化名)和其女友劉穎惰说,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缘回,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡吆视,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了酥宴。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啦吧。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖拙寡,靈堂內(nèi)的尸體忽然破棺而出授滓,到底是詐尸還是另有隱情,我是刑警寧澤肆糕,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布般堆,位于F島的核電站,受9級特大地震影響诚啃,放射性物質(zhì)發(fā)生泄漏淮摔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一始赎、第九天 我趴在偏房一處隱蔽的房頂上張望和橙。 院中可真熱鬧,春花似錦造垛、人聲如沸魔招。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仆百。三九已至,卻和暖如春奔脐,著一層夾襖步出監(jiān)牢的瞬間俄周,已是汗流浹背吁讨。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留峦朗,地道東北人建丧。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像波势,于是被迫代替她去往敵國和親档痪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容