Django contenttypes 组件
contenttypes组件
介绍
Django包含一个contenttypes应用程序(app),可以跟踪Django项目中安装的所有模型(Model),提供用于处理模型的高级通用接口。
Contenttypes应用的核心是ContentType模型,位于django.contrib.contenttypes.models.ContentType。 ContentType的实例表示并保存项目中安装的模型的信息,每当有新的模型时会自动创建新的ContentType实例。
只要使用django-admin startproject 命令创建的Django项目(PyCharm创建Django项目同理),默认都会在settings.py的INSTALLED_APPS列表中安装好django.contrib.contenttypes。

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

表结构如下图所示:

其中,app_label字段存储了APP的名称,model字段存储了APP下的具体的模型类的名称。
应用场景
我们在网上po一段散文诗也可以po一张旅途的风景图,文字可以被评论,图片也可以被评论。我们需要在数据库中建表存储这些数据,我们可能会设计出下面这样的表结构。

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
# Create your models here.
"""
用户发一段文字,可以被评论
用户发一张图片,也可以被评论
用户(已有)
文字
图片
评论
"""
class Talk(models.Model):
"""说说"""
info = models.TextField()
comments = GenericRelation('Comment', object_id_field='obj_id', content_type_field='table_name')
class Picture(models.Model):
"""图片"""
img = models.CharField(max_length=128)
# 方便反向查询的时候 (不会再数据库中创建这个字段,只是提供了一些方便操作的方法)
comments = GenericRelation('Comment', object_id_field='obj_id', content_type_field='table_name')
class Comment(models.Model):
"""评论"""
info = models.TextField()
# 关联表的表名(外键 --> Django Content Type表)
# content_type = models.ForeignKey(to=ContentType)的时候不需要上面指定
table_name = models.ForeignKey(to=ContentType)
# 关联表中具体的数据id
# object_id = models.IntegerField()
obj_id = models.IntegerField()
# 告诉Django table_name和obj_id是一组动态关联的数据 先找表再找字段,顺序不能变,
content_object = GenericForeignKey('table_name', 'obj_id')
contenttypes使用
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_contenttype.settings")
import django
django.setup()
from app01.models import Post, Picture, Comment
from django.contrib.auth.models import User
# 准备测试数据
user_1 = User.objects.create_user(username='aaa', password='123')
user_2 = User.objects.create_user(username='bbb', password='123')
user_3 = User.objects.create_user(username='ccc', password='123')
post_1 = Post.objects.create(author=user_1, title='Python入门教程')
post_2 = Post.objects.create(author=user_2, title='Python进阶教程')
post_3 = Post.objects.create(author=user_1, title='Python入土教程')
picture_1 = Picture.objects.create(author=user_1, image='小姐姐01.jpg')
picture_2 = Picture.objects.create(author=user_1, image='小姐姐02.jpg')
picture_3 = Picture.objects.create(author=user_3, image='小哥哥01.jpg')
# 给帖子创建评论数据
comment_1 = Comment.objects.create(author=user_1, content='好文!', content_object=post_1)
# 给图片创建评论数据
comment_2 = Comment.objects.create(author=user_2, content='好美!', content_object=picture_1)
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_contenttypes.settings")
import django
django.setup()
from app01 import models
# 创建说说
models.Talk.objects.create(info='今天天气真好!')
# 创建图片
models.Picture.objects.create(img='1.png')
# 针对说说创建评论
models.Comment.objects.create(
info='确实是废话!',
table_name_id=9,
obj_id=1
)
# 针对图片创建评论
models.Comment.objects.create(
info='这姑娘真好看!',
table_name_id=8,
obj_id=1
)
# 凯哥的说说的评论都有什么?
ret = models.Comment.objects.filter(table_name_id=9, obj_id=1)
print(ret)
# 说说对象.comment.all()
talk_obj = models.Talk.objects.first()
ret = talk_obj.comments.all()
print(ret)
接下来如果我们想要查看某篇帖子或者某个照片的所有评论,这个时候就可以用上另外一个工具--GenericRelation了。
在models.py中使用django.contrib.contenttypes中提供的特殊字段GenericForeignKey来实现:
class Comment(models.Model):
"""评论表"""
author = models.ForeignKey(User)
content = models.TextField()
content_type = models.ForeignKey(ContentType) # 外键关联django_content_type表
object_id = models.PositiveIntegerField() # 关联数据的主键
content_object = GenericForeignKey('content_type', 'object_id')
from django.contrib.contenttypes.fields import GenericRelation
修改models.py中的Post和Picture,添加用于反向查询的comments字段:
class Post(models.Model):
"""帖子表"""
author = models.ForeignKey(User)
title = models.CharField(max_length=72)
comments = GenericRelation('Comment') # 支持反向查找评论数据(不会在数据库中创建字段)
class Picture(models.Model):
"""图片表"""
author = models.ForeignKey(User)
image = models.ImageField()
comments = GenericRelation('Comment') # 支持反向查找评论数据(不会在数据库中创建字段)
查询示例:
post_1 = Post.objects.filter(id=1).first() comment_list = post_1.comments.all()

浙公网安备 33010602011771号