ContentType介绍
Django ContentTypes
是由Django
框架提供的一个核心功能,它对当前项目中所有基于Django
驱动的model
提供了更高层次的抽象接口。
Django
权限管理中的Permission
借助ContentType
实现了对任意models
的权限操作。ContenType
的通用类型-GenericRelation
(通用外键关联),使模型类中的某张表关联到任意的表。
在新建一个项目的时候在installed_app
中默认会有contenttypes
:
在迁移完数据库后会发现项目的表中存在一张叫做django_content_type
的表,表中有两个关键字段:
app_label
:应用标签,也就是我们每个app模块的名字。model
:对应app模块下的模型类名称。
这张表就是Django模型管理的表,根据这两个字段我们可以定位到任何一个模型类。
ContentType源码解析
源码位置:
from django.contrib.contenttypes.models import ContentType
-
获取自定义模型类例子:
>>> from django.contrib.contenttypes.models import ContentType >>> user_type = ContentType.objects.get(app_label='auth', model='user') >>> user_type <ContentType: user>
-
查询模型类中的字段例子:
-
先根据上边的例子获取模型类
-
查询模型类中的字段
>>> user_type.model_class() <class 'django.contrib.auth.models.User'> >>> user_type.get_object_for_this_type(username='Guido') <User: Guido>
-
GenericRelation和GenericForeignKey介绍与使用
假如在一个项目中有博客模块、文章模块、图片模块,每一个功能模块都可以让其他人进行评论,也就是说每一个模块的model要关联到评论model。
在不使用通用外键时每个应用的模型类以及评论的模型类如下:
from django.db import models
from django.contrib.auth.models import User
# 博客model
class Post(models.Model):
author = models.Foreignkey(User, on_delete=models.CASADE)
body = models.TextField(blank=True)
# 文章model
class Article(models.Model):
author = models.ForeignKey(User, on_delete=models.CASADE)
body = models.TextField(blank=True)
# 图片model
class Picture(models.Model):
author = models.ForeignKey(User, on_delete=models.CASADE)
body = models.TextField(blank=True)
# 博客评论
class Post_omment(models.Model):
author = models.ForeignKey(User, on_delete=models.CASADE)
body = models.TextField(blank=True)
post = models.ForeignKey(to=Post, on_delete=models.CASADE, null=True)
# 图片评论
class Pic_omment(models.Model):
author = models.ForeignKey(User, on_delete=models.CASADE)
body = models.TextField(blank=True)
pic = models.ForeignKey(to=Picture, on_delete=models.CASADE, null=True)
# 文章评论
class Article_comment(models.Model):
author = models.ForeignKey(User, on_delete=models.CASADE)
body = models.TextField(blank=True)
article = models.ForeignKey(to=Article, on_delete=models.CASADE, null=True)
存在问题:这样对于代码的扩展性不是很友好,每当新增一个模块需要添加评论功能的时候都需要在增加一个该模块的评论model
。
解决方法:Django框架其实已经考虑到这种情况,并且提供了对应的处理机制,那就是通用外键的使用。
通用外键:将一个自定义model
变为一个通用的模型类,该model
可以成为任意模型类的外键关联的表。
使用通用外键我们就不用每次新增模块的时候去创建对应的评论模型类,直接让需要的模块关联到定义了通用外键的模型类就可以了。
使用方法:
-
首先要明白表与表之间的关联的意思:
表与表之间的关联也是记录与记录之间的关联,也就是一个表的一条记录关联到另一张表的一条记录。
-
想要让两张表关联就要有能够定位到表中的每一条记录的方法,前边讲解的使用ContentType可以定位到一张表,接下来的通用外键就可以帮我们定位到一条记录。
-
定义含有通用外键的评论模型类:
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey # 此时的模型类为通用模型类 class Comment(models.Modle): author = models.ForeignKey(to=User, on_delete=models.CASADE) body = models.TextField(blank=True) # 1. 使用ContenType定位到一张表 content_type = models.ForeignKey(ContentType, models.CASADE) # 2. 主键id object_id = models.IntegerField() # 3. 根据1和2定位到一条记录 content_object = GenericForeignKey('content_type', 'object_id')
第三步默认情况下传递的参数名称就是
content_type
和object_id
, 如果第1和第2步的名字和这一样的话,可以缺省参数:content_object = GenericForeignKey()
-
定义好通用模型类后,在其他模型类中就可以关联到这个通用模型类了:
from django.contrib.contenttypes.fields import GenericRelation from django.db import models from django.contrib.auth.models import User # 博客model class Post(models.Model): author = models.Foreignkey(User, on_delete=models.CASADE) body = models.TextField(blank=True) # 这样就关联到了评论模型类 comments = GenericRelation(Comment) # 文章model class Article(models.Model): author = models.ForeignKey(User, on_delete=models.CASADE) body = models.TextField(blank=True) # 这样就关联到了评论模型类 comments = GenericRelation(Comment) # 图片model class Picture(models.Model): author = models.ForeignKey(User, on_delete=models.CASADE) body = models.TextField(blank=True) # 这样就关联到了评论模型类 comments = GenericRelation(Comment)
这样不管以后增加了几个功能模块,都不要在重写评论模型类,直接让该模块的模型类关联到通用评论模型类就可以了。
-
需要注意的是通用模型类的通用外键
content_object = GenericForeignKey('content_type', 'object_id')
默认是级联删除,且不提供on_delete
参数:也就是说当我们删除了文章模块后,关于文章模块的评论也将被删除。