zoukankan      html  css  js  c++  java
  • 【Django】--Contenttypes框架,了解内容类型和范型关系

    Django中文文档1.8 https://legacy.gitbook.com/book/wizardforcel/django-chinese-docs-18/details

    Contenttypes

    • Django的contenttypes应用,可以追踪安装在Django项目里的所有应用,并提供一个高层次及通用的接口用于与你的模型进行交互。
    • Contenttypes的核心应用是ContentType模型,位置:django.contrib.contenttypes.models.ContentType
    • 通过添加 'django.contrib.contenttypes' 到你的 INSTALLED_APPS 设置中来启用它。

    Contenttypes相关方法

      1.class ContentType[source]

        每一个 ContentType 实例有两个字段,共同来唯一描述一个已经安装的模型,分别是:

          app_label

            模型所在的应用的名称。 这取自模型的 app_label 属性,并只包括应用的Python 导入路径的最后的部分。

              例如,"django.contrib.contenttypes"的 app_label 是"contenttypes".

           model

            模型的类的名称

        额外属性:

         name[source]

            Contenttype 的人类可读的的名称。它取之于模型的 verbose_name 属性.

          Changed in Django 1.8:

            安装 contenttypes 应用后,添加 sites应用 到你的 INSTALLED_APPS 设置并运行 manage.py migrate 来安装它,模型 django.contrib.sites.models.Site 将安装到你的数据库中。

            同时将创建 ContentType 的一个具有以下值的新实例︰
              app_label 将设置为 'sites' (Python 路径"django.contrib.sites"的最后部分)。
              model 将设置为 'site' 。

      2.`get_object_for_this_type (**kwargs)[source]

        接收 ContentType 表示的模型所接收的查询参数,对该模型做 一次get() 查询 ,然后返回相应的对象

      3.model_class ()[source]

        返回此 ContentType 实例所表示的模型类。

        例如,我们可以查找 User 模型的 ContentType ︰

          

        >>> from django.contrib.contenttypes.models import ContentType
        >>> user_type = ContentType.objects.get(app_label="auth", model="user")
        >>> user_type
        <ContentType: user>

        然后使用它来查询一个特定的 User ,或者访问 User 模型类︰
        

        >>> user_type.model_class()
        <class 'django.contrib.auth.models.User'>
        >>> user_type.get_object_for_this_type(username='Guido')
        <User: Guido>

        get_object_for_this_type() 和 model_class() 一起使用可以实现两个极其重要的功能

          1. 使用这些方法,你可以编写高级别的泛型代码,执行查询任何已安装的模型—— 而不是导入和使用单一特定模型的类,可以通过 app_label 和 model到 ContentType 在运行时查找,然后使用这个模型类或从它获取对象。
          2. 你可以关联另一个模型到 ContentType 作为一种绑定它到特定模型类的方式,然后使用这些方法来获取对那些模型的访问。

      4.ContentTypeManager 

        class ContentTypeManager [source]

          ContentType 还具有自定义的管理器 ContentTypeManager ,它增加了下列方

    1.get_for_id (id)
      代替:ContentType.objects.get(pk=id)
      原因:此方法使用与 get_for_model() 有相同的共享缓存
    2.get_for_model(model[, for_concrete_model=True])
      接收一个模型类或模型的实例,并返回表示该模型的 ContentType 实例。 for_concrete_model=False 允许获取代理模型的 ContentType 。
    3.get_for_models (*models[, for_concrete_models=True])
      接收可变数目的模型类,并返回一个字典,将模型类映射到表示它们的 ContentType 实例。 for_concrete_model=False 允许获取代理模型的 ContentType 。
    4.clear_cache ()[source]
      
    清除 ContentType 用于跟踪模型的内部缓存,它已为其创建 ContentType 实例。你可能不需要自己调用此方法;Django 将在它需要的时候自动调用。
    5.get_by_natural_key (app_label, model)[source]
      
    返回由给定的应用标签和模型名称唯一标识的 ContentType 实例。这种方法的主要目的是为允许 ContentType 对象在反序列化期间通过自然键来引用。

    get_for_model() 方法特别有用,当你知道你需要与 ContentType 交互但不想要去获取模型元数据以执行手动查找的麻烦。
    >>> from django.contrib.auth.models import User
    >>> user_type = ContentType.objects.get_for_model(User)
    >>> user_type
    <ContentType: user>


    通用关系

      在你的model添加一个外键到 ContentType 这将允许你更快捷的绑定自身到其他的model class,就像上述的 Permission model 一样。

      但是它非常有可能进一步的利用 ContentType 来实现真正的 generic (有时称之为多态) relationships 在models之间。

      一个简单的例子是标记系统,它可能看起来像这样:

        

    from django.db import models
    from django.contrib.contenttypes.fields import GenericForeignKey
    from django.contrib.contenttypes.models import ContentType
    class TaggedItem(models.Model):
      tag = models.SlugField()
      content_type = models.ForeignKey(ContentType)
      object_id = models.PositiveIntegerField()
      content_object = GenericForeignKey('content_type', 'object_id')
      def __str__(self): # __unicode__ on Python 2
        return self.tag


    一个普通的 ForeignKey 只能指向其他任意一个model,这是因为TaggedItem model用一个 ForeignKey只能关联一个model,也只能有一个model存储tags.
    contenttypes application 提供了一个特殊的字段(GenericForeignKey)避免了这个问题,并且允许你和任何一个model建立关联关系

    class GenericForeignKey[source]

      三步建立GenericForeignKey:

        1.给你的model设置一个ForeignKey字段到ContentType.一般命名为:“content_type”.

        2.给你的model设置一个字段,用来存储你想要关联的model主键值。对于大多数model,这是一个 PositiveIntegerField字段。并且通常命名为“object_id”.

        3.给你的model一个 GenericForeignKey字段,把1,2点提到的那两个字段的名词传给他。如果这两个字段名字分别为“content_type”和“object_id”,你就可以省略他们。因为GenericForeignKey默认会去自动查找这两个字段。

    for_concrete_model

      默认是 True .

      如果为 False ,那么字段将会涉及到proxy models(代理模型)。
      这映射了 for_concrete_model 的参数到 get_for_model() .

    allow_unsaved_instance_assignme

      New in Django 1.8.
        
    与 ForeignKey.allow_unsaved_instance_assignment 类似。
      自1.7版起已弃用

        此类过去在 django.contrib.contenttypes.generic 中定
        义。将从Django 1.9中删除从此旧位置导入的支持。

    主键类型的兼容性

      “object_id” 字段并不总是相同的,这是由于储存在相关模型中的主键类型的关系,但
       是他们的主键值必须被转变为相同类型。

       通过 “object_id” 字段 的get_db_prep_value() 方法实现。

      例如, 如果你想要简历generic 关系到一个 IntegerField 或者 CharField 为主
      键的模型, 你可以使用 CharField 给 “object_id”字段,因为数字是可以被
      get_db_prep_value() 转化为字母的

    序列化 ContentType 的对象引用

      如果你想要序列化一个建立了 generic关系的model数据(for example, whengenerating fixtures ) ,你应该用一个自然键来唯一的标识相关的ContentType 对象。有关详细信息,请参阅natural keys和 dumpdata --natural-foreign 。

      这允许你像平时用 ForeignKey 类似的API来工作。每一个 TaggedItem 都将有一个 content_object 字段返回对象的关联,你也可以指定这个字段或者用它来创建一个 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 完成的方式问题,,你没有办法用这个字段直接执行数据库API,filters的操作。

      比如 ( filter() and exclude() , for example) 。因为一个 GenericForeignKey 不是一个普通的字段对象t, 这些例子是不会工作的:

      

    # This will fail
    >>> TaggedItem.objects.filter(content_object=guido)
    # This will also fail
    >>> TaggedItem.objects.get(content_object=guido)

    同样的, GenericForeignKey s 是不会出现在 ModelForm S

    反向通用关系

      class GenericRelation [source]

        自1.7版起已弃用:此类过去在 django.contrib.contenttypes.generic 中定义。

        将从Django 1.9中删除从此旧位置导入的支持

        
      related_query_name

       New in Django 1.7

         默认情况下,相关对象返回到该对象的关系不存在。设置 related_query_name来创建一个对象从关联对象返回到对象自身。这允许查询和筛选相关的对象。

         如果你知道你最经常使用哪种型号的,你还可以添加一个“反向”的通用关系,以使其能附加一个附加的API。

      

    class Bookmark(models.Model):
      url = models.URLField()
      tags = GenericRelation(TaggedItem)

      Bookmark 的每个实例都会有一个 tags 属性,可以用来获取相关的TaggedItems

      

    >>> 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()[<TaggedItem: django>, <TaggedItem: python>]

      New in Django 1.7

        定义一个 GenericRelation 伴有 related_query_name 可以允许从相关联的对象中查询。

        

    tags = GenericRelation(TaggedItem, related_query_name='bookmarks’)

      这允许你从 TaggedItem 执行过滤筛选, 排序, 和其他的查询操作 Bookmark

        

    >>> # Get all tags belonging to books containing `django` in the url
    >>> TaggedItem.objects.filter(bookmarks__url__contains='django')
    [<TaggedItem: django>, <TaggedItem: python>]

      GenericRelation和GenericForeignKey一样可以接受以content-type和object-id字段命名的参数。

      如果一个model的GenericForeignKey字段使用的不是默认的命名,当你创建一个GenericRelation的时候一定要显示的传递这个字段命名给它。例如:

      TaggedItem model关联到上述所用的字段用content_type_fk 和 object_primary_key两个名称来创建一个generic foreignkey,然后就需要这样定义:

      

    tags = GenericRelation(TaggedItem,
                  content_type_field='content_type_fk',
                  object_id_field='object_primary_key')

      

      当然,如果你没有添加一个反向的关系,你可以手动做相同类型的查找:

      

    >>> b = Bookmark.objects.get(url='https://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>]

      如果一个GenericRelation model在它的GenericForeignKey的ct_field or fk_field 使用了非默认值,例如:

        ct_field = "object_pk" , 你就要设置GenericRelation中的ct_field和fk_field:

        

    comments = fields.GenericRelation(Comment, object_id_field="object_pk")

      同时请注意,如果你删除了一个具有 GenericRelation 的对象, 任何以GenericForeignKey 指向他的对象也会被删除. 在上面的例子中, 如果一个Bookmark 对象被删除了,任何指向它的 TaggedItem 对象也会被同时删除.

      不同于 ForeignKey , GenericForeignKey 并不接受一个 on_delete 参数来控制它的行为:如果你非常渴望这种可控制行为,你应该不使用GenericRelation 来避免这种级联删除,并且这种行为控制也可以通过pre_delete 信号来提供。

    通用关系和聚合

       Django’s database aggregation API不能与 GenericRelation 配合使用。例如,您可能会试图尝试以下操作:

      

      Bookmark.objects.aggregate(Count('tags'))

      这是错误的。然而generic relation 添加了额外的查询集过滤来保证正确的内容类型,但是aggregate()方法并没有被考虑进来。现在,如果你需要再generic relations 使用聚合,你只能不通过聚合API来计算他们。

    Generic relation在表单中的应用

      django.contrib.contenttypes.forms 模块提供:

          BaseGenericlnlineFormSet

           用于GenericForeignKey的表单工厂,generic_inlineformaset_factory().

        class BaseGenericInlineFormSet [source]

          自1.7版起已弃用:此类过去在 django.contrib.contenttypes.generic 中定义。将从Django 1.9中删除从此旧位置导入的支持。

        

          generic_inlineformset_factory (model, form=ModelForm,formset=BaseGenericInlineFormSet, 
                          ct_field="content_type", fk_field="object_id",fields=None,
                          exclude=None, extra=3, can_order=False, can_delete=True,
                          max_num = None,formfield_callback=None,validate_max=False,
                          for_concrete_model = True,min_num= None,validate_min = False)

        使用 modelformset_factory() 返回 GenericInlineFormSet.

        如果它们分别与默认值, content_type 和 object_id 不同,则必须提供 ct_field 和 fk_field 。

        其他参数与 modelformset_factory() 和 inlineformset_factory() 中记录的参数类似.

        for_concrete_model 参数对应于 GenericForeignKey 上的 for_concrete_model 参数。

        自1.7版起已弃用:此函数用于在 django.contrib.contenttypes.generic 中定义。

        将从Django 1.9中删除从此旧位置导入的支持。

        Changed in Django 1.7:

           min_num 和 validate_min.

    管理中的通用关系

      django.contrib.contenttypes.admin 模块提供GenericTabularInlineGenericStackedInline(GenericInlineModel的子类别)

        这些类和函数确保了generic relations在forms 和 admin的使用。有关详细信息,请参阅model formset和admin文档。

        class GenericInlineModelAdmin [source]

          GenericInlineModelAdmin 类继承了来自 InlineModelAdmin 类的所有属性。但是,它添加了一些自己的用于处理通用关系:

          ct_field

            模型上的ContentType外键字段的名称.默认为content_type。

          ct_fk_field

            表示相关对象的ID的整数字段的名称。默认为object_id。

          自1.7版起已弃用:此类过去在 django.contrib.contenttypes.generic 中定义。将从Django 1.9中删除从此旧位置导入的支持。

        class GenericTabularInline [source]

        class GenericStackedInline [source]

        GenericInlineModelAdmin 的子类,分别具有堆叠和表格布局. 

        自1.7版起已弃用:这些类以前在 django.contrib.contenttypes.generic 中定义。将从Django 1.9中删除从此旧位置导入的支持.

         

      

    人生短短数十载,经不起几次重头再来
  • 相关阅读:
    ngnix-内网能用,外网不能用
    python学习
    mysql数据库导出xls-自定义
    Oralce-资源配置PROFILE
    oracle-用户管理与权限分配
    Oracle-创建索引分区
    Oracle-表分区
    Oracle--索引视图序列等对象
    Oracle-数据表对象
    Oracle-管理表空间和数据文件
  • 原文地址:https://www.cnblogs.com/bk770466199/p/8921044.html
Copyright © 2011-2022 走看看