一. 介绍

Django包含一个contenttypes应用程序(app), 可以跟踪Django项目中安装的所有模型(Model), 提供用于处理模型的高级通用接口.

Contenttypes应用的核心是ContentType模型, 位于django.contrib.contenttypes.models.ContentType. ContentType的实例表示并保存项目中安装的模型的信息, 每当有新的模型时会自动创建新的ContentType实例.

只要使用django-admin startproject命令创建的Django项目(PyCharm创建Django项目同理), 默认都会在settings.pyINSTALLED_APPS列表中安装好django.contrib.contenttypes.

我们执行了数据迁移命令之后, 会自动在数据库中创建一个名为django_content_type的表.

表结构如下所示:

其中, app_label字段存储了APP的名称, model字段存储了APP下的具体的模型类的名称.

二. 应用场景

1. 表结构设计的演变

举个简单的例子, 我们可以在某个平台单独发文章, 也可以单独发图片, 每一篇文章或每一张图片都可以被不同的用户评论. 如此一来, 我们就可以设计出以下表结构:

app01/models.py文件:

from django.db import models

class UserInfo(models.Model):
"""用户表"""
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
password = models.CharField(max_length=32) class Post(models.Model):
"""帖子表"""
author = models.ForeignKey(to='UserInfo')
title = models.TextField() class Picture(models.Model):
"""图片表"""
author = models.ForeignKey(to='UserInfo')
image = models.CharField(max_length=128) class Comment(models.Model):
"""评论表"""
author = models.ForeignKey(to='UserInfo')
content = models.TextField() post = models.ForeignKey(to='Post', null=True, blank=True, on_delete=models.CASCADE)
picture = models.ForeignKey(to='Picture', null=True, blank=True, on_delete=models.CASCADE)

图示说明:

从上表可以看出, Comment表的post字段和picture字段下的数据有较多的空余, 造成了数据库空间的浪费. 于是, 我们尝试进行这样的改进:

其中, table_name指该条评论对应的表名(帖子?图片?), object_id指该表名对应的表中某条记录的id.

如此一来, 进一步思考, 我们不妨再设计一个表django_content_type, 里面专门存放表名, 用Comment表关联django_content_type表, 把原先的table_name换成表名对应的id.

2. GenericForeignKeyGenericRelation

这个时候我们就用上了前面讲到的contenttypes, 借助contenttypes我们就能够在创建Comment的时候再决定和Post关联还是和Picture关联.

app01/models.py中:

  • 使用django.contrib.contenttypes中提供的特殊字段GenericForeignKey来实现表与表之间的关联(不会再数据库中创建新的字段).
  • 使用GenericRelation进行反向查询.
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation class UserInfo(models.Model):
"""用户表"""
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
password = models.CharField(max_length=32) class Post(models.Model):
"""帖子表"""
author = models.ForeignKey(to='UserInfo')
title = models.TextField() comments = GenericRelation('Comment') # 支持反向查找评论数据(不会在数据库中创建字段) class Picture(models.Model):
"""图片表"""
author = models.ForeignKey(to='UserInfo')
image = models.CharField(max_length=128) comments = GenericRelation('Comment') # 支持反向查找评论数据(不会在数据库中创建字段) class Comment(models.Model):
"""评论表"""
author = models.ForeignKey(to='UserInfo')
content = models.TextField()
# content_type是关联的表名
content_type = models.ForeignKey(to=ContentType) # 外键关联django的ContentType表
# object_id是关联表中具体的数据id
object_id = models.PositiveIntegerField() # 关联数据的主键
# 通过GenericForeignKey把以上二者(表名, 该表中具体数据id)动态关联起来
content_object = GenericForeignKey('content_type', 'object_id')

3. 测试

在Django项目根目录下创建一个用于测试的文件text.py:

import os

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_contenttype.settings")
import django django.setup()
#### 以上代码是Django环境的准备 #### from app01 import models # 准备测试数据
user_1 = models.UserInfo.objects.create(username='aaa', password='123')
user_2 = models.UserInfo.objects.create(username='bbb', password='123')
user_3 = models.UserInfo.objects.create(username='ccc', password='123')
post_1 = models.Post.objects.create(author=user_1, title='Python入门教程')
post_2 = models.Post.objects.create(author=user_2, title='Python进阶教程')
post_3 = models.Post.objects.create(author=user_1, title='Python入土教程')
picture_1 = models.Picture.objects.create(author=user_1, image='小姐姐01.jpg')
picture_2 = models.Picture.objects.create(author=user_1, image='小姐姐02.jpg')
picture_3 = models.Picture.objects.create(author=user_3, image='小哥哥01.jpg') # 给帖子创建评论数据
comment_1 = models.Comment.objects.create(author=user_1, content='好文!', content_object=post_1)
# 给图片创建评论数据
comment_2 = models.Comment.objects.create(author=user_2, content='好美!', content_object=picture_1)
# 查询示例
post_1 = models.Post.objects.first()
ret = post_1.comments.values()
print(ret)

