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


    一. 什么是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文档

  • 相关阅读:
    nfs目录权限
    14.5.5 AUTO_INCREMENT Handling in InnoDB 在InnoDB AUTO_INCREMENT处理
    Tk 表格的宽度
    化工企业数据分析平台项目之应收款分析
    化工企业数据分析平台项目之应收款分析
    14.5.3 Grouping DML Operations with Transactions 分组DML 事务操作
    perl | 匹配多个
    struts的控制器组件
    解决Thinkpad开启飞行模式无法连接无线网络
    如何解决Thinkpad连接wifi经常断线
  • 原文地址:https://www.cnblogs.com/AngryZe/p/9336669.html
Copyright © 2020-2023  润新知