Django的ContentType应用

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类型,这个跟传统的get方法的区别就是它跟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 import User

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的类型,通过这种类型可以实现在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的字段命名都是作为字符串参数传进content_object的,即:
content_object=fields.GenericForeignKey(‘content_type‘,‘object_id‘)

django的signal结合contenttypes可以实现好友最新动态,新鲜事,消息通知等功能。总体来说这个功能就是在用户发生某个动作的时候将其记录下来或者附加某些操作,比如通知好友。要实现这种功能可以在动作发生的代码里实现也可以通过数据库触发器等实现,但在django中,一个很简单的方法的就是使用signals。

当django保存一个object的时候会发出一系列的signals,可以通过对这些signals注册listener,从而在相应的signals发出时执行一定的代码。

使用signals来监听用户的动作有很多好处:
1、不管这个动作是发生在什么页面,甚至在很多页面都可以发生这个动作,都只需要写一次代码来监听保存object这个动作就可以了。
2、可以完全不修改原来的代码就可以添加监听signals的功能。
3、你几乎可以在signals监听代码里写任何代码,包括做一些判断是不是第一次发生此动作还是一个修改行为等等。

想要记录下每个操作,同时还能追踪到这个操作的具体动作。

*首先用信号机制,监听信号,实现对信号的响应函数,在响应函数中记录发生的动作(记录在一张记录表,相当于下文的Event)。

*其次就是为了能追踪到操作的具体动作,必须从这张表中得到相应操作的model,这就得用到上面说的ContentType。

对于新鲜事这个功能来说就是使用GenericRelation来产生一个特殊的外键,它不像models.ForeignKey那样,必须指定一个Model来作为它指向的对象。GenericRelation可以指向任何Model对象,有点像C语言中 void* 指针。

这样关于保存用户所产生的这个动作,比如用户写了一片日志,我们就可以使用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'发表时间', 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 发表了日志《%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'事件发生时间', 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:监测的类:Post类
            :param instance: 监测的类: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)可以监听多个类

只要model中有object的保存操作,都将执行post_post_save函数,故可以在这个接受函数中实现通知好友等功能。

前面说到django在保存一个object的时候会发出一系列signals,在这里我们所监听的是signals.post_save这个signal,这个signal是在django保存完一个对象后发出的,django中已定义好得一些signal, 在django/db/models/signal.py中可以查看,同时也可以自定义信号。

利用connect这个函数来注册监听器, connect原型为:

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

第一个参数是要执行的函数,第二个参数是指定发送信号的Class,这里指定为Post这个Model,对其他Model所发出的signal并不会执行注册的函数。

instance这个参数,即刚刚保存完的Model对象实例。创建事件的时候看到可以将post这个instance直接赋给generic.GenericForeignKey类型的字段,从而event实例就可以通过它来获取事件的真正信息了。

最后有一点需要的注意的是,Post的Model定义里现在多了一个字段:

content_object= GenericRelation(‘Event’)

通过这个字段可以得到与某篇post相关联的所有事件,最重要的一点是如果没有这个字段,那么当删除一篇post的时候,与该post关联的事件是不会自动删除的。反之有这个字段就会进行自动的级联删除

转载:https://www.jianshu.com/p/5636167ff230

原文地址:https://www.cnblogs.com/qiaoqianshitou/p/9655362.html

时间: 2024-10-11 01:18:45

Django的ContentType应用的相关文章

Django之ContentType组件

一.需求 给商品创建优惠券: 看看下面表结构: class Food(models.Model): """ id name 1 面条 """ name = models.CharField(max_length=32) def __str__(self): return self.name class Fruit(models.Model): """ id name 1 苹果 """ n

Django 使用Contenttype组件创建多关联数据库表

from django.db import models '''contenttype使用意义:如果使用contenttypes就不需要再使用多个Foreignkey, 因为在django_content_type表已经存储了app名和model名, 所以我们只需要将我们创建的模型与django_content_type表关联起来, 然后再存储一个实例 id 即可准确定位到某个app中某个模型的具体实例 ''' '''使用Django的Contenttype字段.''' # 导入必需模块 fro

Django中contenttype的应用

content_type表将app名称与其中的表的关系进行保存 通过下边的示例来理解content_type的具体应用: models: from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey,GenericRelation # Create you

django之contenttype

一 楔子 路飞学城 路飞学城有两种收费策略.一是按照学位来收费,python,C++,Java,另外一种是按照部分课程收费,python基础,面向对象,函数,这样一部分来收费.涉及到时间,一个月时长的多少钱,两个月时长的多少钱. 所以,第一版的表格设计如下. 四张表,价格策略外键关联课程表. 进阶1:两张价格策略表的重复的太多,没有必要 可以在价格策略表后面新添加一列,空表示不相关. 表面上这个没问题解决了.隐患是 课程除了学位课,普通课外,以后可能还有新的种类的课程,如果依照这种思路,每当出现

Django的ContentType框架django_conent_type

Django包含了一个conenttype应用程序,记录了Django项目中安装的所有模型,为当前项目所有基于Django驱动的model提供了更高层次的抽象接口. 一.概述 ContentTypes应用程序的核心是 django.contrib.contenttypes.models.ContentType: @python_2_unicode_compatible class ContentType(models.Model): app_label = models.CharField(ma

【Django】ContentType组件

目录 理解 表结构 使用 @ 好,现在我们有这样一个需求,我们的商城里有很多的商品,然而节日要来了,我们要搞活动. 那么,我们就要设计优惠券,优惠券都有什么类型呢?满减的.折扣的.立减的.等等等... 我们对应着活动类型,对某类商品设计优惠卷,比如: 家电是一类商品.食物是一类商品,那么我们就可以设计家电折扣优惠券,以及食物满减优惠券等. 所以,我们一顺手,表结构就出来了: from django.db import models is_true = {'null': True, 'blank'

【Django】ContentType组件 -- 2019-08-08 18:03:22

目录 理解 表结构 使用 原文: http://106.13.73.98/__/72/ @ 好,现在我们有这样一个需求,我们的商城里有很多的商品,然而节日要来了,我们要搞活动. 那么,我们就要设计优惠券,优惠券都有什么类型呢?满减的.折扣的.立减的.等等等... 我们对应着活动类型,对某类商品设计优惠卷,比如: 家电是一类商品.食物是一类商品,那么我们就可以设计家电折扣优惠券,以及食物满减优惠券等. 所以,我们一顺手,表结构就出来了: from django.db import models i

Django 之 ContentType组件

一.什么是 ContentTypes ContentTypes 是 Django 内置的一个应用,它可以追踪记录项目中所有 app 和 model 的对应关系,并记录在 django_content_type 表中. 二.ContentTypes 的应用场景 ContentTypes 适用于一张表与多张表相关关联的场景,如:一个卖课程的网站,它主要售卖两类课程(普通课程和学位课程).不同课程之间因学习周期不同,价格也不尽相同.因此就形成了每个课程可能有一个或多个价格策略.类似于下面这种: 如果我

django ContentType组件

一,需求 给商品创建优惠券: 看看下面表结构: class Food(models.Model): """ id name 1 面条 """ name = models.CharField(max_length=32) def __str__(self): return self.name class Fruit(models.Model): """ id name 1 苹果 """ n