码迷,mamicode.com
首页 > 其他好文 > 详细

[Django学习] Django基础(10)_ContentType学习总结

时间:2018-07-21 17:25:57      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:username   mod   cas   之间   初始   tail   出现   安装   ever   

一. 什么是ContentTypes

  Django ContentTypes是由Django框架提供的一个核心功能。Django ContentTypes是一个记录了项目中所有model元数据的表,表中一条记录对应着一个存在的model。

  当使用django-admin初始化一个django项目的时候,可以看到在默认的INSTALL_APPS已经包含了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.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

  在第一次对Django的model进行migrate之后,就可以发现在数据库中出现了一张默认生成的名为django_content_type的表。 如果没有建立任何的model,默认django_content_type是这样的:

sqlite> select * from django_content_type;
1|admin|logentry
2|auth|group
3|auth|user
4|auth|permission
5|contenttypes|contenttype
6|sessions|session

  django_content_type记录了当前的Django项目中所有model所属的app(即app_label属性)以及model的名字(即model属性)。 所以可以通过一个ContentType表的id和一个具体表中的id找到任何记录,即先通过ContenType表的id可以得到某个model,再通过model的id得到具体的对象。

二. ContentType实例的基本方法

1. ContentType.get_object_for_this_type(**kwargs)

  为ContentType表示的模型获取一组有效的查找参数,并执行get()查找该模型,返回相应的对象。

2. ContentType.model_class()
  返回由这个ContentType实例表示的模型类。
>>> from django.contrib.contenttypes.models import ContentType
>>> user_type = ContentType.objects.get(app_label="auth", model="user")
<ContentType: user>
>>>
>>> user_type.model_class()
<class ‘django.contrib.auth.models.User‘>
>>>
>>> user_type.get_object_for_this_type(username=‘Guido‘)
<User: Guido>

  使用这些方法,您可以编写高级通用代码执行查询任何安装模型——而不是import和使用一个特定的模型类;再运行时,您可以传递app_label和model到一个ContentType的查询中,然后就可以使用查询结果中的model class或检索model中的对象。

  您可以将另一个模型与ContentType关联起来,将它的实例与特定的模型类绑定在一起,并使用这些方法访问这些模型类。

三. 自定义管理器ContentTypeManager

1. get_for_id(id)

  通过id来查询ContentType

3. get_for_model(modelfor_concrete_model=True)

  获取模型类或模型实例,并返回表示该模型的ContentType实例

4. get_for_models(*modelsfor_concrete_models=True)

  获取模型类的可变数量,并返回一个字典,该字典将模型类映射到表示它们的ContentType实例。

5. get_by_natural_key(app_labelmodel)

  返回由给定的应用程序标签和模型名称唯一标识的ContentType实例。

>>> ct=ContentType.objects.all()
>>> ct
<QuerySet [<ContentType: log entry>, <ContentType: permission>, <ContentType: group>, <ContentType: user>, 
<ContentType: content type>, <ContentType: session>, <ContentType: blog>, <ContentType: blog type>, <ContentType: readnum>, 
<ContentType: read num>, <ContentType: read detail num>]>
>>>
>>> ContentType.objects.get_for_id(1)
<ContentType: log entry>
>>>
>>> from blog.models import Blog
>>> from blog.models import BlogType
>>> ContentType.objects.get_for_model(Blog)
<ContentType: blog>
>>> ContentType.objects.get_for_models(Blog,BlogType)
{<class ‘blog.models.Blog‘>: <ContentType: blog>, <class ‘blog.models.BlogType‘>: <ContentType: blog type>}
>>> ContentType.objects.get_by_natural_key(app_label=‘blogstatistics‘,model=‘readnum‘)
<ContentType: read num>

四. Generic relations

  从某个模型中添加外键到ContentType可以使您的模型有效地绑定到另一个模型类,从而使用ContentType来启用模型之间的真正泛型(有时称为“多态”)关系。

from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models

class TaggedItem(models.Model):
    tag = models.SlugField()
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey(‘content_type‘, ‘object_id‘)

    def __str__(self):
        return self.tag

  普通的ForeignKey只能“指向”另一个模型,这意味着如果TaggedItem模型使用了ForeignKey,那么它必须选择一个特定模型来存储Tag。contenttypes应用程序提供了一个特殊的字段类型(GenericForeignKey),它并允许与任何模型的关系。

  一个标准的GenericForeignKey由三部分组成:

  • 在model中定义ForeignKey字段,并关联到ContentType表。通常这个字段命名为“content_type”
  • 在model中定义PositiveIntegerField字段,用来存储关联表中的主键。通常这个字段命名为“object_id”
  • 在model中定义GenericForeignKey字段,传入上述两个字段的名字。

  这将使API与普通的ForeignKey相似;每个TaggedItem都有一个content_object字段,该字段返回与之相关的对象,您也可以将其分配给该字段,或者在创建TaggedItem时使用: 

五. Reverse generic relations

  如果您知道您将最经常使用哪些模型,您还可以添加一个“反向”泛型关系来启用一个额外的API。

from django.contrib.contenttypes.fields import GenericRelation
from django.db import models

class Bookmark(models.Model):
    url = models.URLField()
    tags = GenericRelation(TaggedItem) #不会在数据库中创建字段

  Bookmark实例将每个实例都有一个Tags属性,可以用来检索它们关联的taggeditem:

>>> b = Bookmark(url=‘https://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()
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>

From: Django文档

 

[Django学习] Django基础(10)_ContentType学习总结

标签:username   mod   cas   之间   初始   tail   出现   安装   ever   

原文地址:https://www.cnblogs.com/AngryZe/p/9336669.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!