ContentType 记录了django中的模型,并且新安装的模型会自动加入。
要使用只需要在INSTALLED_APPS中增加'django.contrib.contenttypes'即可
ContentType模型
ContentType.get_object_for_this_type(**kwargs) 通过一系列参数来获得指向model的实例. ContentType.model_class() 通过ContentType instance 返回 model class
>>> from django.contrib.contenttypes.models import ContentType >>> user_type = ContentType.objects.get(app_label="auth", model="user") >>> user_type >>> user_type.model_class() <class 'class 'django.contrib.auth.models.User'> >>> user_type.get_object_for_this_type(username='Guido') <User: Guido>
class ContentTypeManager clear_cache() django 自己会处理好 get_for_model(model) 参数为一个其他model的 class 类或者实例,返回content type的实例 get_by_natural_key(app_label,model) 返回content type的实例
Generic relations
在你的model中增加一个外键到ContentType能让你的模型更高效的绑定到其他model class. 一个 tagging system的例子:
from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic class TaggedItem(models.Model): tag = models.SlugField() content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') def __unicode__(self): return self.tag
一个普通的ForeignKey 只能指定具体的一个model,而contenttypes 能提供特殊的field 解决这个问题,指向任意的model GenericForeignKey 有三个部分来构建一个GenericForeignKey: 1.在model中增加一个field为ContentType的ForeignKey. 2.给你的model中加一个field来存储指向model的主键.这个field一般命名为object_id.它是主键 3.增加一个GenericForeignKey类型的field, 传递前面两个field的值. 默认为"content_type" 和"object_id",
object_id 的类型不一定要和相关连的model的primary key fields一样,只要能强制转换过来就可以。为了最大的兼容性可以使用TextField,但是会降低数据库效率
这就像一个普通的ForeignKey; 每一个TaggedItem的content_object返回它实际指向的model,你能在创建TaggedItem的时候给它赋值.
>>> from django.contrib.auth.models import User >>> guido = User.objects.get(username='Guido') >>> t = TaggedItem(content_object=guido, tag='bdfl') >>> t.save() >>> t.content_object <User: Guido>
GenericForeignKey不能使用 (filter()和exclude()等数据库的API) :
# This will fail >>> TaggedItem.objects.filter(content_object=guido) # This will also fail >>> TaggedItem.objects.get(content_object=guido)
Reverse generic relations
class GenericRelationclass Bookmark(models.Model): url = models.URLField() tags = generic.GenericRelation(TaggedItem)
Bookmark instances 将有一个tags属性, 并且和TaggedItems 联系起来:
>>> b = Bookmark(url='http://www.djangoproject.com/') >>> b.save() >>> t1 = TaggedItem(content_object=b, tag='django') >>> t1.save() >>> t2 = TaggedItem(content_object=b, tag='python') >>> t2.save() >>> b.tags.all() [<TaggedItem: django>, <TaggedItem: python>]
GenericRelation接收 content-type 和 object-id 作为参数,
如果 model 的GenericForeignkey 用的不是默认field names ,在建立GeneriRelation的时候必须传递field的name给它
例如, 如果TaggedItem model 使用 fields content_type_fk and object_primary_key 生成 generic foreign key,代码如下
>>> b = Bookmark.objects.get(url='http://www.djangoproject.com/') >>> bookmark_type = ContentType.objects.get_for_model(b) >>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id,object_id=b.id) [<TaggedItem: django>,]
当然, 如果你不使用reverse relationship, 也可以这么写:
>>> b = Bookmark.objects.get(url='http://www.djangoproject.com/') >>> bookmark_type = ContentType.objects.get_for_model(b) >>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id, ... object_id=b.id) [<TaggedItem: django>, <TaggedItem: python>]