Django之contenttypes组件的更多相关文章

  1. Django contenttypes 组件

    contenttypes组件 介绍 Django包含一个contenttypes应用程序(app),可以跟踪Django项目中安装的所有模型(Model),提供用于处理模型的高级通用接口. Conte ...

  2. Django contenttypes组件

    contenttypes组件 介绍 Django包含一个contenttypes应用程序(app),可以跟踪Django项目中安装的所有模型(Model),提供用于处理模型的高级通用接口. Conte ...

  3. django内置组件——ContentTypes

    一.什么是Django ContentTypes? Django ContentTypes是由Django框架提供的一个核心功能,它对当前项目中所有基于Django驱动的model提供了更高层次的抽象 ...

  4. 【django之stark组件】

    一.需求 仿照django的admin,开发自己的stark组件.实现类似数据库客户端的功能,对数据进行增删改查. 二.实现 1.在settings配置中分别注册这三个app # Applicatio ...

  5. django 之 stark组件

    ----------------------------------------------------------------烦恼没完没了,内心动荡不安,呜呼哀哉. 一.有个特殊的需求,需要用sta ...

  6. Django之ContentType组件

    一.理想表结构设计 1.初始构建 1. 场景刚过去的双12,很多电商平台都会对他们的商品进行打折促销活动的,那么我们如果要实现这样的一个场景,改如何设计我们的表? 2. 初始表设计 注释很重要,看看吧 ...

  7. python框架之Django(13)-admin组件

    使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.你可以在项目的 settings.py 中的 INSTALLED_APPS ...

  8. Django组件(五) Django之ContentType组件

    基础使用 -contenttype组件 -django提供的一个快速连表操作的组件,可以追踪项目中所有的APP和model的对应关系,并记录在ContentType表中. 当我们的项目做数据迁移后,会 ...

  9. Django 之 admin组件使用&源码解析

    admin组件使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.可以在项目的 settings.py 中的 INSTALLED ...

随机推荐

  1. mybatis的简单搭建和使用(一)

    前言 mybatis是一个持久层的框架,那么问题来了,什么是持久层的框架呢,持久层就是把数据持久化的保存到数据库中,这种过程一般叫数据持久化的过程,现为了程序员能够很方便的操作数据库,于是就出现持久层 ...

  2. CSS效果篇--纯CSS+HTML实现checkbox的思路与实例

    checkbox应该是一个比较常用的html功能了,不过浏览器自带的checkbox往往样式不怎么好看,而且不同浏览器效果也不一样.出于美化和统一视觉效果的需求,checkbox的自定义就被提出来了. ...

  3. Mysql-sql行转列

    原始数据如下图所示:(商品的销售明细)date=业务日期:Item=商品名称:saleqty=销售数量 -- 建立测试数据(表)create table test (Date varchar(10), ...

  4. vue初级尝试

    为了跟上前端后台化的潮流,本少不得不开始关注vue,下列上机代码是针对App.vue进行的更改 数据渲染----一般键值对,数组,对象和对象数组 <template> <div id ...

  5. python一些方便excel行操作的函数(一)

    import collections class headhandler(): def __init__(self,mylist): self.mystorage={} self.mylist = m ...

  6. 多项式乘法(FFT)模板 && 快速数论变换(NTT)

    具体步骤: 1.补0:在两个多项式最前面补0,得到两个 $2n$ 次多项式,设系数向量分别为 $v_1$ 和 $v_2$. 2.求值:用FFT计算 $f_1 = DFT(v_1)$ 和 $f_2=DF ...

  7. 牛客寒假算法基础集训营2 【处女座与复读机】DP最小编辑距离【模板题】

    链接:https://ac.nowcoder.com/acm/contest/327/G来源:牛客网 一天,处女座在牛客算法群里发了一句“我好强啊”,引起无数的复读,可是处女座发现复读之后变成了“处女 ...

  8. MySQL 5.7半同步复制技术

    一.复制架构衍生史 在谈这个特性之前,我们先来看看MySQL的复制架构衍生史. 在2000年,MySQL 3.23.15版本引入了Replication.Replication作为一种准实时同步方式, ...

  9. 秒的换算:ms(毫秒),μs(微秒),ns(纳秒),ps(皮秒)

    皮秒 皮秒,符号ps(英语:picosecond ).1皮秒等于一万亿分之一秒(10-12秒) 1,000 皮秒 = 1纳秒 1,000,000 皮秒 = 1微秒 1,000,000,000 皮秒 = ...

  10. python_bisect模块的使用

    这个模块只有几个函数, 一旦决定使用二分搜索时,立马要想到使用这个模块 import bisect L = [1,3,3,6,8,12,15] x = 3 x_insert_point = bisec ...