Django ContentType是由Django框架提供的一个核心功能,对当前项目中所有基于Django驱动的model提供了更高层次的抽象接口
- 为什么要使用它?
假设我们创建了如下模型,里面包含文章Post,Picture和评论Comment模型。Comment可以是对Post的评论,也可以是对Picture的评论。如果你还想对其它对象(比如回答,用户) 进行评论, 这样你将需要在comment对象里添加非常多的ForeignKey。你的直觉会告诉你,这样做很傻,会造成代码重复和字段浪费。一个更好的方式是,只有当你需要对某个对象或模型进行评论时,才创建comment与那个模型的关系。这时你就需要使用django contenttypes
–>即指定对象获模型具有这个表的内容,进行联系 - ContentType
其就是一个简单的mode模型,其在数据库中表的名字为django_content_type
#源码
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'),)
django_content_type记录了当前的Django项目中所有model所属的app(即app_label属性)以及model的名字(即model属性)。
可以通过contenttypes动态的访问model类型,而不需要每次import具体的model类型。
ContentType实例提供的接口
- ContentType.model_class()
获取当前ContentType类型所代表的模型类 - ContentType.get_object_for_this_type()
使用当前ContentType类型所代表的模型类做一次get查询
ContentType管理器(manager)提供的接口
- ContentType.objects.get_for_id()
通过id寻找ContentType类型,这个跟传统的get方法的区别就是它跟get_for_model共享一个缓存,因此更为推荐。 - ContentType.objects.get_for_model()
通过model或者model的实例来寻找ContentType类型
使用contenttypes
- 在model中定义ForeignKey字段,并关联到ContentType表。通常这个字段命名为“content_type”
- 在model中定义PositiveIntegerField字段,用来存储关联表中的主键。通常这个字段命名为“object_id”
- 在model中定义GenericForeignKey字段,传入上述两个字段的名字。
- 也可添加其余字段,作为model的属性
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class ReadDetail(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING)#必须
object_id = models.PositiveIntegerField()#必须
content_object = GenericForeignKey('content_type', 'object_id')#必须
date = models.DateField(default=timezone.now)#自添加字段
read_num = models.IntegerField(default=0)#自添加字段
from django.contrib.contenttypes.models import ContentType
blog=Blog()#实例化Blog是model类
blog_content_type=ContentType.objects.get_for_model(blog)
#通过model或者model的实例来寻找ContentType类型
readnum, created = ReadNum.objects.get_or_create(content_type=blog_content_type, object_id=3)
#创建ReadDetail 实例 get_or_create 如果由这个对象就获取readnum,没有则创建这个对象 返回的是 (obj,Trye|False)
readnum.read_num=3
readnem.save()
#我们就通过ContentType关联到对应的model,并可获其操作.